]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/thr_lwp.c
6ae1d22b717f46f126ef4829d513eeffff095797
[openldap] / libraries / libldap_r / thr_lwp.c
1 /*
2  * Copyright 1998,1999 The OpenLDAP Foundation, Redwood City, California, USA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted only
6  * as authorized by the OpenLDAP Public License.  A copy of this
7  * license is available at http://www.OpenLDAP.org/license.html or
8  * in file LICENSE in the top-level directory of the distribution.
9  */
10
11 /* thr_lwp.c - wrappers around SunOS LWP threads */
12
13 /* BUGS:
14  * - slurpd calls the get_stack/free_stack functions. Should be fixed, so
15  *   they can become static.
16  */
17
18 #include "portable.h"
19
20 #if defined( HAVE_LWP )
21
22 /*************
23  *           *
24  * SunOS LWP *
25  *           *
26  *************/
27
28 /* This implementation NEEDS WORK.   It currently does not compile */
29
30 #include <stdio.h>
31
32 #include <ac/time.h>
33 #include <ac/socket.h>
34
35 #include "ldap-int.h"
36
37 #include "ldap_pvt_thread.h"
38
39 #include <lwp/lwp.h>
40 #include <lwp/stackdep.h>
41
42 #define MAX_STACK       51200
43 #define MAX_THREADS     20
44
45 /*
46  * Initialize LWP by spinning of a schedular
47  */
48 int
49 ldap_pvt_thread_initialize( void )
50 {
51         thread_t                tid;
52         stkalign_t              *stack;
53         int                     stackno;
54
55         if (( stack = get_stack( &stackno )) == NULL ) {
56                 return -1;
57         }
58
59         lwp_create( &tid, lwp_scheduler, MINPRIO, 0, stack, 1, stackno );
60         return 0;
61 }
62
63 int
64 ldap_pvt_thread_destroy( void )
65 {
66         /* need to destory lwp_scheduler thread and clean up private
67                 variables */
68         return 0;
69 }
70
71 struct stackinfo {
72         int             stk_inuse;
73         stkalign_t      *stk_stack;
74 };
75
76 static struct stackinfo *stacks;
77
78 static stkalign_t * ldap_pvt_thread_get_stack( int *stacknop )
79 {
80         int     i;
81
82         if ( stacks == NULL ) {
83                 stacks = (struct stackinfo *) LDAP_CALLOC( 1, MAX_THREADS *
84                     sizeof(struct stackinfo) );
85         }
86
87         for ( i = 0; i < MAX_THREADS; i++ ) {
88                 if ( stacks[i].stk_inuse == 0 ) {
89                         break;
90                 }
91         }
92
93         if ( i == MAX_THREADS ) {
94                 Debug( LDAP_DEBUG_ANY,
95                     "no more stacks (max %d) - increase MAX_THREADS for more",
96                     MAX_THREADS, 0, 0 );
97                 return( NULL );
98         }
99
100         if ( stacks[i].stk_stack == NULL ) {
101                 stacks[i].stk_stack = (stkalign_t *) malloc(
102                     (MAX_STACK / sizeof(stkalign_t) + 1 )
103                     * sizeof(stkalign_t) );
104         }
105
106         *stacknop = i;
107         stacks[i].stk_inuse = 1;
108         return( stacks[i].stk_stack + MAX_STACK / sizeof(stkalign_t) );
109 }
110
111 static void
112 ldap_pvt_thread_free_stack( int stackno )
113 {
114         if ( stackno < 0 || stackno > MAX_THREADS ) {
115                 Debug( LDAP_DEBUG_ANY, "free_stack of bogus stack %d\n",
116                     stackno, 0, 0 );
117         }
118
119         stacks[stackno].stk_inuse = 0;
120 }
121
122 static static void
123 lwp_create_stack( void *(*func)(), void *arg, int stackno )
124 {
125         (*func)( arg );
126
127         ldap_pvt_thread_free_stack( stackno );
128 }
129
130 int 
131 ldap_pvt_thread_create( ldap_pvt_thread_t * thread, 
132         int detach,
133         void *(*start_routine)( void *),
134         void *arg)
135 {
136         stkalign_t      *stack;
137         int             stackno;
138
139         if ( (stack = ldap_pvt_thread_get_stack( &stackno )) == NULL ) {
140                 return( -1 );
141         }
142         return( lwp_create( thread, lwp_create_stack, MINPRIO, 0, 
143                            stack, 3, start_routine, arg, stackno ) );
144 }
145
146 void 
147 ldap_pvt_thread_exit( void *retval )
148 {
149         lwp_destroy( SELF );
150 }
151
152 unsigned int
153 ldap_pvt_thread_sleep(
154         unsigned int interval
155 )
156 {
157         thread_t                mylwp;
158         tl_t            *t, *nt;
159         time_t          now;
160
161
162         if ( lwp_self( &mylwp ) < 0 ) {
163                 return -1;
164         }
165
166         time( &now );
167
168         mon_enter( &sglob->tsl_mon );
169
170         if ( sglob->tsl_list != NULL ) {
171                 for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
172                         if ( SAMETHREAD( t->tl_tid, mylwp )) {
173                                 /* We're already sleeping? */
174                                 t->tl_wake = now + interval;
175                                 mon_exit( &sglob->tsl_mon );
176                                 lwp_suspend( mylwp );
177                                 return 0;
178                         }
179                 }
180         }
181
182         nt = (tl_t *) malloc( sizeof( tl_t ));
183
184         nt->tl_next = sglob->tsl_list;
185         nt->tl_wake = now + interval;
186         nt->tl_tid = mylwp;
187         sglob->tsl_list = nt;
188
189         mon_exit( &sglob->tsl_mon );
190
191         lwp_suspend( mylwp );
192         return 0;
193 }
194
195 /*
196  * The lwp_scheduler thread periodically checks to see if any threads
197  * are due to be resumed.  If there are, it resumes them.  Otherwise,
198  * it computes the lesser of ( 1 second ) or ( the minimum time until
199  * a thread need to be resumed ) and puts itself to sleep for that amount
200  * of time.
201  */
202 static void
203 lwp_scheduler(
204         int             stackno
205 )
206 {
207         time_t                  now, min;
208         struct timeval          interval;
209         tl_t                    *t;
210
211         while ( !sglob->slurpd_shutdown ) {
212                 mon_enter( &sglob->tsl_mon );
213
214                 time( &now );
215                 min = 0L;
216                 if ( sglob->tsl_list != NULL ) {
217                         for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
218                                 if (( t->tl_wake  > 0L ) && ( t->tl_wake < now )) {
219                                         lwp_resume( t->tl_tid );
220                                         t->tl_wake = 0L;
221                                 }
222
223                                 if (( t->tl_wake > now ) && ( t->tl_wake < min )) {
224                                         min =  t->tl_wake;
225                                 }
226                         }
227                 }
228
229                 mon_exit( &sglob->tsl_mon );
230
231                 interval.tv_usec = 0L;
232                 if ( min == 0L ) {
233                         interval.tv_sec = 1L;
234                 } else {
235                         interval.tv_sec = min;
236                 }
237
238                 lwp_sleep( &interval );
239         }
240
241         mon_enter( &sglob->tsl_mon );
242
243         for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
244                 lwp_resume( t->tl_tid );
245         }
246
247         mon_exit( &sglob->tsl_mon );
248
249         free_stack( stackno );
250 }
251
252 int 
253 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
254 {
255         lwp_join( thread );
256         return 0;
257 }
258
259 int 
260 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
261 {
262         return 0;
263 }
264
265 int 
266 ldap_pvt_thread_yield( void )
267 {
268         lwp_yield( SELF );
269         return 0;
270 }
271
272 int 
273 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
274 {
275         /*
276          * lwp cv_create requires the monitor id be passed in
277          * when the cv is created, pthreads passes it when the
278          * condition is waited for.  so, we fake the creation
279          * here and actually do it when the cv is waited for
280          * later.
281          */
282
283         cond->lcv_created = 0;
284
285         return( 0 );
286 }
287
288 int 
289 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
290 {
291         return( cond->lcv_created ? cv_notify( cv->lcv_cv ) : 0 );
292 }
293
294 int 
295 ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, 
296                       ldap_pvt_thread_mutex_t *mutex )
297 {
298         if ( ! cond->lcv_created ) {
299                 cv_create( &cond->lcv_cv, *mutex );
300                 cond->lcv_created = 1;
301         }
302
303         return( cv_wait( cond->lcv_cv ) );      
304 }
305
306 int 
307 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
308 {
309         return( mon_create( mutex ) );
310 }
311
312 int 
313 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
314 {
315         return( mon_destroy( *mutex ) );
316 }
317
318 int 
319 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
320 {
321         return( mon_enter( *mutex ) );
322 }
323
324 int 
325 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
326 {
327         return( mon_exit( *mutex ) );
328 }
329
330 int
331 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mp )
332 {
333         return( mon_cond_enter( *mp ) );
334 }
335
336 int
337 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cv )
338 {
339         return( cv->lcv_created ? cv_destroy( cv->lcv_cv ) : 0 );
340 }
341
342 int
343 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cv )
344 {
345         return( cv->lcv_created ? cv_broadcast( cv->lcv_cv ) : 0 );
346 }
347
348 #endif /* HAVE_LWP */