version 1.11, 2002/03/14 16:42:29
|
version 1.12, 2002/03/18 11:34:28
|
|
|
struct timeval & dealloc_wait, | struct timeval & dealloc_wait, |
struct timeval & deadlock_detect) | struct timeval & deadlock_detect) |
: _max_threads(max), _min_threads(min), | : _max_threads(max), _min_threads(min), |
_current_threads(0), _waiters(initial_size), |
_current_threads(0), |
_pool_sem(0), _pool(true), _running(true), |
_pool(true), _running(true), |
_dead(true), _dying(0) | _dead(true), _dying(0) |
{ | { |
_allocate_wait.tv_sec = alloc_wait.tv_sec; | _allocate_wait.tv_sec = alloc_wait.tv_sec; |
|
|
ThreadPool::~ThreadPool(void) | ThreadPool::~ThreadPool(void) |
{ | { |
_dying++; | _dying++; |
Thread *th = _pool.remove_first(); |
Thread *th = 0; |
while(th != 0) | while(th != 0) |
{ | { |
Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem"); | Semaphore *sleep_sem = (Semaphore *)th->reference_tsd("sleep sem"); |
|
|
} | } |
catch(IPCException &) | catch(IPCException &) |
{ | { |
PEGASUS_STD(cout) << " ipc exception returning thread to avail list" << PEGASUS_STD(endl); |
|
| |
myself->exit_self(0); | myself->exit_self(0); |
} | } |
|
|
while(pool->_dying < 1) | while(pool->_dying < 1) |
{ | { |
sleep_sem->wait(); | sleep_sem->wait(); |
pegasus_yield(); |
|
| |
// when we awaken we reside on the running queue, not the pool queue | // when we awaken we reside on the running queue, not the pool queue |
if(pool->_dying > 0) | if(pool->_dying > 0) |
break; | break; |
| |
|
|
PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *_work)(void *) = 0; | PEGASUS_THREAD_RETURN (PEGASUS_THREAD_CDECL *_work)(void *) = 0; |
void *parm = 0; | void *parm = 0; |
| |
|
|
} | } |
catch(IPCException &) | catch(IPCException &) |
{ | { |
PEGASUS_STD(cout) << " ipc exception returning thread to avail list" << PEGASUS_STD(endl); |
|
| |
myself->exit_self(0); | myself->exit_self(0); |
} | } |
|
|
} | } |
catch(IPCException &) | catch(IPCException &) |
{ | { |
PEGASUS_STD(cout) << " ipc exception returning thread to avail list" << PEGASUS_STD(endl); |
|
| |
myself->exit_self(0); | myself->exit_self(0); |
} | } |
|
|
| |
Thread *th = _pool.remove_first(); | Thread *th = _pool.remove_first(); |
| |
|
|
// wait for the right interval and try again | // wait for the right interval and try again |
while(th == 0 && _dying < 1) | while(th == 0 && _dying < 1) |
{ | { |
_check_deadlock(&start); | _check_deadlock(&start); |
Uint32 interval = (_allocate_wait.tv_sec * 1000) + _allocate_wait.tv_usec; |
|
// will throw a timeout if no thread comes free |
|
try |
|
{ |
|
_pool_sem.time_wait(interval); |
|
} |
|
catch(TimeOut & ) |
|
{ |
|
if(_current_threads < _max_threads) | if(_current_threads < _max_threads) |
{ | { |
PEGASUS_STD(cout) << "timeout in waiting for free thread, allocating new thread " << PEGASUS_STD(endl); |
|
th = _init_thread(); | th = _init_thread(); |
continue; | continue; |
} | } |
PEGASUS_STD(cout) << " timeout but no free thread, looping" << PEGASUS_STD(endl); |
pegasus_yield(); |
|
|
} |
|
catch(IPCException & ) |
|
{ |
|
PEGASUS_STD(cout) << " IPC Exception " << PEGASUS_STD(endl); |
|
abort(); |
|
} |
|
|
|
|
|
th = _pool.remove_first(); | th = _pool.remove_first(); |
} | } |
| |
|
|
| |
if(sleep_sem == 0) | if(sleep_sem == 0) |
{ | { |
|
|
th->dereference_tsd(); | th->dereference_tsd(); |
throw NullPointer(); | throw NullPointer(); |
} | } |
|
|
// but should call it at least once per _deadlock_detect with the running q | // but should call it at least once per _deadlock_detect with the running q |
// and at least once per _deallocate_wait for the pool q | // and at least once per _deallocate_wait for the pool q |
| |
void ThreadPool::kill_dead_threads(void) |
Uint32 ThreadPool::kill_dead_threads(void) |
throw(IPCException) | throw(IPCException) |
{ | { |
struct timeval now; | struct timeval now; |
gettimeofday(&now, NULL); | gettimeofday(&now, NULL); |
|
Uint32 bodies = 0; |
| |
| |
// first go thread the dead q and clean it up as much as possible | // first go thread the dead q and clean it up as much as possible |
|
|
} | } |
// put the thread on the dead list | // put the thread on the dead list |
_dead.insert_first(th); | _dead.insert_first(th); |
|
bodies++; |
sleep_sem->signal(); | sleep_sem->signal(); |
th->dereference_tsd(); | th->dereference_tsd(); |
th = 0; | th = 0; |
|
|
} | } |
| |
| |
return; |
return bodies; |
} | } |
| |
|
|
|
// inline int timeval_subtract (struct timeval *result, |
|
// struct timeval *x, |
|
// struct timeval *y) |
|
// { |
|
// /* Perform the carry for the later subtraction by updating Y. */ |
|
// if (x->tv_usec < y->tv_usec) { |
|
// int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; |
|
// y->tv_usec -= 1000000 * nsec; |
|
// y->tv_sec += nsec; |
|
// } |
|
// if (x->tv_usec - y->tv_usec > 1000000) { |
|
// int nsec = (x->tv_usec - y->tv_usec) / 1000000; |
|
// y->tv_usec += 1000000 * nsec; |
|
// y->tv_sec -= nsec; |
|
// } |
|
|
|
// /* Compute the time remaining to wait. |
|
// `tv_usec' is certainly positive. */ |
|
// result->tv_sec = x->tv_sec - y->tv_sec; |
|
// result->tv_usec = x->tv_usec - y->tv_usec; |
|
|
|
// /* Return 1 if result is negative. */ |
|
// return x->tv_sec < y->tv_sec; |
|
// } |
|
|
Boolean ThreadPool::check_time(struct timeval *start, struct timeval *interval) | Boolean ThreadPool::check_time(struct timeval *start, struct timeval *interval) |
{ | { |
struct timeval now; | struct timeval now; |
gettimeofday(&now, NULL); | gettimeofday(&now, NULL); |
if( (now.tv_sec - start->tv_sec) > interval->tv_sec || |
start->tv_sec += interval->tv_sec; |
(((now.tv_sec - start->tv_sec) == interval->tv_sec) && |
start->tv_usec += interval->tv_usec; |
((now.tv_usec - start->tv_usec) >= interval->tv_usec ) ) ) |
start->tv_sec += start->tv_usec / 1000000; |
|
start->tv_usec %= 1000000; |
|
struct timeval remaining; |
|
|
|
if ( timeval_subtract(&remaining, start, &now) ) |
return true; | return true; |
else | else |
return false; | return false; |