mirror of
https://git.openldap.org/openldap/openldap.git
synced 2024-12-21 03:10:25 +08:00
Fix for thread/fork problem. Don't start a worker thread until one is
needed.
This commit is contained in:
parent
b065b258f4
commit
719b945c78
@ -44,6 +44,7 @@ struct ldap_int_thread_pool_s {
|
|||||||
long ltp_pending_count;
|
long ltp_pending_count;
|
||||||
long ltp_active_count;
|
long ltp_active_count;
|
||||||
long ltp_open_count;
|
long ltp_open_count;
|
||||||
|
long ltp_starting;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ldap_int_thread_ctx_s {
|
typedef struct ldap_int_thread_ctx_s {
|
||||||
@ -87,9 +88,8 @@ ldap_pvt_thread_pool_init (
|
|||||||
int max_concurrency,
|
int max_concurrency,
|
||||||
int max_pending )
|
int max_pending )
|
||||||
{
|
{
|
||||||
int rc;
|
|
||||||
ldap_pvt_thread_pool_t pool;
|
ldap_pvt_thread_pool_t pool;
|
||||||
ldap_pvt_thread_t thr;
|
int rc;
|
||||||
|
|
||||||
*tpool = NULL;
|
*tpool = NULL;
|
||||||
pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
|
pool = (ldap_pvt_thread_pool_t) LDAP_CALLOC(1,
|
||||||
@ -97,8 +97,12 @@ ldap_pvt_thread_pool_init (
|
|||||||
|
|
||||||
if (pool == NULL) return(-1);
|
if (pool == NULL) return(-1);
|
||||||
|
|
||||||
ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
|
rc = ldap_pvt_thread_mutex_init(&pool->ltp_mutex);
|
||||||
ldap_pvt_thread_cond_init(&pool->ltp_cond);
|
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_state = LDAP_INT_THREAD_POOL_RUNNING;
|
||||||
pool->ltp_max_count = max_concurrency;
|
pool->ltp_max_count = max_concurrency;
|
||||||
pool->ltp_max_pending = max_pending;
|
pool->ltp_max_pending = max_pending;
|
||||||
@ -106,9 +110,24 @@ ldap_pvt_thread_pool_init (
|
|||||||
ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool);
|
ldap_int_thread_enlist(&ldap_int_thread_pool_list, pool);
|
||||||
ldap_pvt_thread_mutex_unlock(&ldap_pvt_thread_pool_mutex);
|
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++;
|
pool->ltp_open_count++;
|
||||||
|
|
||||||
|
ldap_pvt_thread_t thr;
|
||||||
rc = ldap_pvt_thread_create( &thr, 1,
|
rc = ldap_pvt_thread_create( &thr, 1,
|
||||||
(void *) ldap_int_thread_pool_wrapper, pool );
|
(void *) ldap_int_thread_pool_wrapper, pool );
|
||||||
|
|
||||||
@ -122,6 +141,7 @@ ldap_pvt_thread_pool_init (
|
|||||||
free(pool);
|
free(pool);
|
||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
*tpool = pool;
|
*tpool = pool;
|
||||||
return(0);
|
return(0);
|
||||||
@ -172,6 +192,7 @@ ldap_pvt_thread_pool_submit (
|
|||||||
|| pool->ltp_open_count < pool->ltp_max_count))
|
|| pool->ltp_open_count < pool->ltp_max_count))
|
||||||
{
|
{
|
||||||
pool->ltp_open_count++;
|
pool->ltp_open_count++;
|
||||||
|
pool->ltp_starting++;
|
||||||
need_thread = 1;
|
need_thread = 1;
|
||||||
}
|
}
|
||||||
ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
|
ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
|
||||||
@ -179,15 +200,17 @@ ldap_pvt_thread_pool_submit (
|
|||||||
if (need_thread) {
|
if (need_thread) {
|
||||||
int rc = ldap_pvt_thread_create( &thr, 1,
|
int rc = ldap_pvt_thread_create( &thr, 1,
|
||||||
(void *)ldap_int_thread_pool_wrapper, pool );
|
(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
|
/* couldn't create thread. back out of
|
||||||
* ltp_open_count and check for even worse things.
|
* ltp_open_count and check for even worse things.
|
||||||
*/
|
*/
|
||||||
ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
|
|
||||||
pool->ltp_open_count--;
|
pool->ltp_open_count--;
|
||||||
|
pool->ltp_starting--;
|
||||||
if (pool->ltp_open_count == 0) {
|
if (pool->ltp_open_count == 0) {
|
||||||
/* no open threads at all?!? this will never happen
|
/* no open threads at all?!?
|
||||||
* because we always leave at least one thread open.
|
|
||||||
*/
|
*/
|
||||||
if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) {
|
if (ldap_int_thread_delist(&pool->ltp_pending_list, ctx)) {
|
||||||
/* no open threads, context not handled, so
|
/* no open threads, context not handled, so
|
||||||
@ -200,13 +223,13 @@ ldap_pvt_thread_pool_submit (
|
|||||||
return(-1);
|
return(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
|
|
||||||
/* there is another open thread, so this
|
/* there is another open thread, so this
|
||||||
* context will be handled eventually.
|
* context will be handled eventually.
|
||||||
* continue on and signal that the context
|
* continue on and signal that the context
|
||||||
* is waiting.
|
* is waiting.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(0);
|
return(0);
|
||||||
@ -305,7 +328,10 @@ ldap_int_thread_pool_wrapper (
|
|||||||
/* we could check an idle timer here, and let the
|
/* we could check an idle timer here, and let the
|
||||||
* thread die if it has been inactive for a while.
|
* thread die if it has been inactive for a while.
|
||||||
* only die if there are other open threads (i.e.,
|
* 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)
|
if (pool->ltp_state == LDAP_INT_THREAD_POOL_RUNNING)
|
||||||
|
Loading…
Reference in New Issue
Block a user