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.
17 #include <ac/stdlib.h>
18 #include <ac/string.h>
20 #include "ldap_int_thread.h"
21 #include "ldap_pvt_thread.h"
24 LDAP_PVT_THREAD_POOL_RUNNING,
25 LDAP_PVT_THREAD_POOL_FINISHING,
26 LDAP_PVT_THREAD_POOL_STOPPING
29 typedef struct t_ldap_pvt_thread_listelement {
30 struct t_ldap_pvt_thread_listelement *next;
31 } ldap_pvt_thread_listelement, *ldap_pvt_thread_list;
33 struct t_ldap_pvt_thread_pool {
34 struct t_ldap_pvt_thread_pool *ltp_next;
35 ldap_pvt_thread_mutex_t ltp_mutex;
36 ldap_pvt_thread_cond_t ltp_cond;
37 ldap_pvt_thread_list ltp_pending_list;
41 long ltp_pending_count;
42 long ltp_active_count;
46 typedef struct t_ldap_pvt_thread_ctx {
47 struct t_ldap_pvt_thread_ctx *ltc_next;
48 void *(*ltc_start_routine)( void *);
50 } ldap_pvt_thread_ctx;
52 ldap_pvt_thread_list ldap_pvt_thread_pool_list = NULL;
53 ldap_pvt_thread_mutex_t ldap_pvt_thread_pool_mutex;
55 void *ldap_pvt_thread_pool_wrapper( ldap_pvt_thread_pool_t pool );
56 void *ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem );
57 void *ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem );
58 void *ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem );
62 ldap_pvt_thread_initialize ( void )
66 rc = ldap_int_thread_initialize();
68 /* init the mutex that protext the list of pools
70 ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
76 ldap_pvt_thread_destroy ( void )
78 while (ldap_pvt_thread_pool_list != NULL) {
79 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
81 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
83 return ldap_int_thread_destroy();
87 ldap_pvt_thread_get_concurrency ( void )
89 #ifdef HAVE_GETCONCURRENCY
90 return ldap_int_thread_get_concurrency();
97 ldap_pvt_thread_set_concurrency ( int concurrency )
99 #ifdef HAVE_SETCONCURRENCY
100 return ldap_int_thread_set_concurrency(concurrency);
107 ldap_pvt_thread_create (
108 ldap_pvt_thread_t * thread,
110 void *(*start_routine)( void * ),
113 return ldap_int_thread_create(thread, detach, start_routine, arg);
117 ldap_pvt_thread_exit ( void *retval )
119 ldap_int_thread_exit(retval);
123 ldap_pvt_thread_join ( ldap_pvt_thread_t thread, void **status )
125 return ldap_int_thread_join(thread, status);
129 ldap_pvt_thread_kill ( ldap_pvt_thread_t thread, int signo )
131 return ldap_int_thread_kill(thread, signo);
135 ldap_pvt_thread_yield ( void )
137 return ldap_int_thread_yield();
141 ldap_pvt_thread_cond_init ( ldap_pvt_thread_cond_t *cond )
143 return ldap_int_thread_cond_init(cond);
147 ldap_pvt_thread_cond_destroy ( ldap_pvt_thread_cond_t *cond )
149 return ldap_int_thread_cond_destroy(cond);
153 ldap_pvt_thread_cond_signal ( ldap_pvt_thread_cond_t *cond )
155 return ldap_int_thread_cond_signal(cond);
159 ldap_pvt_thread_cond_broadcast ( ldap_pvt_thread_cond_t *cond )
161 return ldap_int_thread_cond_broadcast(cond);
165 ldap_pvt_thread_cond_wait (
166 ldap_pvt_thread_cond_t *cond,
167 ldap_pvt_thread_mutex_t *mutex )
169 return ldap_int_thread_cond_wait(cond, mutex);
173 ldap_pvt_thread_mutex_init ( ldap_pvt_thread_mutex_t *mutex )
175 return ldap_int_thread_mutex_init(mutex);
179 ldap_pvt_thread_mutex_destroy ( ldap_pvt_thread_mutex_t *mutex )
181 return ldap_int_thread_mutex_destroy(mutex);
185 ldap_pvt_thread_mutex_lock ( ldap_pvt_thread_mutex_t *mutex )
187 return ldap_int_thread_mutex_lock(mutex);
191 ldap_pvt_thread_mutex_trylock ( ldap_pvt_thread_mutex_t *mutex )
193 return ldap_int_thread_mutex_trylock(mutex);
197 ldap_pvt_thread_mutex_unlock ( ldap_pvt_thread_mutex_t *mutex )
199 return ldap_int_thread_mutex_unlock(mutex);
204 /* There must be a separate implementation when NO_THREADS is on.
205 * Since ldap_pvt_thread_pool_wrapper loops, there's no way to
206 * simply let the underlying (stub) thread implementation take
207 * care of things (unless there was an #ifdef that removed the
208 * "while" in ldap_pvt_thread_pool_wrapper, but why do all the
209 * extra work of init/submit/destroy when all that's needed
213 ldap_pvt_thread_pool_startup ( void )
219 ldap_pvt_thread_pool_shutdown ( void )
225 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
232 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
234 (start_routine)(arg);
239 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
245 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
253 ldap_pvt_thread_pool_startup ( void )
255 return ldap_pvt_thread_mutex_init(&ldap_pvt_thread_pool_mutex);
259 ldap_pvt_thread_pool_shutdown ( void )
261 while (ldap_pvt_thread_pool_list != NULL) {
262 ldap_pvt_thread_pool_destroy((ldap_pvt_thread_pool_t)ldap_pvt_thread_pool_list, 0);
264 ldap_pvt_thread_mutex_destroy(&ldap_pvt_thread_pool_mutex);
269 ldap_pvt_thread_pool_initialize ( ldap_pvt_thread_pool_t *pool_out, int max_concurrency, int max_pending )
271 ldap_pvt_thread_pool_t pool;
272 ldap_pvt_thread_t thr;
275 pool = (ldap_pvt_thread_pool_t)calloc(1, sizeof(struct t_ldap_pvt_thread_pool));
279 ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
280 ldap_pvt_thread_cond_init(&pool->ltp_cond);
281 pool->ltp_state = LDAP_PVT_THREAD_POOL_RUNNING;
282 pool->ltp_max_count = max_concurrency;
283 pool->ltp_max_pending = max_pending;
284 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
285 ldap_pvt_thread_enlist(&ldap_pvt_thread_pool_list, pool);
286 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
288 /* start up one thread, just so there is one */
289 pool->ltp_open_count++;
290 if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
291 /* couldn't start one? then don't start any */
292 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
293 ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
294 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
295 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
296 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
306 ldap_pvt_thread_pool_submit ( ldap_pvt_thread_pool_t pool, void *(*start_routine)( void * ), void *arg )
308 ldap_pvt_thread_ctx *ctx;
310 ldap_pvt_thread_t thr;
315 ctx = (ldap_pvt_thread_ctx *)calloc(1, sizeof(ldap_pvt_thread_ctx));
319 ctx->ltc_start_routine = start_routine;
322 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
323 if (pool->ltp_state != LDAP_PVT_THREAD_POOL_RUNNING
324 || (pool->ltp_max_pending > 0 && pool->ltp_pending_count >= pool->ltp_max_pending))
326 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
330 pool->ltp_pending_count++;
331 ldap_pvt_thread_enlist(&pool->ltp_pending_list, ctx);
332 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
333 if ((pool->ltp_open_count <= 0
334 || pool->ltp_pending_count > 1
335 || pool->ltp_open_count == pool->ltp_active_count)
336 && (pool->ltp_max_count <= 0
337 || pool->ltp_open_count < pool->ltp_max_count))
339 pool->ltp_open_count++;
342 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
345 if (ldap_pvt_thread_create( &thr, 1, (void *)ldap_pvt_thread_pool_wrapper, pool ) != 0) {
346 /* couldn't create thread. back out of
347 * ltp_open_count and check for even worse things.
349 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
350 pool->ltp_open_count--;
351 if (pool->ltp_open_count == 0) {
352 /* no open threads at all?!? this will never happen
353 * because we always leave at least one thread open.
355 if (ldap_pvt_thread_delist(&pool->ltp_pending_list, ctx)) {
356 /* no open threads, context not handled, so
357 * back out of ltp_pending_count, free the context,
360 pool->ltp_pending_count++;
361 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
366 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
367 /* there is another open thread, so this
368 * context will be handled eventually.
369 * continue on and signal that the context
379 ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t pool )
386 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
387 count = pool->ltp_pending_count + pool->ltp_active_count;
388 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
393 ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t pool, int run_pending )
396 ldap_pvt_thread_ctx *ctx;
401 ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex);
402 pool = ldap_pvt_thread_delist(&ldap_pvt_thread_pool_list, pool);
403 ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
408 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
410 pool->ltp_state = LDAP_PVT_THREAD_POOL_FINISHING;
412 pool->ltp_state = LDAP_PVT_THREAD_POOL_STOPPING;
413 waiting = pool->ltp_open_count;
414 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
416 /* broadcast could be used here, but only after
417 * it is fixed in the NT thread implementation
419 while (--waiting >= 0)
420 ldap_pvt_thread_cond_signal(&pool->ltp_cond);
422 ldap_pvt_thread_yield();
423 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
424 waiting = pool->ltp_open_count;
425 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
426 } while (waiting > 0);
428 while (ctx = (ldap_pvt_thread_ctx *)ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL))
431 ldap_pvt_thread_cond_destroy(&pool->ltp_cond);
432 ldap_pvt_thread_mutex_destroy(&pool->ltp_mutex);
438 ldap_pvt_thread_pool_wrapper ( ldap_pvt_thread_pool_t pool )
440 ldap_pvt_thread_ctx *ctx;
442 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
444 while (pool->ltp_state != LDAP_PVT_THREAD_POOL_STOPPING) {
446 ctx = ldap_pvt_thread_delist(&pool->ltp_pending_list, NULL);
448 if (pool->ltp_state == LDAP_PVT_THREAD_POOL_FINISHING)
450 /* we could check an idle timer here, and let the
451 * thread die if it has been inactive for a while.
452 * only die if there are other open threads (i.e.,
453 * always have at least one thread open).
455 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
456 ldap_pvt_thread_yield();
457 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
459 if (pool->ltp_state == LDAP_PVT_THREAD_POOL_RUNNING)
460 ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
465 pool->ltp_pending_count--;
466 pool->ltp_active_count++;
467 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
469 (ctx->ltc_start_routine)(ctx->ltc_arg);
471 ldap_pvt_thread_yield();
473 /* if we use an idle timer, here's
474 * a good place to update it
477 ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
478 pool->ltp_active_count--;
481 pool->ltp_open_count--;
482 ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
484 ldap_pvt_thread_exit(NULL);
489 ldap_pvt_thread_enlist( ldap_pvt_thread_list *list, void *elem )
491 ldap_pvt_thread_listelement *prev;
496 ((ldap_pvt_thread_listelement *)elem)->next = NULL;
502 for (prev = *list ; prev->next != NULL; prev = prev->next) ;
508 ldap_pvt_thread_delist( ldap_pvt_thread_list *list, void *elem )
510 ldap_pvt_thread_listelement *prev;
519 *list = ((ldap_pvt_thread_listelement *)elem)->next;
523 for (prev = *list ; prev->next != NULL; prev = prev->next) {
524 if (prev->next == elem) {
525 prev->next = ((ldap_pvt_thread_listelement *)elem)->next;
533 ldap_pvt_thread_onlist( ldap_pvt_thread_list *list, void *elem )
535 ldap_pvt_thread_listelement *prev;
537 if (elem == NULL || *list == NULL)
540 for (prev = *list ; prev != NULL; prev = prev->next) {
548 #endif /* NO_THREADS */