X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap_r%2Ftpool.c;h=6d014d70ff0dc58ca36ca61c490df9c00c762582;hb=3bdbaf54877583e6694c2f3fe6dfa01e351f3b9f;hp=af0c4f739d63069105f6118fd9cc70fe59f8bef9;hpb=ec426532b2cca95330566b1941795dac7e03bb57;p=openldap diff --git a/libraries/libldap_r/tpool.c b/libraries/libldap_r/tpool.c index af0c4f739d..6d014d70ff 100644 --- a/libraries/libldap_r/tpool.c +++ b/libraries/libldap_r/tpool.c @@ -12,8 +12,8 @@ #include "portable.h" #include -#include +#include #include #include #include @@ -44,6 +44,7 @@ struct ldap_int_thread_pool_s { long ltp_pending_count; long ltp_active_count; long ltp_open_count; + long ltp_starting; }; typedef struct ldap_int_thread_ctx_s { @@ -60,7 +61,9 @@ static void *ldap_int_thread_pool_wrapper( static void *ldap_int_thread_enlist( ldap_int_thread_list_t *list, void *elem ); static void *ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem ); +#if 0 static void *ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem ); +#endif int ldap_int_thread_pool_startup ( void ) @@ -84,12 +87,11 @@ ldap_int_thread_pool_shutdown ( void ) int ldap_pvt_thread_pool_init ( ldap_pvt_thread_pool_t *tpool, - int max_concurrency, + int max_threads, int max_pending ) { - int rc; ldap_pvt_thread_pool_t pool; - ldap_pvt_thread_t thr; + int rc; *tpool = NULL; pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1, @@ -97,18 +99,37 @@ ldap_pvt_thread_pool_init ( if (pool == NULL) return(-1); - ldap_pvt_thread_mutex_init(&pool->ltp_mutex); - ldap_pvt_thread_cond_init(&pool->ltp_cond); + rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex); + if (rc != 0) + return(rc); + rc = ldap_pvt_thread_cond_init(&pool->ltp_cond); + if (rc != 0) + return(rc); pool->ltp_state = LDAP_INT_THREAD_POOL_RUNNING; - pool->ltp_max_count = max_concurrency; + pool->ltp_max_count = max_threads; pool->ltp_max_pending = max_pending; ldap_pvt_thread_mutex_lock(&ldap_pvt_thread_pool_mutex); ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool); ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex); - /* start up one thread, just so there is one */ +#if 0 + /* THIS WILL NOT WORK on some systems. If the process + * forks after starting a thread, there is no guarantee + * that the thread will survive the fork. For example, + * slapd forks in order to daemonize, and does so after + * calling ldap_pvt_thread_pool_init. On some systems, + * this initial thread does not run in the child process, + * but ltp_open_count == 1, so two things happen: + * 1) the first client connection fails, and 2) when + * slapd is kill'ed, it never terminates since it waits + * for all worker threads to exit. */ + + /* start up one thread, just so there is one. no need to + * lock the mutex right now, since no threads are running. + */ pool->ltp_open_count++; + ldap_pvt_thread_t thr; rc = ldap_pvt_thread_create( &thr, 1, (void *) ldap_int_thread_pool_wrapper, pool ); @@ -122,6 +143,7 @@ ldap_pvt_thread_pool_init ( free(pool); return(-1); } +#endif *tpool = pool; return(0); @@ -172,6 +194,7 @@ ldap_pvt_thread_pool_submit ( || pool->ltp_open_count < pool->ltp_max_count)) { pool->ltp_open_count++; + pool->ltp_starting++; need_thread = 1; } ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); @@ -179,15 +202,17 @@ ldap_pvt_thread_pool_submit ( if (need_thread) { int rc = ldap_pvt_thread_create( &thr, 1, (void *)ldap_int_thread_pool_wrapper, pool ); - if (rc != 0) { + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + if (rc == 0) { + pool->ltp_starting--; + } else { /* couldn't create thread. back out of * ltp_open_count and check for even worse things. */ - ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); pool->ltp_open_count--; + pool->ltp_starting--; if (pool->ltp_open_count == 0) { - /* no open threads at all?!? this will never happen - * because we always leave at least one thread open. + /* no open threads at all?!? */ if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) { /* no open threads, context not handled, so @@ -200,18 +225,37 @@ ldap_pvt_thread_pool_submit ( return(-1); } } - ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); /* there is another open thread, so this * context will be handled eventually. * continue on and signal that the context * is waiting. */ } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); } return(0); } +int +ldap_pvt_thread_pool_maxthreads ( ldap_pvt_thread_pool_t *tpool, int max_threads ) +{ + struct ldap_int_thread_pool_s *pool; + + if (tpool == NULL) + return(-1); + + pool = *tpool; + + if (pool == NULL) + return(-1); + + ldap_pvt_thread_mutex_lock(&pool->ltp_mutex); + pool->ltp_max_count = max_threads; + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); + return(0); +} + int ldap_pvt_thread_pool_backload ( ldap_pvt_thread_pool_t *tpool ) { @@ -257,7 +301,6 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) ? LDAP_INT_THREAD_POOL_FINISHING : LDAP_INT_THREAD_POOL_STOPPING; waiting = pool->ltp_open_count; - ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); /* broadcast could be used here, but only after * it is fixed in the NT thread implementation @@ -265,6 +308,7 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) while (--waiting >= 0) { ldap_pvt_thread_cond_signal(&pool->ltp_cond); } + ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); do { ldap_pvt_thread_yield(); @@ -273,8 +317,8 @@ ldap_pvt_thread_pool_destroy ( ldap_pvt_thread_pool_t *tpool, int run_pending ) ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex); } while (waiting > 0); - while (ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist( - &pool->ltp_pending_list, NULL)) + while ((ctx = (ldap_int_thread_ctx_t *)ldap_int_thread_delist( + &pool->ltp_pending_list, NULL)) != NULL) { free(ctx); } @@ -302,10 +346,24 @@ ldap_int_thread_pool_wrapper ( if (ctx == NULL) { if (pool->ltp_state == LDAP_INT_THREAD_POOL_FINISHING) break; + if (pool->ltp_max_count > 0 + && pool->ltp_open_count > pool->ltp_max_count) + { + /* too many threads running (can happen if the + * maximum threads value is set during ongoing + * operation using ldap_pvt_thread_pool_maxthreads) + * so let this thread die. + */ + break; + } + /* we could check an idle timer here, and let the * thread die if it has been inactive for a while. * only die if there are other open threads (i.e., - * always have at least one thread open). + * always have at least one thread open). the check + * should be like this: + * if (pool->ltp_open_count > 1 && pool->ltp_starting == 0) + * check timer, leave thread (break;) */ if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING) @@ -377,7 +435,7 @@ ldap_int_thread_delist( ldap_int_thread_list_t *list, void *elem ) } return(NULL); } - +#if 0 static void * ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem ) { @@ -392,5 +450,5 @@ ldap_int_thread_onlist( ldap_int_thread_list_t *list, void *elem ) return(NULL); } - +#endif #endif /* LDAP_HAVE_THREAD_POOL */