/************************************************************************ * Function: TimerThreadShutdown * * Description: * Shutdown the timer thread * Events scheduled in the future will NOT be run. * Timer thread should be shutdown BEFORE it's associated * thread pool. * Returns: * returns 0 if succesfull, * nonzero otherwise. * Always returns 0. ***********************************************************************/ int TimerThreadShutdown( TimerThread * timer ) { ListNode *tempNode2 = NULL; ListNode *tempNode = NULL; assert( timer != NULL ); if( timer == NULL ) { return EINVAL; } ithread_mutex_lock( &timer->mutex ); timer->shutdown = 1; tempNode = ListHead( &timer->eventQ ); //Delete nodes in Q //call registered free function //on argument while( tempNode != NULL ) { TimerEvent *temp = ( TimerEvent * ) tempNode->item; tempNode2 = ListNext( &timer->eventQ, tempNode ); ListDelNode( &timer->eventQ, tempNode, 0 ); if( temp->job.free_func ) { temp->job.free_func( temp->job.arg ); } FreeTimerEvent( timer, temp ); tempNode = tempNode2; } ListDestroy( &timer->eventQ, 0 ); FreeListDestroy( &timer->freeEvents ); ithread_cond_broadcast( &timer->condition ); while( timer->shutdown ) //wait for timer thread to shutdown { ithread_cond_wait( &timer->condition, &timer->mutex ); } ithread_mutex_unlock( &timer->mutex ); //destroy condition while( ithread_cond_destroy( &timer->condition ) != 0 ) { } //destroy mutex while( ithread_mutex_destroy( &timer->mutex ) != 0 ) { } return 0; }
/*! * \brief Implements a thread pool worker. Worker waits for a job to become * available. Worker picks up persistent jobs first, high priority, * med priority, then low priority. * * If worker remains idle for more than specified max, the worker is released. * * \internal */ static void *WorkerThread( /*! arg -> is cast to (ThreadPool *). */ void *arg) { time_t start = 0; ThreadPoolJob *job = NULL; ListNode *head = NULL; struct timespec timeout; int retCode = 0; int persistent = -1; ThreadPool *tp = (ThreadPool *) arg; ithread_initialize_thread(); /* Increment total thread count */ ithread_mutex_lock(&tp->mutex); tp->totalThreads++; tp->pendingWorkerThreadStart = 0; ithread_cond_broadcast(&tp->start_and_shutdown); ithread_mutex_unlock(&tp->mutex); SetSeed(); StatsTime(&start); while (1) { ithread_mutex_lock(&tp->mutex); if (job) { tp->busyThreads--; FreeThreadPoolJob(tp, job); job = NULL; } retCode = 0; tp->stats.idleThreads++; tp->stats.totalWorkTime += (double)StatsTime(NULL) - (double)start; StatsTime(&start); if (persistent == 0) { tp->stats.workerThreads--; } else if (persistent == 1) { /* Persistent thread becomes a regular thread */ tp->persistentThreads--; } /* Check for a job or shutdown */ while (tp->lowJobQ.size == 0 && tp->medJobQ.size == 0 && tp->highJobQ.size == 0 && !tp->persistentJob && !tp->shutdown) { /* If wait timed out and we currently have more than the * min threads, or if we have more than the max threads * (only possible if the attributes have been reset) * let this thread die. */ if ((retCode == ETIMEDOUT && tp->totalThreads > tp->attr.minThreads) || (tp->attr.maxThreads != -1 && tp->totalThreads > tp->attr.maxThreads)) { tp->stats.idleThreads--; goto exit_function; } SetRelTimeout(&timeout, tp->attr.maxIdleTime); /* wait for a job up to the specified max time */ retCode = ithread_cond_timedwait( &tp->condition, &tp->mutex, &timeout); } tp->stats.idleThreads--; /* idle time */ tp->stats.totalIdleTime += (double)StatsTime(NULL) - (double)start; /* work time */ StatsTime(&start); /* bump priority of starved jobs */ BumpPriority(tp); /* if shutdown then stop */ if (tp->shutdown) { goto exit_function; } else { /* Pick up persistent job if available */ if (tp->persistentJob) { job = tp->persistentJob; tp->persistentJob = NULL; tp->persistentThreads++; persistent = 1; ithread_cond_broadcast(&tp->start_and_shutdown); } else { tp->stats.workerThreads++; persistent = 0; /* Pick the highest priority job */ if (tp->highJobQ.size > 0) { head = ListHead(&tp->highJobQ); if (head == NULL) { tp->stats.workerThreads--; goto exit_function; } job = (ThreadPoolJob *) head->item; CalcWaitTime(tp, HIGH_PRIORITY, job); ListDelNode(&tp->highJobQ, head, 0); } else if (tp->medJobQ.size > 0) { head = ListHead(&tp->medJobQ); if (head == NULL) { tp->stats.workerThreads--; goto exit_function; } job = (ThreadPoolJob *) head->item; CalcWaitTime(tp, MED_PRIORITY, job); ListDelNode(&tp->medJobQ, head, 0); } else if (tp->lowJobQ.size > 0) { head = ListHead(&tp->lowJobQ); if (head == NULL) { tp->stats.workerThreads--; goto exit_function; } job = (ThreadPoolJob *) head->item; CalcWaitTime(tp, LOW_PRIORITY, job); ListDelNode(&tp->lowJobQ, head, 0); } else { /* Should never get here */ tp->stats.workerThreads--; goto exit_function; } } } tp->busyThreads++; ithread_mutex_unlock(&tp->mutex); /* In the future can log info */ if (SetPriority(job->priority) != 0) { } else { } /* run the job */ job->func(job->arg); /* return to Normal */ SetPriority(DEFAULT_PRIORITY); } exit_function: tp->totalThreads--; ithread_cond_broadcast(&tp->start_and_shutdown); ithread_mutex_unlock(&tp->mutex); ithread_cleanup_thread(); return NULL; }
int ThreadPoolShutdown(ThreadPool *tp) { ListNode *head = NULL; ThreadPoolJob *temp = NULL; if (!tp) return EINVAL; ithread_mutex_lock(&tp->mutex); /* clean up high priority jobs */ while (tp->highJobQ.size) { head = ListHead(&tp->highJobQ); if (head == NULL) { ithread_mutex_unlock(&tp->mutex); return EINVAL; } temp = (ThreadPoolJob *)head->item; if (temp->free_func) temp->free_func(temp->arg); FreeThreadPoolJob(tp, temp); ListDelNode(&tp->highJobQ, head, 0); } ListDestroy(&tp->highJobQ, 0); /* clean up med priority jobs */ while (tp->medJobQ.size) { head = ListHead(&tp->medJobQ); if (head == NULL) { ithread_mutex_unlock(&tp->mutex); return EINVAL; } temp = (ThreadPoolJob *)head->item; if (temp->free_func) temp->free_func(temp->arg); FreeThreadPoolJob(tp, temp); ListDelNode(&tp->medJobQ, head, 0); } ListDestroy(&tp->medJobQ, 0); /* clean up low priority jobs */ while (tp->lowJobQ.size) { head = ListHead(&tp->lowJobQ); if (head == NULL) { ithread_mutex_unlock(&tp->mutex); return EINVAL; } temp = (ThreadPoolJob *)head->item; if (temp->free_func) temp->free_func(temp->arg); FreeThreadPoolJob(tp, temp); ListDelNode(&tp->lowJobQ, head, 0); } ListDestroy(&tp->lowJobQ, 0); /* clean up long term job */ if (tp->persistentJob) { temp = tp->persistentJob; if (temp->free_func) temp->free_func(temp->arg); FreeThreadPoolJob(tp, temp); tp->persistentJob = NULL; } /* signal shutdown */ tp->shutdown = 1; ithread_cond_broadcast(&tp->condition); /* wait for all threads to finish */ while (tp->totalThreads > 0) ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); /* destroy condition */ while (ithread_cond_destroy(&tp->condition) != 0) {} while (ithread_cond_destroy(&tp->start_and_shutdown) != 0) {} FreeListDestroy(&tp->jobFreeList); ithread_mutex_unlock(&tp->mutex); /* destroy mutex */ while (ithread_mutex_destroy(&tp->mutex) != 0) {} return 0; }
/**************************************************************************** * Function: WorkerThread * * Description: * Implements a thread pool worker. * Worker waits for a job to become available. * Worker picks up persistent jobs first, high priority, med priority, * then low priority. * If worker remains idle for more than specified max, the worker * is released. * Internal Only. * Parameters: * void * arg -> is cast to ThreadPool * *****************************************************************************/ static void *WorkerThread( void *arg ) { time_t start = 0; ThreadPoolJob *job = NULL; ListNode *head = NULL; struct timespec timeout; int retCode = 0; int persistent = -1; ThreadPool *tp = ( ThreadPool *) arg; // allow static linking #ifdef WIN32 #ifdef PTW32_STATIC_LIB pthread_win32_thread_attach_np(); #endif #endif assert( tp != NULL ); // Increment total thread count ithread_mutex_lock( &tp->mutex ); tp->totalThreads++; ithread_cond_broadcast( &tp->start_and_shutdown ); ithread_mutex_unlock( &tp->mutex ); SetSeed(); StatsTime( &start ); while( 1 ) { ithread_mutex_lock( &tp->mutex ); if( job ) { FreeThreadPoolJob( tp, job ); job = NULL; } retCode = 0; tp->stats.idleThreads++; tp->stats.totalWorkTime += ( StatsTime( NULL ) - start ); // work time StatsTime( &start ); // idle time if( persistent == 1 ) { // Persistent thread // becomes a regular thread tp->persistentThreads--; } if( persistent == 0 ) { tp->stats.workerThreads--; } // Check for a job or shutdown while( tp->lowJobQ.size == 0 && tp->medJobQ.size == 0 && tp->highJobQ.size == 0 && !tp->persistentJob && !tp->shutdown ) { // If wait timed out // and we currently have more than the // min threads, or if we have more than the max threads // (only possible if the attributes have been reset) // let this thread die. if( ( retCode == ETIMEDOUT && tp->totalThreads > tp->attr.minThreads ) || ( tp->attr.maxThreads != -1 && tp->totalThreads > tp->attr.maxThreads ) ) { tp->stats.idleThreads--; tp->totalThreads--; ithread_cond_broadcast( &tp->start_and_shutdown ); ithread_mutex_unlock( &tp->mutex ); #ifdef WIN32 #ifdef PTW32_STATIC_LIB // allow static linking pthread_win32_thread_detach_np (); #endif #endif return NULL; } SetRelTimeout( &timeout, tp->attr.maxIdleTime ); // wait for a job up to the specified max time retCode = ithread_cond_timedwait( &tp->condition, &tp->mutex, &timeout ); } tp->stats.idleThreads--; tp->stats.totalIdleTime += ( StatsTime( NULL ) - start ); // idle time StatsTime( &start ); // work time // bump priority of starved jobs BumpPriority( tp ); // if shutdown then stop if( tp->shutdown ) { tp->totalThreads--; ithread_cond_broadcast( &tp->start_and_shutdown ); ithread_mutex_unlock( &tp->mutex ); #ifdef WIN32 #ifdef PTW32_STATIC_LIB // allow static linking pthread_win32_thread_detach_np (); #endif #endif return NULL; } else { // Pick up persistent job if available if( tp->persistentJob ) { job = tp->persistentJob; tp->persistentJob = NULL; tp->persistentThreads++; persistent = 1; ithread_cond_broadcast( &tp->start_and_shutdown ); } else { tp->stats.workerThreads++; persistent = 0; // Pick the highest priority job if( tp->highJobQ.size > 0 ) { head = ListHead( &tp->highJobQ ); job = ( ThreadPoolJob *) head->item; CalcWaitTime( tp, HIGH_PRIORITY, job ); ListDelNode( &tp->highJobQ, head, 0 ); } else if( tp->medJobQ.size > 0 ) { head = ListHead( &tp->medJobQ ); job = ( ThreadPoolJob *) head->item; CalcWaitTime( tp, MED_PRIORITY, job ); ListDelNode( &tp->medJobQ, head, 0 ); } else if( tp->lowJobQ.size > 0 ) { head = ListHead( &tp->lowJobQ ); job = ( ThreadPoolJob *) head->item; CalcWaitTime( tp, LOW_PRIORITY, job ); ListDelNode( &tp->lowJobQ, head, 0 ); } else { // Should never get here assert( 0 ); tp->stats.workerThreads--; tp->totalThreads--; ithread_cond_broadcast( &tp->start_and_shutdown ); ithread_mutex_unlock( &tp->mutex ); return NULL; } } } ithread_mutex_unlock( &tp->mutex ); if( SetPriority( job->priority ) != 0 ) { // In the future can log // info } else { // In the future can log // info } // run the job job->func( job->arg ); // return to Normal SetPriority( DEFAULT_PRIORITY ); } }