/******************************************************************************** * upnp_igd_timer_loop * * Description: * Thread function which check the timeouts. * * Parameters: * args -- The upnp igd context * ********************************************************************************/ void *upnp_igd_timer_loop(void *args) { upnp_igd_context *igd_ctxt = (upnp_igd_context*)args; struct timespec ts; struct timeval tp; /* how often to verify the timeouts, in seconds */ int incr = igd_ctxt->timer_timeout; // Update timeout gettimeofday(&tp, NULL); ts.tv_sec = tp.tv_sec; ts.tv_nsec = tp.tv_usec * 1000; ts.tv_sec += incr; ithread_mutex_lock(&igd_ctxt->timer_mutex); while(ithread_cond_timedwait(&igd_ctxt->timer_cond, &igd_ctxt->timer_mutex, &ts) == ETIMEDOUT) { upnp_igd_verify_timeouts(igd_ctxt, incr); upnp_context_handle_callbacks(igd_ctxt); // Update timeout gettimeofday(&tp, NULL); ts.tv_sec = tp.tv_sec; ts.tv_nsec = tp.tv_usec * 1000; ts.tv_sec += incr; } ithread_mutex_unlock(&igd_ctxt->timer_mutex); return NULL; }
int wphoto_upnp_handshake(void) { int ret = -1, err; char descurl[256]; const char *desc_xml = "MobileDevDesc.xml"; struct timespec timer; int camera_responded_save; char *camera_url_save; int pinged_camera; ithread_mutex_init(&state_mutex, NULL); ithread_cond_init(&state_cond, NULL); camera_url = NULL; camera_responded = 0; err = UpnpInit(NULL, 0); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpInit", err); goto err_init; } server_ip = UpnpGetServerIpAddress(); server_port = UpnpGetServerPort(); if (init_xml_docs() < 0) { perror("init_xml_docs"); goto err_init; } printf("address: %s:%d\n", server_ip, server_port); snprintf(descurl, sizeof(descurl), "http://%s:%d/%s", server_ip, server_port, desc_xml); err = web_add_callback("/MobileDevDesc.xml", web_MobileDevDesc, NULL); if (err) { perror("web_add_callback"); goto err_init; } err = web_add_callback("/desc_iml/CameraConnectedMobile.xml", web_CameraConnectedMobile, NULL); if (err) { perror("web_add_callback"); goto err_init; } if (web_start() < 0) { printf("web_init error\n"); goto err_init; } err = UpnpRegisterRootDevice(descurl, upnp_device_event_handler, &device_handle, &device_handle); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpRegisterRootDevice", err); goto err_init; } err = UpnpRegisterClient(upnp_client_event_handler, &client_handle, &client_handle); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpRegisterClient", err); goto err_register; } clock_gettime(CLOCK_REALTIME, &timer); discovery_timeout = 1; camera_responded_save = 0; camera_url_save = NULL; pinged_camera = 0; do { int wait_err; if (!camera_responded_save) { err = UpnpSendAdvertisement(device_handle, 0); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpSendAdvertisement", err); goto err_register; } printf("NOTIFY sent\n"); } if (camera_url_save && !pinged_camera) if (ping_camera(camera_url_save) == 0) pinged_camera = 1; timer.tv_sec += ADVERTISEMENT_INTERVAL; wait: ithread_mutex_lock(&state_mutex); wait_err = 0; while (camera_responded == camera_responded_save && strcmp_null(camera_url, camera_url_save) == 0 && !discovery_timeout && wait_err == 0) wait_err = ithread_cond_timedwait( &state_cond, &state_mutex, &timer); camera_responded_save = camera_responded; if (strcmp_null(camera_url, camera_url_save) != 0) { free(camera_url_save); camera_url_save = strdup(camera_url); } /* * Once we have the camera url, we stop sending M-SEARCH * requests */ if (discovery_timeout && !camera_url_save) { err = UpnpSearchAsync(client_handle, MSEARCH_INTERVAL, CAMERA_SERVICE_NAME, (void*)42); if (err != UPNP_E_SUCCESS) { upnp_perror("UpnpSearchAsync", err); goto err_register; } printf("M-SEARCH sent\n"); } discovery_timeout = 0; ithread_mutex_unlock(&state_mutex); if (wait_err != ETIMEDOUT && (!pinged_camera || !camera_responded_save)) goto wait; } while (!pinged_camera || !camera_responded_save); return 0; err_register: UpnpUnRegisterRootDevice(device_handle); err_init: UpnpFinish(); return ret; }
/*! * \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; }
/**************************************************************************** * 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 ); } } }
/**************************************************************************** * 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 ); } }