3 * Copyright 1998-2000 The OpenLDAP Foundation, Redwood City, California, USA
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.
14 #include <ac/stdlib.h>
15 #include <ac/string.h>
17 #include "ldap_int_thread.h"
18 #include "ldap_pvt_thread.h"
21 LDAP_PVT_THREAD_POOL_RUNNING,
22 LDAP_PVT_THREAD_POOL_FINISHING,
23 LDAP_PVT_THREAD_POOL_STOPPING
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;
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;
38 long ltp_pending_count;
39 long ltp_active_count;
43 typedef struct t_ldap_pvt_thread_ctx {
44 struct t_ldap_pvt_thread_ctx *ltc_next;
45 void *(*ltc_start_routine)( void *);
47 } ldap_pvt_thread_ctx;
49 ldap_pvt_thread_list ldap_pvt_thread_pool_list = NULL;
50 ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
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 );
59 ldap_pvt_thread_initialize ( void )
63 rc = ldap_int_thread_initialize();
65 /* init the mutex that protext the list of pools
67 ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
73 ldap_pvt_thread_destroy ( void )
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);
78 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
80 return ldap_int_thread_destroy();
84 ldap_pvt_thread_get_concurrency ( void )
86 #ifdef HAVE_GETCONCURRENCY
87 return ldap_int_thread_get_concurrency();
94 ldap_pvt_thread_set_concurrency ( int concurrency )
96 #ifdef HAVE_SETCONCURRENCY
97 return ldap_int_thread_set_concurrency(concurrency);
104 ldap_pvt_thread_create (
105 ldap_pvt_thread_t * thread,
107 void *(*start_routine)( void * ),
110 return ldap_int_thread_create(thread, detach, start_routine, arg);
114 ldap_pvt_thread_exit ( void *retval )
116 ldap_int_thread_exit(retval);
120 ldap_pvt_thread_join ( ldap_pvt_thread_t thread, void **status )
122 return ldap_int_thread_join(thread, status);
126 ldap_pvt_thread_kill ( ldap_pvt_thread_t thread, int signo )
128 return ldap_int_thread_kill(thread, signo);
132 ldap_pvt_thread_yield ( void )
134 return ldap_int_thread_yield();
138 ldap_pvt_thread_cond_init ( ldap_pvt_thread_cond_t *cond )
140 return ldap_int_thread_cond_init(cond);
144 ldap_pvt_thread_cond_destroy ( ldap_pvt_thread_cond_t *cond )
146 return ldap_int_thread_cond_destroy(cond);
150 ldap_pvt_thread_cond_signal ( ldap_pvt_thread_cond_t *cond )
152 return ldap_int_thread_cond_signal(cond);
156 ldap_pvt_thread_cond_broadcast ( ldap_pvt_thread_cond_t *cond )
158 return ldap_int_thread_cond_broadcast(cond);
162 ldap_pvt_thread_cond_wait (
163 ldap_pvt_thread_cond_t *cond,
164 ldap_pvt_thread_mutex_t *mutex )
166 return ldap_int_thread_cond_wait(cond, mutex);
170 ldap_pvt_thread_mutex_init ( ldap_pvt_thread_mutex_t *mutex )
172 return ldap_int_thread_mutex_init(mutex);
176 ldap_pvt_thread_mutex_destroy ( ldap_pvt_thread_mutex_t *mutex )
178 return ldap_int_thread_mutex_destroy(mutex);
182 ldap_pvt_thread_mutex_lock ( ldap_pvt_thread_mutex_t *mutex )
184 return ldap_int_thread_mutex_lock(mutex);
188 ldap_pvt_thread_mutex_trylock ( ldap_pvt_thread_mutex_t *mutex )
190 return ldap_int_thread_mutex_trylock(mutex);
194 ldap_pvt_thread_mutex_unlock ( ldap_pvt_thread_mutex_t *mutex )
196 return ldap_int_thread_mutex_unlock(mutex);
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
210 ldap_pvt_thread_pool_startup ( void )
216 ldap_pvt_thread_pool_shutdown ( void )
222 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
229 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
231 (start_routine)(arg);
236 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
242 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
250 ldap_pvt_thread_pool_startup ( void )
252 return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
256 ldap_pvt_thread_pool_shutdown ( void )
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);
261 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
266 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
268 ldap_pvt_thread_pool_t pool;
269 ldap_pvt_thread_t thr;
272 pool = (ldap_pvt_thread_pool_t)calloc(1, sizeof(struct t_ldap_pvt_thread_pool));
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);
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);
303 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
305 ldap_pvt_thread_ctx *ctx;
307 ldap_pvt_thread_t thr;
309 return ldap_pvt_thread_create( &thr, 1, (void *)start_routine, arg );
314 ctx = (ldap_pvt_thread_ctx *)calloc(1, sizeof(ldap_pvt_thread_ctx));
318 ctx->ltc_start_routine = start_routine;
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))
325 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
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))
334 pool->ltp_open_count++;
337 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
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.
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.
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,
355 pool->ltp_pending_count++;
356 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
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
370 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
375 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
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);
389 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
392 ldap_pvt_thread_ctx *ctx;
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);
404 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
406 pool->ltp_state = LDAP_PVT_THREAD_POOL_FINISHING;
408 pool->ltp_state = LDAP_PVT_THREAD_POOL_STOPPING;
409 waiting = pool->ltp_open_count;
410 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
412 /* broadcast could be used here, but only after
413 * it is fixed in the NT thread implementation
415 while (--waiting >= 0)
416 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
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);
424 while (ctx = (ldap_pvt_thread_ctx *)ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL))
427 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
428 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
434 ldap_pvt_thread_pool_wrapper ( ldap_pvt_thread_pool_t pool )
436 ldap_pvt_thread_ctx *ctx;
438 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
440 while (pool->ltp_state != LDAP_PVT_THREAD_POOL_STOPPING) {
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)
448 ctx = ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL);
450 if (pool->ltp_state == LDAP_PVT_THREAD_POOL_FINISHING)
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).
460 pool->ltp_pending_count--;
461 pool->ltp_active_count++;
462 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
464 (ctx->ltc_start_routine)(ctx->ltc_arg);
467 /* if we use an idle timer, here's
468 * a good place to update it
471 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
472 pool->ltp_active_count--;
475 pool->ltp_open_count--;
476 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
478 ldap_pvt_thread_exit(NULL);
483 ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem )
485 ldap_pvt_thread_listelement *prev;
490 ((ldap_pvt_thread_listelement *)elem)->next = NULL;
496 for (prev = *list ; prev->next != NULL; prev = prev->next) ;
502 ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem )
504 ldap_pvt_thread_listelement *prev;
513 *list = ((ldap_pvt_thread_listelement *)elem)->next;
517 for (prev = *list ; prev->next != NULL; prev = prev->next) {
518 if (prev->next == elem) {
519 prev->next = ((ldap_pvt_thread_listelement *)elem)->next;
527 ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem )
529 ldap_pvt_thread_listelement *prev;
531 if (elem == NULL || *list == NULL)
534 for (prev = *list ; prev != NULL; prev = prev->next) {
541 #endif /* NO_THREADS */