Example #1
0
int ThreadPoolRemove(ThreadPool *tp, int jobId, ThreadPoolJob *out)
{
	int ret = INVALID_JOB_ID;
	ThreadPoolJob *temp = NULL;
	ListNode *tempNode = NULL;
	ThreadPoolJob dummy;

	if (!tp)
		return EINVAL;
	if (!out)
		out = &dummy;
	dummy.jobId = jobId;

	ithread_mutex_lock(&tp->mutex);

	tempNode = ListFind(&tp->highJobQ, NULL, &dummy);
	if (tempNode) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode(&tp->highJobQ, tempNode, 0);
		FreeThreadPoolJob(tp, temp);
		ret = 0;
		goto exit_function;
	}

	tempNode = ListFind(&tp->medJobQ, NULL, &dummy);
	if (tempNode) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode(&tp->medJobQ, tempNode, 0);
		FreeThreadPoolJob(tp, temp);
		ret = 0;
		goto exit_function;
	}
	tempNode = ListFind(&tp->lowJobQ, NULL, &dummy);
	if (tempNode) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode(&tp->lowJobQ, tempNode, 0);
		FreeThreadPoolJob(tp, temp);
		ret = 0;
		goto exit_function;
	}
	if (tp->persistentJob && tp->persistentJob->jobId == jobId) {
		*out = *tp->persistentJob;
		FreeThreadPoolJob(tp, tp->persistentJob);
		tp->persistentJob = NULL;
		ret = 0;
		goto exit_function;
	}

exit_function:
	ithread_mutex_unlock(&tp->mutex);

	return ret;
}
Example #2
0
/*
 * This gets called before queuing a new event.
 * - The list size can never go over MAX_SUBSCRIPTION_QUEUED_EVENTS so we
 *   discard the oldest non-active event if it is already at the max
 * - We also discard any non-active event older than MAX_SUBSCRIPTION_EVENT_AGE.
 * non-active: any but the head of queue, which is already copied to
 * the thread pool
 */
static void maybeDiscardEvents(LinkedList *listp)
{
	time_t now = time(0L);

	while (ListSize(listp) > 1) {
		ListNode *node = ListHead(listp);
		/* The first candidate is the second event: first non-active */
		if (node == 0 || (node = node->next) == 0) {
			/* Major inconsistency, really, should abort here. */
			fprintf(stderr, "gena_device: maybeDiscardEvents: "
					"list is inconsistent\n");
			break;
		}

		notify_thread_struct *ntsp =
			(notify_thread_struct *)(((ThreadPoolJob *)node->item)->arg);
		if (ListSize(listp) > g_UpnpSdkEQMaxLen ||
			now - ntsp->ctime > g_UpnpSdkEQMaxAge) {
			free_notify_struct(ntsp);
			free(node->item);
			ListDelNode(listp, node, 0);
		} else {
			/* If the list is smaller than the max and the oldest
			 * task is young enough, stop pruning */
			break;
		}
	}
}
Example #3
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;
}
Example #4
0
/****************************************************************************
 * Function: BumpPriority
 *
 *  Description:
 *      Determines whether any jobs
 *      need to be bumped to a higher priority Q and bumps them.
 *
 *      tp->mutex must be locked.
 *      Internal Only.
 *  Parameters:
 *      ThreadPool *tp
 *****************************************************************************/
static void BumpPriority( ThreadPool *tp )
{
    int done = 0;
    struct timeval now;
    unsigned long diffTime = 0;
    ThreadPoolJob *tempJob = NULL;

    assert( tp != NULL );

    gettimeofday(&now, NULL);	

    while( !done ) {
        if( tp->medJobQ.size ) {
            tempJob = ( ThreadPoolJob *) tp->medJobQ.head.next->item;
            diffTime = DiffMillis( &now, &tempJob->requestTime );
            if( diffTime >= ( tp->attr.starvationTime ) ) {
                // If job has waited longer than the starvation time
                // bump priority (add to higher priority Q)
                StatsAccountMQ( tp, diffTime );
                ListDelNode( &tp->medJobQ, tp->medJobQ.head.next, 0 );
                ListAddTail( &tp->highJobQ, tempJob );
                continue;
            }
        }
        if( tp->lowJobQ.size ) {
            tempJob = ( ThreadPoolJob *) tp->lowJobQ.head.next->item;
            diffTime = DiffMillis( &now, &tempJob->requestTime );
            if( diffTime >= ( tp->attr.maxIdleTime ) ) {
                // If job has waited longer than the starvation time
                // bump priority (add to higher priority Q)
                StatsAccountLQ( tp, diffTime );
                ListDelNode( &tp->lowJobQ, tp->lowJobQ.head.next, 0 );
                ListAddTail( &tp->medJobQ, tempJob );
                continue;
            }
        }
        done = 1;
    }
}
Example #5
0
/************************************************************************
* Function : searchExpired											
*																	
* Parameters:														
*		IN void * arg:
*
* Description:														
*	This function 
*
* Returns: void
*
***************************************************************************/
void
searchExpired( void *arg )
{

    int *id = ( int * )arg;
    int handle = -1;
    struct Handle_Info *ctrlpt_info = NULL;

    //remove search Target from list and call client back
    ListNode *node = NULL;
    SsdpSearchArg *item;
    Upnp_FunPtr ctrlpt_callback;
    void *cookie = NULL;
    int found = 0;

    HandleLock(  );

    //remove search target from search list

    if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
        free( id );
        HandleUnlock(  );
        return;
    }

    ctrlpt_callback = ctrlpt_info->Callback;

    node = ListHead( &ctrlpt_info->SsdpSearchList );

    while( node != NULL ) {
        item = ( SsdpSearchArg * ) node->item;
        if( item->timeoutEventId == ( *id ) ) {
            free( item->searchTarget );
            cookie = item->cookie;
            found = 1;
            item->searchTarget = NULL;
            free( item );
            ListDelNode( &ctrlpt_info->SsdpSearchList, node, 0 );
            break;
        }
        node = ListNext( &ctrlpt_info->SsdpSearchList, node );
    }
    HandleUnlock(  );

    if( found ) {
        ctrlpt_callback( UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie );
    }

    free( id );
}
static void s_Delete_Object(t_FAKE_OBJ *fake_hnd)
{
	ListNode *node = ListHead(&s_object_list);
	
	while( node )
	{
		if( node->item == (void*)fake_hnd )
		{
			free(fake_hnd);
			ListDelNode(&s_object_list, node, 0);
			break;
		}
		node = ListNext(&s_object_list, node);
	}
}
Example #7
0
/****************************************************************************
 * Function: ListDestroy
 *
 *  Description:
 *      Removes all memory associated with list nodes.
 *      Does not free LinkedList *list.
 *      Items stored in the list are not freed, only nodes are.
 *  Parameters:
 *      LinkedList *list  - must be valid, non null, pointer to a linked list.
 *  Returns:
 *      0 on success. Nonzero on failure.
 *      Always returns 0.
 *  Precondition:
 *      The list has been initialized.
 *****************************************************************************/
int
ListDestroy( LinkedList * list,
             int freeItem )
{
    ListNode *dnode = NULL;
    ListNode *temp = NULL;

    if( list == NULL )
        return EINVAL;

    for( dnode = list->head.next; dnode != &list->tail; ) {
        temp = dnode->next;
        ListDelNode( list, dnode, freeItem );
        dnode = temp;
    }

    list->size = 0;
    FreeListDestroy( &list->freeNodeList );
    return 0;
}
Example #8
0
void freeSubscriptionQueuedEvents(subscription *sub)
{
	if (ListSize(&sub->outgoing) > 0) {
		/* The first event is discarded without dealing
		   notify_thread_struct: there is a mirror ThreadPool entry for
		   this one, and it will take care of the refcount etc. Other
		   entries must be fully cleaned-up here */
		int first = 1;
		ListNode *node = ListHead(&sub->outgoing);
		while (node) {
			ThreadPoolJob *job = (ThreadPoolJob *)node->item;
			if (first) {
				first = 0;
			} else {
				free_notify_struct((notify_thread_struct *)job->arg);
			}
			free(node->item);
			ListDelNode(&sub->outgoing, node, 0);
			node = ListHead(&sub->outgoing);
		}
	}
}
Example #9
0
/************************************************************************
 * Function: TimerThreadRemove
 * 
 *  Description:
 *     Removes an event from the timer Q.
 *     Events can only be removed 
 *     before they have been placed in the
 *     thread pool.
 *
 *  Parameters:
 *             timer - valid timer thread pointer.
 *             id - id of event to remove.
 *             out - space for returned job (Can be NULL)
 *  Return:
 *            0 on success.
 *            INVALID_EVENT_ID on error.
 *
 ************************************************************************/
int
TimerThreadRemove( TimerThread * timer,
                   int id,
                   ThreadPoolJob * out )
{
    int rc = INVALID_EVENT_ID;
    ListNode *tempNode = NULL;
    TimerEvent *temp = NULL;

    assert( timer != NULL );

    if( timer == NULL ) {
        return EINVAL;
    }

    ithread_mutex_lock( &timer->mutex );

    tempNode = ListHead( &timer->eventQ );

    while( tempNode != NULL ) {
        temp = ( TimerEvent * ) tempNode->item;
        if( temp->id == id )
        {

            ListDelNode( &timer->eventQ, tempNode, 0 );
            if( out != NULL )
                ( *out ) = temp->job;
            FreeTimerEvent( timer, temp );
            rc = 0;
            break;
        }
        tempNode = ListNext( &timer->eventQ, tempNode );
    }

    ithread_mutex_unlock( &timer->mutex );
    return rc;
}
Example #10
0
static void s_Dmscp_UnRegister_ServiceCalback(int hnd)
{
	int *p;
	ListNode *node;
	
	HT_DBG_FUNC_START(HT_MOD_DMC, HT_BIT_MANY,(int)hnd, NULL);
	sem_wait(&(s_dmscp_service_updated_lock));
	
	node = ListHead(&s_dmscp_service_updated_list);
	while( node )
	{
		p = (int *)(node->item);
		if( p[1] == hnd )
		{
			ListDelNode(&s_dmscp_service_updated_list, node, 0);
			free(p);
			break;
		}
		node = ListNext(&s_dmscp_service_updated_list, node);
	}
	
	sem_post(&(s_dmscp_service_updated_lock));
	HT_DBG_FUNC_END(hnd, NULL);
}
Example #11
0
/*!
 * \brief Thread job to Notify a control point.
 *
 * It validates the subscription and copies the subscription. Also make sure
 * that events are sent in order.
 *
 * \note calls the genaNotify to do the actual work.
 */
static void genaNotifyThread(
	/*! [in] notify thread structure containing all the headers and property set info. */
	void *input)
{
	subscription *sub;
	service_info *service;
	subscription sub_copy;
	notify_thread_struct *in = (notify_thread_struct *) input;
	int return_code;
	struct Handle_Info *handle_info;

	/* This should be a HandleLock and not a HandleReadLock otherwise if there
	 * is a lot of notifications, then multiple threads will acquire a read
	 * lock and the thread which sends the notification will be blocked forever
	 * on the HandleLock at the end of this function. */
	/*HandleReadLock(); */
	HandleLock();
	/* validate context */

	if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}

	if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) ||
	    !service->active ||
	    !(sub = GetSubscriptionSID(in->sid, service)) ||
	    copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}

	HandleUnlock();

	/* send the notify */
	return_code = genaNotify(in->headers, in->propertySet, &sub_copy);
	freeSubscription(&sub_copy);
	HandleLock();
	if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}
	/* validate context */
	if (!(service = FindServiceId(&handle_info->ServiceTable, in->servId, in->UDN)) ||
	    !service->active ||
	    !(sub = GetSubscriptionSID(in->sid, service))) {
		free_notify_struct(in);
		HandleUnlock();
		return;
	}
	sub->ToSendEventKey++;
	if (sub->ToSendEventKey < 0)
		/* wrap to 1 for overflow */
		sub->ToSendEventKey = 1;

	/* Remove head of event queue. Possibly activate next */
	{
		ListNode *node = ListHead(&sub->outgoing);
		if (node)
			ListDelNode(&sub->outgoing, node, 1);
		if (ListSize(&sub->outgoing) > 0) {
			ThreadPoolJob *job;
			ListNode *node = ListHead(&sub->outgoing);
			job = (ThreadPoolJob*)node->item;
			/* The new head of queue should not have already been
			   added to the pool, else something is very wrong */
			assert(job->jobId != STALE_JOBID);

			ThreadPoolAdd(&gSendThreadPool, job, NULL);
			job->jobId = STALE_JOBID;
		}
	}

	if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB)
		RemoveSubscriptionSID(in->sid, service);
	free_notify_struct(in);

	HandleUnlock();
}
Example #12
0
/****************************************************************************
 * 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 );
        }

    }
}
Example #13
0
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;
}
Example #14
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;
}
Example #15
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 );
	}
}
Example #16
0
/****************************************************************************
 * Function: ThreadPoolRemove
 *
 *  Description:
 *      Removes a job from the thread pool.
 *      Can only remove jobs which are not
 *      currently running.
 *  Parameters:
 *      tp - valid thread pool pointer
 *      jobId - id of job
 *      ThreadPoolJob *out - space for removed job.
 *                           Can be null if not needed.
 *
 *  Returns:
 *      0 on success. INVALID_JOB_ID on failure.
 *****************************************************************************/
int ThreadPoolRemove( ThreadPool *tp, int jobId, ThreadPoolJob *out )
{
	ThreadPoolJob *temp = NULL;
	int ret = INVALID_JOB_ID;
	ListNode *tempNode = NULL;
	ThreadPoolJob dummy;

	assert( tp != NULL );
	if( tp == NULL ) {
		return EINVAL;
	}

	if( out == NULL ) {
		out = &dummy;
	}

	dummy.jobId = jobId;

	ithread_mutex_lock( &tp->mutex );

	tempNode = ListFind( &tp->highJobQ, NULL, &dummy );
	if( tempNode ) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode( &tp->highJobQ, tempNode, 0 );
		FreeThreadPoolJob( tp, temp );
		ithread_mutex_unlock( &tp->mutex );

		return 0;
	}

	tempNode = ListFind( &tp->medJobQ, NULL, &dummy );
	if( tempNode ) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode( &tp->medJobQ, tempNode, 0 );
		FreeThreadPoolJob( tp, temp );
		ithread_mutex_unlock( &tp->mutex );

		return 0;
	}

	tempNode = ListFind( &tp->lowJobQ, NULL, &dummy );
	if( tempNode ) {
		temp = (ThreadPoolJob *)tempNode->item;
		*out = *temp;
		ListDelNode( &tp->lowJobQ, tempNode, 0 );
		FreeThreadPoolJob( tp, temp );
		ithread_mutex_unlock( &tp->mutex );

		return 0;
	}

	if( tp->persistentJob && tp->persistentJob->jobId == jobId ) {
		*out = *tp->persistentJob;
		FreeThreadPoolJob( tp, tp->persistentJob );
		tp->persistentJob = NULL;
		ithread_mutex_unlock( &tp->mutex );

		return 0;
	}

	ithread_mutex_unlock( &tp->mutex );

	return ret;
}