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