mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-01-06 10:46:21 +08:00
ITS#7115 Re-fix tpool.c (idle/unidle)
This commit is contained in:
parent
e86da2fe3f
commit
fa7575666f
@ -125,11 +125,11 @@ struct ldap_int_thread_pool_s {
|
||||
/* Max number of threads in pool, or 0 for default (LDAP_MAXTHR) */
|
||||
int ltp_max_count;
|
||||
|
||||
/* Max number of pending + paused requests, negated when ltp_finishing */
|
||||
/* Max pending + paused + idle tasks, negated when ltp_finishing */
|
||||
int ltp_max_pending;
|
||||
|
||||
int ltp_pending_count; /* Pending or paused requests */
|
||||
int ltp_active_count; /* Active, not paused requests */
|
||||
int ltp_pending_count; /* Pending + paused + idle tasks */
|
||||
int ltp_active_count; /* Active, not paused/idle tasks */
|
||||
int ltp_open_count; /* Number of threads, negated when ltp_pause */
|
||||
int ltp_starting; /* Currenlty starting threads */
|
||||
|
||||
@ -711,16 +711,21 @@ ldap_int_thread_pool_wrapper (
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
#define DO_PAUSE 0
|
||||
#define CHECK_PAUSE 1
|
||||
#define GO_IDLE 2
|
||||
#define GO_UNIDLE 3
|
||||
/* Arguments > ltp_pause to handle_pause(,PAUSE_ARG()). arg=PAUSE_ARG
|
||||
* ensures (arg-ltp_pause) sets GO_* at need and keeps DO_PAUSE/GO_*.
|
||||
*/
|
||||
#define GO_IDLE 8
|
||||
#define GO_UNIDLE 16
|
||||
#define CHECK_PAUSE 32 /* if (ltp_pause) { GO_IDLE; GO_UNIDLE; } */
|
||||
#define DO_PAUSE 64 /* CHECK_PAUSE; pause the pool */
|
||||
#define PAUSE_ARG(a) \
|
||||
((a) | ((a) & (GO_IDLE|GO_UNIDLE) ? GO_IDLE-1 : CHECK_PAUSE))
|
||||
|
||||
static int
|
||||
handle_pause( ldap_pvt_thread_pool_t *tpool, int pause_type )
|
||||
{
|
||||
struct ldap_int_thread_pool_s *pool;
|
||||
int ret = 0;
|
||||
int ret = 0, pause;
|
||||
|
||||
if (tpool == NULL)
|
||||
return(-1);
|
||||
@ -735,9 +740,34 @@ handle_pause( ldap_pvt_thread_pool_t *tpool, int pause_type )
|
||||
|
||||
ldap_pvt_thread_mutex_lock(&pool->ltp_mutex);
|
||||
|
||||
switch( pause_type ) {
|
||||
case DO_PAUSE:
|
||||
/* Wait for everyone else to pause or finish */
|
||||
pause = pool->ltp_pause; /* 0 or 1 */
|
||||
|
||||
/* If ltp_pause and not GO_IDLE|GO_UNIDLE: Set GO_IDLE,GO_UNIDLE */
|
||||
pause_type -= pause;
|
||||
|
||||
if (pause_type & GO_IDLE) {
|
||||
pool->ltp_pending_count++;
|
||||
pool->ltp_active_count--;
|
||||
if (pause && pool->ltp_active_count < 2) {
|
||||
/* Tell the task waiting to DO_PAUSE it can proceed */
|
||||
ldap_pvt_thread_cond_signal(&pool->ltp_pcond);
|
||||
}
|
||||
}
|
||||
|
||||
if (pause_type & GO_UNIDLE) {
|
||||
/* Wait out pause if any, then cancel GO_IDLE */
|
||||
ret = pause;
|
||||
for (; pause; pause = pool->ltp_pause) {
|
||||
ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
|
||||
}
|
||||
pool->ltp_pending_count--;
|
||||
pool->ltp_active_count++;
|
||||
}
|
||||
|
||||
if (pause_type & DO_PAUSE) {
|
||||
/* Tell everyone else to pause or finish, then await that */
|
||||
ret = 0;
|
||||
assert(!pool->ltp_pause);
|
||||
pool->ltp_pause = 1;
|
||||
/* Let ldap_pvt_thread_pool_submit() through to its ltp_pause test,
|
||||
* and do not finish threads in ldap_pvt_thread_pool_wrapper() */
|
||||
@ -745,70 +775,50 @@ handle_pause( ldap_pvt_thread_pool_t *tpool, int pause_type )
|
||||
SET_VARY_OPEN_COUNT(pool);
|
||||
/* Hide pending tasks from ldap_pvt_thread_pool_wrapper() */
|
||||
pool->ltp_work_list = &empty_pending_list;
|
||||
|
||||
/* Wait for this task to become the sole active task */
|
||||
while (pool->ltp_active_count > 1) {
|
||||
ldap_pvt_thread_cond_wait(&pool->ltp_pcond, &pool->ltp_mutex);
|
||||
}
|
||||
break;
|
||||
case GO_UNIDLE:
|
||||
pool->ltp_pending_count--;
|
||||
pool->ltp_active_count++;
|
||||
/* FALLTHRU */
|
||||
case CHECK_PAUSE:
|
||||
case GO_IDLE:
|
||||
/* If someone else has already requested a pause, we have to wait */
|
||||
if (pool->ltp_pause) {
|
||||
pool->ltp_pending_count++;
|
||||
pool->ltp_active_count--;
|
||||
/* let the other pool_pause() know when it can proceed */
|
||||
if (pool->ltp_active_count < 2)
|
||||
ldap_pvt_thread_cond_signal(&pool->ltp_pcond);
|
||||
do {
|
||||
ldap_pvt_thread_cond_wait(&pool->ltp_cond, &pool->ltp_mutex);
|
||||
} while (pool->ltp_pause);
|
||||
pool->ltp_pending_count--;
|
||||
pool->ltp_active_count++;
|
||||
ret = 1;
|
||||
}
|
||||
if (pause_type != GO_IDLE)
|
||||
break;
|
||||
pool->ltp_pending_count++;
|
||||
pool->ltp_active_count--;
|
||||
break;
|
||||
}
|
||||
|
||||
ldap_pvt_thread_mutex_unlock(&pool->ltp_mutex);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/* Consider this task idle: It will not block pool_pause() in other tasks. */
|
||||
void
|
||||
ldap_pvt_thread_pool_idle( ldap_pvt_thread_pool_t *tpool )
|
||||
{
|
||||
handle_pause( tpool, GO_IDLE );
|
||||
handle_pause(tpool, PAUSE_ARG(GO_IDLE));
|
||||
}
|
||||
|
||||
/* Cancel pool_idle(). If a pause was requested, wait for it first. */
|
||||
void
|
||||
ldap_pvt_thread_pool_unidle( ldap_pvt_thread_pool_t *tpool )
|
||||
{
|
||||
handle_pause( tpool, GO_UNIDLE );
|
||||
handle_pause(tpool, PAUSE_ARG(GO_UNIDLE));
|
||||
}
|
||||
|
||||
/*
|
||||
* If a pause was requested, wait for it. If several threads
|
||||
* are waiting to pause, let through one or more pauses.
|
||||
* The calling task must be active, not idle.
|
||||
* Return 1 if we waited, 0 if not, -1 at parameter error.
|
||||
*/
|
||||
int
|
||||
ldap_pvt_thread_pool_pausecheck( ldap_pvt_thread_pool_t *tpool )
|
||||
{
|
||||
return handle_pause( tpool, CHECK_PAUSE );
|
||||
return handle_pause(tpool, PAUSE_ARG(CHECK_PAUSE));
|
||||
}
|
||||
|
||||
/* Pause the pool. Return when all other threads are paused. */
|
||||
/*
|
||||
* Pause the pool. The calling task must be active, not idle.
|
||||
* Return when all other tasks are paused or idle.
|
||||
*/
|
||||
int
|
||||
ldap_pvt_thread_pool_pause( ldap_pvt_thread_pool_t *tpool )
|
||||
{
|
||||
return handle_pause( tpool, DO_PAUSE );
|
||||
return handle_pause(tpool, PAUSE_ARG(DO_PAUSE));
|
||||
}
|
||||
|
||||
/* End a pause */
|
||||
|
Loading…
Reference in New Issue
Block a user