/******************************************************************************** * upnp_igd_stop * * Description: * Stop uPnP IGD context. * * Parameters: * igd_ctxt -- The upnp igd context * ********************************************************************************/ int upnp_igd_stop(upnp_igd_context *igd_ctxt) { ithread_mutex_lock(&igd_ctxt->mutex); if(igd_ctxt->upnp_handle == -1) { upnp_igd_print(igd_ctxt, UPNP_IGD_WARNING, "uPnP IGD client already stopped..."); ithread_mutex_unlock(&igd_ctxt->mutex); return -1; } ithread_mutex_lock(&igd_ctxt->timer_mutex); ithread_cond_signal(&igd_ctxt->timer_cond); ithread_mutex_unlock(&igd_ctxt->timer_mutex); ithread_join(igd_ctxt->timer_thread, NULL); upnp_igd_remove_all(igd_ctxt); UpnpUnRegisterClient(igd_ctxt->upnp_handle); // Wait that all clients are finish the callback // Doing UpnpUnRegisterClient no more callbacks are bone // But current running clients are still here ithread_mutex_lock(&igd_ctxt->client_mutex); while(igd_ctxt->client_count > 0) { ithread_cond_wait(&igd_ctxt->client_cond, &igd_ctxt->client_mutex); } ithread_mutex_unlock(&igd_ctxt->client_mutex); igd_ctxt->upnp_handle = -1; ithread_mutex_unlock(&igd_ctxt->mutex); // Handle remaining callbacks upnp_context_handle_callbacks(igd_ctxt); return 0; }
/**************************************************************************** * Function: ThreadPoolAddPersistent * * Description: * Adds a long term job to the thread pool. * Job will be run as soon as possible. * Call will block until job is scheduled. * Parameters: * tp - valid thread pool pointer * job-> valid ThreadPoolJob pointer with following fields * func - ThreadFunction to run * arg - argument to function. * priority - priority of job. * free_function - function to use when freeing argument * Returns: * 0 on success, nonzero on failure * EOUTOFMEM not enough memory to add job. * EMAXTHREADS not enough threads to add persistent job. *****************************************************************************/ int ThreadPoolAddPersistent( ThreadPool *tp, ThreadPoolJob *job, int *jobId ) { int tempId = -1; ThreadPoolJob *temp = NULL; assert( tp != NULL ); assert( job != NULL ); if( ( tp == NULL ) || ( job == NULL ) ) { return EINVAL; } if( jobId == NULL ) { jobId = &tempId; } *jobId = INVALID_JOB_ID; ithread_mutex_lock( &tp->mutex ); assert( job->priority == LOW_PRIORITY || job->priority == MED_PRIORITY || job->priority == HIGH_PRIORITY ); // Create A worker if less than max threads running if( tp->totalThreads < tp->attr.maxThreads ) { CreateWorker( tp ); } else { // if there is more than one worker thread // available then schedule job, otherwise fail if( tp->totalThreads - tp->persistentThreads - 1 == 0 ) { ithread_mutex_unlock( &tp->mutex ); return EMAXTHREADS; } } temp = CreateThreadPoolJob( job, tp->lastJobId, tp ); if( temp == NULL ) { ithread_mutex_unlock( &tp->mutex ); return EOUTOFMEM; } tp->persistentJob = temp; // Notify a waiting thread ithread_cond_signal( &tp->condition ); // wait until long job has been picked up while( tp->persistentJob != NULL ) { ithread_cond_wait( &tp->start_and_shutdown, &tp->mutex ); } *jobId = tp->lastJobId++; ithread_mutex_unlock( &tp->mutex ); return 0; }
/************************************************************************ * 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 Creates a worker thread, if the thread pool does not already have * max threads. * * \remark The ThreadPool object mutex must be locked prior to calling this * function. * * \internal * * \return * \li \c 0 on success, < 0 on failure. * \li \c EMAXTHREADS if already max threads reached. * \li \c EAGAIN if system can not create thread. */ static int CreateWorker( /*! A pointer to the ThreadPool object. */ ThreadPool *tp) { ithread_t temp; int rc = 0; ithread_attr_t attr; /* if a new worker is the process of starting, wait until it fully starts */ while (tp->pendingWorkerThreadStart) { ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); } if (tp->attr.maxThreads != INFINITE_THREADS && tp->totalThreads + 1 > tp->attr.maxThreads) { return EMAXTHREADS; } ithread_attr_init(&attr); ithread_attr_setstacksize(&attr, tp->attr.stackSize); ithread_attr_setdetachstate(&attr, ITHREAD_CREATE_DETACHED); rc = ithread_create(&temp, &attr, WorkerThread, tp); ithread_attr_destroy(&attr); if (rc == 0) { rc = ithread_detach(temp); /* ithread_detach will return EINVAL if thread has been successfully detached by ithread_create */ if (rc == EINVAL) rc = 0; tp->pendingWorkerThreadStart = 1; /* wait until the new worker thread starts */ while (tp->pendingWorkerThreadStart) { ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); } } if (tp->stats.maxThreads < tp->totalThreads) { tp->stats.maxThreads = tp->totalThreads; } return rc; }
int ThreadPoolAddPersistent(ThreadPool *tp, ThreadPoolJob *job, int *jobId) { int ret = 0; int tempId = -1; ThreadPoolJob *temp = NULL; if (!tp || !job) { return EINVAL; } if (!jobId) { jobId = &tempId; } *jobId = INVALID_JOB_ID; ithread_mutex_lock(&tp->mutex); /* Create A worker if less than max threads running */ if (tp->totalThreads < tp->attr.maxThreads) { CreateWorker(tp); } else { /* if there is more than one worker thread * available then schedule job, otherwise fail */ if (tp->totalThreads - tp->persistentThreads - 1 == 0) { ret = EMAXTHREADS; goto exit_function; } } temp = CreateThreadPoolJob(job, tp->lastJobId, tp); if (!temp) { ret = EOUTOFMEM; goto exit_function; } tp->persistentJob = temp; /* Notify a waiting thread */ ithread_cond_signal(&tp->condition); /* wait until long job has been picked up */ while (tp->persistentJob) ithread_cond_wait(&tp->start_and_shutdown, &tp->mutex); *jobId = tp->lastJobId++; exit_function: ithread_mutex_unlock(&tp->mutex); return ret; }
/**************************************************************************** * Function: CreateWorker * * Description: * Creates a worker thread, if the thread pool * does not already have max threads. * Internal to thread pool. * Parameters: * ThreadPool *tp * * Returns: * 0 on success, <0 on failure * EMAXTHREADS if already max threads reached * EAGAIN if system can not create thread * *****************************************************************************/ static int CreateWorker( ThreadPool *tp ) { //printf("%s, %d\n", __FUNCTION__, __LINE__); ithread_t temp; int rc = 1; int currentThreads = tp->totalThreads + 1; //printf("%s, %d\n", __FUNCTION__, __LINE__); assert( tp != NULL ); if ( tp->attr.maxThreads != INFINITE_THREADS && currentThreads > tp->attr.maxThreads ) { return EMAXTHREADS; } //printf("%s, %d\n", __FUNCTION__, __LINE__); //rc = ithread_create( &temp, NULL, WorkerThread, tp ); rc = pthread_create( &temp, NULL, WorkerThread, tp ); //printf("%s, %d, %d\n", __FUNCTION__, __LINE__, rc); //pthread_join(temp, NULL); //printf("%s, %d\n", __FUNCTION__, __LINE__); if( rc == 0 ) { rc = ithread_detach( temp ); //printf("%s, %d, totalThreads: %d, currentThreads: %d\n", __FUNCTION__, __LINE__, tp->totalThreads, currentThreads); while( tp->totalThreads < currentThreads ) { //printf("%s, %d\n", __FUNCTION__, __LINE__, tp->totalThreads, currentThreads); ithread_cond_wait( &tp->start_and_shutdown, &tp->mutex ); } } //printf("%s, %d\n", __FUNCTION__, __LINE__); if( tp->stats.maxThreads < tp->totalThreads ) { tp->stats.maxThreads = tp->totalThreads; } //printf("%s, %d\n", __FUNCTION__, __LINE__); return rc; }
/**************************************************************************** * Function: TimerThreadWorker * * Description: * Implements timer thread. * Waits for next event to occur and schedules * associated job into threadpool. * Internal Only. * Parameters: * void * arg -> is cast to TimerThread * *****************************************************************************/ static void * TimerThreadWorker( void *arg ) { TimerThread *timer = ( TimerThread * ) arg; ListNode *head = NULL; TimerEvent *nextEvent = NULL; time_t currentTime = 0; time_t nextEventTime = 0; struct timespec timeToWait; int tempId; assert( timer != NULL ); ithread_mutex_lock( &timer->mutex ); while( 1 ) { //mutex should always be locked at top of loop //Check for shutdown if( timer->shutdown ) { timer->shutdown = 0; ithread_cond_signal( &timer->condition ); ithread_mutex_unlock( &timer->mutex ); return NULL; } nextEvent = NULL; //Get the next event if possible if( timer->eventQ.size > 0 ) { head = ListHead( &timer->eventQ ); nextEvent = ( TimerEvent * ) head->item; nextEventTime = nextEvent->eventTime; } currentTime = time( NULL ); //If time has elapsed, schedule job if( ( nextEvent != NULL ) && ( currentTime >= nextEventTime ) ) { if( nextEvent->persistent ) { ThreadPoolAddPersistent( timer->tp, &nextEvent->job, &tempId ); } else { ThreadPoolAdd( timer->tp, &nextEvent->job, &tempId ); } ListDelNode( &timer->eventQ, head, 0 ); FreeTimerEvent( timer, nextEvent ); continue; } if( nextEvent != NULL ) { timeToWait.tv_nsec = 0; timeToWait.tv_sec = nextEvent->eventTime; ithread_cond_timedwait( &timer->condition, &timer->mutex, &timeToWait ); } else { ithread_cond_wait( &timer->condition, &timer->mutex ); } } }
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; }