]> git.sur5r.net Git - openldap/blob - libraries/libldap_r/threads.c
Disable thread pooling while I fix the deadlock.
[openldap] / libraries / libldap_r / threads.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 #include "portable.h"
13
14 #include <ac/stdlib.h>
15 #include <ac/string.h>
16
17 #include "ldap_int_thread.h"
18 #include "ldap_pvt_thread.h"
19
20 enum {
21         LDAP_PVT_THREAD_POOL_RUNNING,
22         LDAP_PVT_THREAD_POOL_FINISHING,
23         LDAP_PVT_THREAD_POOL_STOPPING
24 };
25
26 typedef struct t_ldap_pvt_thread_listelement {
27         struct t_ldap_pvt_thread_listelement *next;
28 } ldap_pvt_thread_listelement, *ldap_pvt_thread_list;
29
30 struct t_ldap_pvt_thread_pool {
31         struct t_ldap_pvt_thread_pool *ltp_next;
32         ldap_pvt_thread_mutex_t ltp_mutex;
33         ldap_pvt_thread_cond_t ltp_cond;
34         ldap_pvt_thread_list ltp_pending_list;
35         long ltp_state;
36         long ltp_max_count;
37         long ltp_max_pending;
38         long ltp_pending_count;
39         long ltp_active_count;
40         long ltp_open_count;
41 };
42
43 typedef struct t_ldap_pvt_thread_ctx {
44         struct t_ldap_pvt_thread_ctx *ltc_next;
45         void *(*ltc_start_routine)( void *);
46         void *ltc_arg;
47 } ldap_pvt_thread_ctx;
48
49 ldap_pvt_thread_list ldap_pvt_thread_pool_list = NULL;
50 ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
51
52 void *ldap_pvt_thread_pool_wrapper( ldap_pvt_thread_pool_t pool );
53 void *ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem );
54 void *ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem );
55 void *ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem );
56
57
58 int
59 ldap_pvt_thread_initialize ( void )
60 {
61         int rc;
62
63         rc = ldap_int_thread_initialize();
64         if (rc == 0) {
65                 /* init the mutex that protext the list of pools
66                  */
67                 ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
68         }
69         return rc;
70 }
71
72 int
73 ldap_pvt_thread_destroy ( void )
74 {
75         while (ldap_pvt_thread_pool_list != NULL) {
76                 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
77         }
78         ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
79
80         return ldap_int_thread_destroy();
81 }
82
83 int
84 ldap_pvt_thread_get_concurrency ( void )
85 {
86 #ifdef HAVE_GETCONCURRENCY
87         return ldap_int_thread_get_concurrency();
88 #else
89         return 1;
90 #endif
91 }
92
93 int
94 ldap_pvt_thread_set_concurrency ( int concurrency )
95 {
96 #ifdef HAVE_SETCONCURRENCY
97         return ldap_int_thread_set_concurrency(concurrency);
98 #else
99         return 1;
100 #endif
101 }
102
103 int 
104 ldap_pvt_thread_create (
105         ldap_pvt_thread_t * thread, 
106         int     detach,
107         void *(*start_routine)( void * ), 
108         void *arg)
109 {
110         return ldap_int_thread_create(thread, detach, start_routine, arg);
111 }
112
113 void
114 ldap_pvt_thread_exit ( void *retval )
115 {
116         ldap_int_thread_exit(retval);
117 }
118
119 int
120 ldap_pvt_thread_join ( ldap_pvt_thread_t thread, void **status )
121 {
122         return ldap_int_thread_join(thread, status);
123 }
124
125 int
126 ldap_pvt_thread_kill ( ldap_pvt_thread_t thread, int signo )
127 {
128         return ldap_int_thread_kill(thread, signo);
129 }
130
131 int
132 ldap_pvt_thread_yield ( void )
133 {
134         return ldap_int_thread_yield();
135 }
136
137 int
138 ldap_pvt_thread_cond_init ( ldap_pvt_thread_cond_t *cond )
139 {
140         return ldap_int_thread_cond_init(cond);
141 }
142
143 int
144 ldap_pvt_thread_cond_destroy ( ldap_pvt_thread_cond_t *cond )
145 {
146         return ldap_int_thread_cond_destroy(cond);
147 }
148
149 int
150 ldap_pvt_thread_cond_signal ( ldap_pvt_thread_cond_t *cond )
151 {
152         return ldap_int_thread_cond_signal(cond);
153 }
154
155 int
156 ldap_pvt_thread_cond_broadcast ( ldap_pvt_thread_cond_t *cond )
157 {
158         return ldap_int_thread_cond_broadcast(cond);
159 }
160
161 int
162 ldap_pvt_thread_cond_wait (
163         ldap_pvt_thread_cond_t *cond, 
164         ldap_pvt_thread_mutex_t *mutex )
165 {
166         return ldap_int_thread_cond_wait(cond, mutex);
167 }
168
169 int
170 ldap_pvt_thread_mutex_init ( ldap_pvt_thread_mutex_t *mutex )
171 {
172         return ldap_int_thread_mutex_init(mutex);
173 }
174
175 int
176 ldap_pvt_thread_mutex_destroy ( ldap_pvt_thread_mutex_t *mutex )
177 {
178         return ldap_int_thread_mutex_destroy(mutex);
179 }
180
181 int
182 ldap_pvt_thread_mutex_lock ( ldap_pvt_thread_mutex_t *mutex )
183 {
184         return ldap_int_thread_mutex_lock(mutex);
185 }
186
187 int
188 ldap_pvt_thread_mutex_trylock ( ldap_pvt_thread_mutex_t *mutex )
189 {
190         return ldap_int_thread_mutex_trylock(mutex);
191 }
192
193 int
194 ldap_pvt_thread_mutex_unlock ( ldap_pvt_thread_mutex_t *mutex )
195 {
196         return ldap_int_thread_mutex_unlock(mutex);
197 }
198
199 #ifdef NO_THREADS
200
201 /* There must be a separate implementation when NO_THREADS is on.
202  * Since ldap_pvt_thread_pool_wrapper loops, there's no way to
203  * simply let the underlying (stub) thread implementation take
204  * care of things (unless there was an #ifdef that removed the
205  * "while" in ldap_pvt_thread_pool_wrapper, but why do all the
206  * extra work of init/submit/destroy when all that's needed
207  * are these stubs?)
208  */
209 int
210 ldap_pvt_thread_pool_startup ( void )
211 {
212         return(0);
213 }
214
215 int
216 ldap_pvt_thread_pool_shutdown ( void )
217 {
218         return(0);
219 }
220
221 int
222 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
223 {
224         *pool_out = NULL;
225         return(0);
226 }
227
228 int
229 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
230 {
231         (start_routine)(arg);
232         return(0);
233 }
234
235 int
236 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
237 {
238         return(0);
239 }
240
241 int
242 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
243 {
244         return(0);
245 }
246
247 #else
248
249 int
250 ldap_pvt_thread_pool_startup ( void )
251 {
252         return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
253 }
254
255 int
256 ldap_pvt_thread_pool_shutdown ( void )
257 {
258         while (ldap_pvt_thread_pool_list != NULL) {
259                 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
260         }
261         ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
262         return(0);
263 }
264
265 int
266 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
267 {
268         ldap_pvt_thread_pool_t pool;
269         ldap_pvt_thread_t thr;
270
271         *pool_out = NULL;
272         pool = (ldap_pvt_thread_pool_t)calloc(1, sizeof(struct t_ldap_pvt_thread_pool));
273         if (pool == NULL)
274                 return(-1);
275
276         ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
277         ldap_pvt_thread_cond_init(&pool->ltp_cond);
278         pool->ltp_state = LDAP_PVT_THREAD_POOL_RUNNING;
279         pool->ltp_max_count = max_concurrency;
280         pool->ltp_max_pending = max_pending;
281         ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
282         ldap_pvt_thread_enlist(&ldap_pvt_thread_pool_list, pool);
283         ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
284
285         /* start up one thread, just so there is one */
286         pool->ltp_open_count++;
287         if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
288                 /* couldn't start one?  then don't start any */
289                 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
290                 ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
291                 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
292                 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
293                 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
294                 free(pool);
295                 return(-1);
296         }
297
298         *pool_out = pool;
299         return(0);
300 }
301
302 int
303 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
304 {
305         ldap_pvt_thread_ctx *ctx;
306         int need_thread = 0;
307         ldap_pvt_thread_t thr;
308
309         return ldap_pvt_thread_create( &thr, 1, (void *)start_routine, arg );
310
311         if (pool == NULL)
312                 return(-1);
313
314         ctx = (ldap_pvt_thread_ctx *)calloc(1, sizeof(ldap_pvt_thread_ctx));
315         if (ctx == NULL)
316                 return(-1);
317
318         ctx->ltc_start_routine = start_routine;
319         ctx->ltc_arg = arg;
320
321         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
322         if (pool->ltp_state != LDAP_PVT_THREAD_POOL_RUNNING
323                 || (pool->ltp_max_pending > 0 && pool->ltp_pending_count >= pool->ltp_max_pending))
324         {
325                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
326                 free(ctx);
327                 return(-1);
328         }
329         pool->ltp_pending_count++;
330         ldap_pvt_thread_enlist(&pool->ltp_pending_list, ctx);
331         if ((pool->ltp_open_count <= 0 || pool->ltp_open_count == pool->ltp_active_count)
332                 && (pool->ltp_max_count <= 0 || pool->ltp_open_count < pool->ltp_max_count))
333         {
334                 pool->ltp_open_count++;
335                 need_thread = 1;
336         }
337         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
338
339         if (need_thread) {
340                 if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
341                         /* couldn't create thread.  back out of
342                          * ltp_open_count and check for even worse things.
343                          */
344                         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
345                         pool->ltp_open_count--;
346                         if (pool->ltp_open_count == 0) {
347                                 /* no open threads at all?!?  this will never happen
348                                  * because we always leave at least one thread open.
349                                  */
350                                 if (ldap_pvt_thread_delist(&pool->ltp_pending_list, ctx)) {
351                                         /* no open threads, context not handled, so
352                                          * back out of ltp_pending_count, free the context,
353                                          * report the error.
354                                          */
355                                         pool->ltp_pending_count++;
356                                         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
357                                         free(ctx);
358                                         return(-1);
359                                 }
360                         }
361                         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
362                         /* there is another open thread, so this
363                          * context will be handled eventually.
364                          * continue on and signal that the context
365                          * is waiting.
366                          */
367                 }
368         }
369
370         ldap_pvt_thread_cond_signal(&pool->ltp_cond);
371         return(0);
372 }
373
374 int
375 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
376 {
377         int count;
378
379         if (pool == NULL)
380                 return(0);
381
382         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
383         count = pool->ltp_pending_count + pool->ltp_active_count;
384         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
385         return(count);
386 }
387
388 int
389 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
390 {
391         long waiting;
392         ldap_pvt_thread_ctx *ctx;
393
394         if (pool == NULL)
395                 return(-1);
396
397         ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
398         pool = ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
399         ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
400
401         if (pool == NULL)
402                 return(-1);
403
404         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
405         if (run_pending)
406                 pool->ltp_state = LDAP_PVT_THREAD_POOL_FINISHING;
407         else
408                 pool->ltp_state = LDAP_PVT_THREAD_POOL_STOPPING;
409         waiting = pool->ltp_open_count;
410         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
411
412         /* broadcast could be used here, but only after
413          * it is fixed in the NT thread implementation
414          */
415         while (--waiting >= 0)
416                 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
417         do {
418                 ldap_pvt_thread_yield();
419                 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
420                 waiting = pool->ltp_open_count;
421                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
422         } while (waiting > 0);
423
424         while (ctx = (ldap_pvt_thread_ctx *)ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL))
425                 free(ctx);
426
427         ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
428         ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
429         free(pool);
430         return(0);
431 }
432
433 void *
434 ldap_pvt_thread_pool_wrapper ( ldap_pvt_thread_pool_t pool )
435 {
436         ldap_pvt_thread_ctx *ctx;
437
438         ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
439
440         while (pool->ltp_state != LDAP_PVT_THREAD_POOL_STOPPING) {
441
442                 if (pool->ltp_state == LDAP_PVT_THREAD_POOL_RUNNING) {
443                         ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
444                         if (pool->ltp_state == LDAP_PVT_THREAD_POOL_STOPPING)
445                                 break;
446                 }
447
448                 ctx = ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL);
449                 if (ctx == NULL) {
450                         if (pool->ltp_state == LDAP_PVT_THREAD_POOL_FINISHING)
451                                 break;
452                         /* we could check an idle timer here, and let the
453                          * thread die if it has been inactive for a while.
454                          * only die if there are other open threads (i.e.,
455                          * always have at least one thread open).
456                          */
457                         continue;
458                 }
459
460                 pool->ltp_pending_count--;
461                 pool->ltp_active_count++;
462                 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
463
464                 (ctx->ltc_start_routine)(ctx->ltc_arg);
465                 free(ctx);
466
467                 /* if we use an idle timer, here's
468                  * a good place to update it
469                  */
470
471                 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
472                 pool->ltp_active_count--;
473         }
474
475         pool->ltp_open_count--;
476         ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
477
478         ldap_pvt_thread_exit(NULL);
479         return(NULL);
480 }
481
482 void *
483 ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem )
484 {
485         ldap_pvt_thread_listelement *prev;
486
487         if (elem == NULL)
488                 return(NULL);
489
490         ((ldap_pvt_thread_listelement *)elem)->next = NULL;
491         if (*list == NULL) {
492                 *list = elem;
493                 return(elem);
494         }
495
496         for (prev = *list ; prev->next != NULL; prev = prev->next) ;
497         prev->next = elem;
498         return(elem);
499 }
500
501 void *
502 ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem )
503 {
504         ldap_pvt_thread_listelement *prev;
505
506         if (*list == NULL)
507                 return(NULL);
508
509         if (elem == NULL)
510                 elem = *list;
511
512         if (*list == elem) {
513                 *list = ((ldap_pvt_thread_listelement *)elem)->next;
514                 return(elem);
515         }
516
517         for (prev = *list ; prev->next != NULL; prev = prev->next) {
518                 if (prev->next == elem) {
519                         prev->next = ((ldap_pvt_thread_listelement *)elem)->next;
520                         return(elem);
521                 }
522         }
523         return(NULL);
524 }
525
526 void *
527 ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem )
528 {
529         ldap_pvt_thread_listelement *prev;
530
531         if (elem == NULL || *list == NULL)
532                 return(NULL);
533
534         for (prev = *list ; prev != NULL; prev = prev->next) {
535                 if (prev == elem)
536                         return(elem);
537         }
538
539         return(NULL);
540 }
541 #endif  /* NO_THREADS */