]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/thr_lwp.c
a401b1929af08d53ddbd6f12f30353d6b95865e2
[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                 if( stacks == NULL ) {
87                         Debug( LDAP_DEBUG_ANY, "stacks allocation failed",
88                                 0, 0, 0 );
89                         return NULL;
90                 }
91         }
92
93         for ( i = 0; i < MAX_THREADS; i++ ) {
94                 if ( stacks[i].stk_inuse == 0 ) {
95                         break;
96                 }
97         }
98
99         if ( i == MAX_THREADS ) {
100                 Debug( LDAP_DEBUG_ANY,
101                     "no more stacks (max %d) - increase MAX_THREADS for more",
102                     MAX_THREADS, 0, 0 );
103                 return( NULL );
104         }
105
106         if ( stacks[i].stk_stack == NULL ) {
107                 stacks[i].stk_stack = (stkalign_t *) LDAP_MALLOC(
108                     (MAX_STACK / sizeof(stkalign_t) + 1 )
109                     * sizeof(stkalign_t) );
110
111                 if( stacks[i].stk_stack == NULL ) {
112                         Debug( LDAP_DEBUG_ANY, "stack allocation failed",
113                                 0, 0, 0 );
114                         return( NULL );
115                 }
116         }
117
118         *stacknop = i;
119         stacks[i].stk_inuse = 1;
120         return( stacks[i].stk_stack + MAX_STACK / sizeof(stkalign_t) );
121 }
122
123 static void
124 ldap_pvt_thread_free_stack( int stackno )
125 {
126         if ( stackno < 0 || stackno > MAX_THREADS ) {
127                 Debug( LDAP_DEBUG_ANY, "free_stack of bogus stack %d\n",
128                     stackno, 0, 0 );
129         }
130
131         stacks[stackno].stk_inuse = 0;
132 }
133
134 static void
135 lwp_create_stack( void *(*func)(), void *arg, int stackno )
136 {
137         (*func)( arg );
138
139         ldap_pvt_thread_free_stack( stackno );
140 }
141
142 int 
143 ldap_pvt_thread_create( ldap_pvt_thread_t * thread, 
144         int detach,
145         void *(*start_routine)( void *),
146         void *arg)
147 {
148         stkalign_t      *stack;
149         int             stackno;
150
151         if ( (stack = ldap_pvt_thread_get_stack( &stackno )) == NULL ) {
152                 return( -1 );
153         }
154         return( lwp_create( thread, lwp_create_stack, MINPRIO, 0, 
155                            stack, 3, start_routine, arg, stackno ) );
156 }
157
158 void 
159 ldap_pvt_thread_exit( void *retval )
160 {
161         lwp_destroy( SELF );
162 }
163
164 unsigned int
165 ldap_pvt_thread_sleep(
166         unsigned int interval
167 )
168 {
169         thread_t                mylwp;
170         tl_t            *t, *nt;
171         time_t          now;
172
173
174         if ( lwp_self( &mylwp ) < 0 ) {
175                 return -1;
176         }
177
178         time( &now );
179
180         mon_enter( &sglob->tsl_mon );
181
182         if ( sglob->tsl_list != NULL ) {
183                 for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
184                         if ( SAMETHREAD( t->tl_tid, mylwp )) {
185                                 /* We're already sleeping? */
186                                 t->tl_wake = now + interval;
187                                 mon_exit( &sglob->tsl_mon );
188                                 lwp_suspend( mylwp );
189                                 return 0;
190                         }
191                 }
192         }
193
194         nt = (tl_t *) LDAP_MALLOC( sizeof( tl_t ));
195
196         if( nt == NULL ) return -1;
197
198         nt->tl_next = sglob->tsl_list;
199         nt->tl_wake = now + interval;
200         nt->tl_tid = mylwp;
201         sglob->tsl_list = nt;
202
203         mon_exit( &sglob->tsl_mon );
204
205         lwp_suspend( mylwp );
206         return 0;
207 }
208
209 /*
210  * The lwp_scheduler thread periodically checks to see if any threads
211  * are due to be resumed.  If there are, it resumes them.  Otherwise,
212  * it computes the lesser of ( 1 second ) or ( the minimum time until
213  * a thread need to be resumed ) and puts itself to sleep for that amount
214  * of time.
215  */
216 static void
217 lwp_scheduler(
218         int             stackno
219 )
220 {
221         time_t                  now, min;
222         struct timeval          interval;
223         tl_t                    *t;
224
225         while ( !sglob->slurpd_shutdown ) {
226                 mon_enter( &sglob->tsl_mon );
227
228                 time( &now );
229                 min = 0L;
230                 if ( sglob->tsl_list != NULL ) {
231                         for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
232                                 if (( t->tl_wake  > 0L ) && ( t->tl_wake < now )) {
233                                         lwp_resume( t->tl_tid );
234                                         t->tl_wake = 0L;
235                                 }
236
237                                 if (( t->tl_wake > now ) && ( t->tl_wake < min )) {
238                                         min =  t->tl_wake;
239                                 }
240                         }
241                 }
242
243                 mon_exit( &sglob->tsl_mon );
244
245                 interval.tv_usec = 0L;
246                 if ( min == 0L ) {
247                         interval.tv_sec = 1L;
248                 } else {
249                         interval.tv_sec = min;
250                 }
251
252                 lwp_sleep( &interval );
253         }
254
255         mon_enter( &sglob->tsl_mon );
256
257         for ( t = sglob->tsl_list; t != NULL; t = t->tl_next ) {
258                 lwp_resume( t->tl_tid );
259         }
260
261         mon_exit( &sglob->tsl_mon );
262
263         free_stack( stackno );
264 }
265
266 int 
267 ldap_pvt_thread_join( ldap_pvt_thread_t thread, void **thread_return )
268 {
269         lwp_join( thread );
270         return 0;
271 }
272
273 int 
274 ldap_pvt_thread_kill( ldap_pvt_thread_t thread, int signo )
275 {
276         return 0;
277 }
278
279 int 
280 ldap_pvt_thread_yield( void )
281 {
282         lwp_yield( SELF );
283         return 0;
284 }
285
286 int 
287 ldap_pvt_thread_cond_init( ldap_pvt_thread_cond_t *cond )
288 {
289         /*
290          * lwp cv_create requires the monitor id be passed in
291          * when the cv is created, pthreads passes it when the
292          * condition is waited for.  so, we fake the creation
293          * here and actually do it when the cv is waited for
294          * later.
295          */
296
297         cond->lcv_created = 0;
298
299         return( 0 );
300 }
301
302 int 
303 ldap_pvt_thread_cond_signal( ldap_pvt_thread_cond_t *cond )
304 {
305         return( cond->lcv_created ? cv_notify( cv->lcv_cv ) : 0 );
306 }
307
308 int 
309 ldap_pvt_thread_cond_wait( ldap_pvt_thread_cond_t *cond, 
310                       ldap_pvt_thread_mutex_t *mutex )
311 {
312         if ( ! cond->lcv_created ) {
313                 cv_create( &cond->lcv_cv, *mutex );
314                 cond->lcv_created = 1;
315         }
316
317         return( cv_wait( cond->lcv_cv ) );      
318 }
319
320 int 
321 ldap_pvt_thread_mutex_init( ldap_pvt_thread_mutex_t *mutex )
322 {
323         return( mon_create( mutex ) );
324 }
325
326 int 
327 ldap_pvt_thread_mutex_destroy( ldap_pvt_thread_mutex_t *mutex )
328 {
329         return( mon_destroy( *mutex ) );
330 }
331
332 int 
333 ldap_pvt_thread_mutex_lock( ldap_pvt_thread_mutex_t *mutex )
334 {
335         return( mon_enter( *mutex ) );
336 }
337
338 int 
339 ldap_pvt_thread_mutex_unlock( ldap_pvt_thread_mutex_t *mutex )
340 {
341         return( mon_exit( *mutex ) );
342 }
343
344 int
345 ldap_pvt_thread_mutex_trylock( ldap_pvt_thread_mutex_t *mp )
346 {
347         return( mon_cond_enter( *mp ) );
348 }
349
350 int
351 ldap_pvt_thread_cond_destroy( ldap_pvt_thread_cond_t *cv )
352 {
353         return( cv->lcv_created ? cv_destroy( cv->lcv_cv ) : 0 );
354 }
355
356 int
357 ldap_pvt_thread_cond_broadcast( ldap_pvt_thread_cond_t *cv )
358 {
359         return( cv->lcv_created ? cv_broadcast( cv->lcv_cv ) : 0 );
360 }
361
362 #endif /* HAVE_LWP */