/******************************************************************************** * upnp_igd_destroy * * Description: * Destroy an existing uPnP IGD context. * * Parameters: * igd_ctxt -- The upnp igd context * ********************************************************************************/ void upnp_igd_destroy(upnp_igd_context* igd_ctxt) { /* Stop client if started */ if(igd_ctxt->upnp_handle != -1) { upnp_igd_stop(igd_ctxt); } upnp_context_free_callbacks(igd_ctxt); UpnpFinish(); ithread_mutex_destroy(&igd_ctxt->devices_mutex); ithread_mutex_destroy(&igd_ctxt->callback_mutex); ithread_cond_destroy(&igd_ctxt->client_cond); ithread_mutex_destroy(&igd_ctxt->client_mutex); ithread_cond_destroy(&igd_ctxt->timer_cond); ithread_mutex_destroy(&igd_ctxt->timer_mutex); ithread_mutex_destroy(&igd_ctxt->print_mutex); ithread_mutex_destroy(&igd_ctxt->mutex); free(igd_ctxt); }
/************************************************************************ * Function: TimerThreadInit * * Description: * Initializes and starts timer thread. * * Parameters: * timer - valid timer thread pointer. * tp - valid thread pool to use. Must be * started. Must be valid for lifetime * of timer. Timer must be shutdown * BEFORE thread pool. * Return: * 0 on success, nonzero on failure * Returns error from ThreadPoolAddPersistent if failure. ************************************************************************/ int TimerThreadInit( TimerThread * timer, ThreadPool * tp ) { int rc = 0; ThreadPoolJob timerThreadWorker; assert( timer != NULL ); assert( tp != NULL ); if( ( timer == NULL ) || ( tp == NULL ) ) { return EINVAL; } rc += ithread_mutex_init( &timer->mutex, NULL ); assert( rc == 0 ); rc += ithread_mutex_lock( &timer->mutex ); assert( rc == 0 ); rc += ithread_cond_init( &timer->condition, NULL ); assert( rc == 0 ); rc += FreeListInit( &timer->freeEvents, sizeof( TimerEvent ), 100 ); assert( rc == 0 ); timer->shutdown = 0; timer->tp = tp; timer->lastEventId = 0; rc += ListInit( &timer->eventQ, NULL, NULL ); assert( rc == 0 ); if( rc != 0 ) { rc = EAGAIN; } else { TPJobInit( &timerThreadWorker, TimerThreadWorker, timer ); TPJobSetPriority( &timerThreadWorker, HIGH_PRIORITY ); rc = ThreadPoolAddPersistent( tp, &timerThreadWorker, NULL ); } ithread_mutex_unlock( &timer->mutex ); if( rc != 0 ) { ithread_cond_destroy( &timer->condition ); ithread_mutex_destroy( &timer->mutex ); FreeListDestroy( &timer->freeEvents ); ListDestroy( &timer->eventQ, 0 ); } return rc; }
/************************************************************************ * 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; }
/******************************************************************************** * upnp_igd_create * * Description: * Create and return uPnP IGD context if there is no error otherwise * NULL. * * Parameters: * cb_fct -- The function to call back for each events * print_fct -- The function used for print logs * cookie -- The cookie pass in cb_fct or print_fct * ********************************************************************************/ upnp_igd_context* upnp_igd_create(upnp_igd_callback_function cb_fct, upnp_igd_print_function print_fct, const char *address, void *cookie) { int ret; unsigned short port = 0; const char *ip_address = address; upnp_igd_context *igd_ctxt = (upnp_igd_context*)malloc(sizeof(upnp_igd_context)); igd_ctxt->devices = NULL; igd_ctxt->callback_fct = cb_fct; igd_ctxt->callback_events = NULL; igd_ctxt->print_fct = print_fct; igd_ctxt->cookie = cookie; igd_ctxt->max_adv_timeout = 60*3; igd_ctxt->timer_timeout = igd_ctxt->max_adv_timeout/2; igd_ctxt->upnp_handle = -1; igd_ctxt->client_count = 0; igd_ctxt->timer_thread = (ithread_t)NULL; /* Initialize mutex */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&igd_ctxt->mutex, &attr); ithread_mutexattr_destroy(&attr); } /* Initialize print mutex */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&igd_ctxt->print_mutex, &attr); ithread_mutexattr_destroy(&attr); } /* Initialize callback mutex */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&igd_ctxt->callback_mutex, &attr); ithread_mutexattr_destroy(&attr); } /* Initialize device mutex */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&igd_ctxt->devices_mutex, &attr); ithread_mutexattr_destroy(&attr); } /* Initialize timer stuff */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_FAST_NP); ithread_mutex_init(&igd_ctxt->timer_mutex, &attr); ithread_mutexattr_destroy(&attr); ithread_cond_init(&igd_ctxt->timer_cond, NULL); } /* Initialize client stuff */ { ithread_mutexattr_t attr; ithread_mutexattr_init(&attr); ithread_mutexattr_setkind_np(&attr, ITHREAD_MUTEX_RECURSIVE_NP); ithread_mutex_init(&igd_ctxt->client_mutex, &attr); ithread_mutexattr_destroy(&attr); ithread_cond_init(&igd_ctxt->client_cond, NULL); } upnp_igd_print(igd_ctxt, UPNP_IGD_DEBUG, "Initializing uPnP IGD with ipaddress:%s port:%u", ip_address ? ip_address : "{NULL}", port); ret = UpnpInit(ip_address, port); if (ret != UPNP_E_SUCCESS) { upnp_igd_print(igd_ctxt, UPNP_IGD_ERROR, "UpnpInit() Error: %d", ret); UpnpFinish(); ithread_mutex_destroy(&igd_ctxt->print_mutex); ithread_mutex_destroy(&igd_ctxt->devices_mutex); ithread_mutex_destroy(&igd_ctxt->timer_mutex); ithread_cond_destroy(&igd_ctxt->timer_cond); ithread_mutex_destroy(&igd_ctxt->callback_mutex); ithread_mutex_destroy(&igd_ctxt->client_mutex); ithread_cond_destroy(&igd_ctxt->client_cond); ithread_mutex_destroy(&igd_ctxt->mutex); free(igd_ctxt); return NULL; } if (!ip_address) { ip_address = UpnpGetServerIpAddress(); } if (!port) { port = UpnpGetServerPort(); } upnp_igd_print(igd_ctxt, UPNP_IGD_MESSAGE, "uPnP IGD Initialized ipaddress:%s port:%u", ip_address ? ip_address : "{NULL}", port); return igd_ctxt; }
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; }
int ThreadPoolInit(ThreadPool *tp, ThreadPoolAttr *attr) { int retCode = 0; int i = 0; if (!tp) { return EINVAL; } retCode += ithread_mutex_init(&tp->mutex, NULL); retCode += ithread_mutex_lock(&tp->mutex); retCode += ithread_cond_init(&tp->condition, NULL); retCode += ithread_cond_init(&tp->start_and_shutdown, NULL); if (retCode) { ithread_mutex_unlock(&tp->mutex); ithread_mutex_destroy(&tp->mutex); ithread_cond_destroy(&tp->condition); ithread_cond_destroy(&tp->start_and_shutdown); return EAGAIN; } if (attr) { tp->attr = *attr; } else { TPAttrInit(&tp->attr); } if (SetPolicyType(tp->attr.schedPolicy) != 0) { ithread_mutex_unlock(&tp->mutex); ithread_mutex_destroy(&tp->mutex); ithread_cond_destroy(&tp->condition); ithread_cond_destroy(&tp->start_and_shutdown); return INVALID_POLICY; } retCode += FreeListInit( &tp->jobFreeList, sizeof(ThreadPoolJob), JOBFREELISTSIZE); StatsInit(&tp->stats); retCode += ListInit(&tp->highJobQ, CmpThreadPoolJob, NULL); retCode += ListInit(&tp->medJobQ, CmpThreadPoolJob, NULL); retCode += ListInit(&tp->lowJobQ, CmpThreadPoolJob, NULL); if (retCode) { retCode = EAGAIN; } else { tp->persistentJob = NULL; tp->lastJobId = 0; tp->shutdown = 0; tp->totalThreads = 0; tp->busyThreads = 0; tp->persistentThreads = 0; tp->pendingWorkerThreadStart = 0; for (i = 0; i < tp->attr.minThreads; ++i) { retCode = CreateWorker(tp); if (retCode) { break; } } } ithread_mutex_unlock(&tp->mutex); if (retCode) { /* clean up if the min threads could not be created */ ThreadPoolShutdown(tp); } return retCode; }
/**************************************************************************** * Function: ThreadPoolInit * * Description: * Initializes and starts ThreadPool. Must be called first. * And only once for ThreadPool. * Parameters: * tp - must be valid, non null, pointer to ThreadPool. * minWorkerThreads - minimum number of worker threads * thread pool will never have less than this * number of threads. * maxWorkerThreads - maximum number of worker threads * thread pool will never have more than this * number of threads. * maxIdleTime - maximum time that a worker thread will spend * idle. If a worker is idle longer than this * time and there are more than the min * number of workers running, than the * worker thread exits. * jobsPerThread - ratio of jobs to thread to try and maintain * if a job is scheduled and the number of jobs per * thread is greater than this number,and * if less than the maximum number of * workers are running then a new thread is * started to help out with efficiency. * schedPolicy - scheduling policy to try and set (OS dependent) * Returns: * 0 on success, nonzero on failure. * EAGAIN if not enough system resources to create minimum threads. * INVALID_POLICY if schedPolicy can't be set * EMAXTHREADS if minimum threads is greater than maximum threads *****************************************************************************/ int ThreadPoolInit( ThreadPool *tp, ThreadPoolAttr *attr ) { int retCode = 0; int i = 0; //printf("%s, %d\n", __FUNCTION__, __LINE__); assert( tp != NULL ); if( tp == NULL ) { return EINVAL; } #ifdef WIN32 #ifdef PTW32_STATIC_LIB pthread_win32_process_attach_np(); #endif #endif //printf("%s, %d\n", __FUNCTION__, __LINE__); retCode += ithread_mutex_init( &tp->mutex, NULL ); assert( retCode == 0 ); retCode += ithread_mutex_lock( &tp->mutex ); assert( retCode == 0 ); retCode += ithread_cond_init( &tp->condition, NULL ); assert( retCode == 0 ); retCode += ithread_cond_init( &tp->start_and_shutdown, NULL ); assert( retCode == 0 ); //printf("%s, %d\n", __FUNCTION__, __LINE__); if( retCode != 0 ) { return EAGAIN; } if( attr ) { tp->attr = ( *attr ); } else { TPAttrInit( &tp->attr ); } //printf("%s, %d, minthreads: %d\n", __FUNCTION__, __LINE__, tp->attr.minThreads); if( SetPolicyType( tp->attr.schedPolicy ) != 0 ) { ithread_mutex_unlock( &tp->mutex ); ithread_mutex_destroy( &tp->mutex ); ithread_cond_destroy( &tp->condition ); ithread_cond_destroy( &tp->start_and_shutdown ); return INVALID_POLICY; } //printf("%s, %d\n", __FUNCTION__, __LINE__); retCode += FreeListInit( &tp->jobFreeList, sizeof( ThreadPoolJob ), JOBFREELISTSIZE ); assert( retCode == 0 ); StatsInit( &tp->stats ); retCode += ListInit( &tp->highJobQ, CmpThreadPoolJob, NULL ); assert( retCode == 0 ); retCode += ListInit( &tp->medJobQ, CmpThreadPoolJob, NULL ); assert( retCode == 0 ); retCode += ListInit( &tp->lowJobQ, CmpThreadPoolJob, NULL ); assert( retCode == 0 ); //printf("%s, %d, retcode is %d\n", __FUNCTION__, __LINE__, retCode); if( retCode != 0 ) { retCode = EAGAIN; //printf("%s, %d\n", __FUNCTION__, __LINE__); } else { //printf("%s, %d\n", __FUNCTION__, __LINE__); tp->persistentJob = NULL; tp->lastJobId = 0; tp->shutdown = 0; tp->totalThreads = 0; tp->persistentThreads = 0; //printf("%s, %d\n", __FUNCTION__, __LINE__); for( i = 0; i < tp->attr.minThreads; ++i ) { if( ( retCode = CreateWorker( tp ) ) != 0 ) { //printf("%s, %d\n", __FUNCTION__, __LINE__); break; } } } //printf("%s, %d\n", __FUNCTION__, __LINE__); ithread_mutex_unlock( &tp->mutex ); if( retCode != 0 ) { // clean up if the min threads could not be created ThreadPoolShutdown( tp ); } //printf("%s, %d\n", __FUNCTION__, __LINE__); return retCode; }