Example #1
0
static
NTSTATUS
WorkLoop(
    PLW_WORK_THREAD pThread
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    PRING pRing = NULL;
    PLW_WORK_ITEM pItem = NULL;
    PLW_WORK_THREADS pThreads = pThread->pThreads;

    LOCK_THREADS(pThread->pThreads);

    for(;;)
    {
        pThreads->ulAvailable++;

        status = WorkWait(pThread);
        GOTO_ERROR_ON_STATUS(status);

        RingDequeue(&pThreads->WorkItems, &pRing);
        pThreads->ulQueued--;
        pThreads->ulAvailable--;

        UNLOCK_THREADS(pThreads);

        pItem = LW_STRUCT_FROM_FIELD(pRing, LW_WORK_ITEM, Ring);
        pItem->pfnFunc(pItem, pItem->pContext);

        LOCK_THREADS(pThreads);
    }

error:

    pThreads->ulAvailable--;
    pThreads->ulStarted--;
    pThread->bStarted = FALSE;

    /* If the thread pool is not being shut down, nothing is
       going to call pthread_join() on this thread, so call
       pthread_detach() now */
    if (!pThreads->bShutdown)
    {
        pthread_detach(pThread->Thread);
        pThread->Thread = INVALID_THREAD_HANDLE;
    }

    UNLOCK_THREADS(pThreads);

    return status;
}
Example #2
0
VOID
DestroyWorkThreads(
    PLW_WORK_THREADS pThreads
    )
{
    size_t i = 0;

    if (pThreads->pWorkThreads)
    {
        WaitWorkItems(pThreads);

        LOCK_THREADS(pThreads);
        pThreads->bShutdown = TRUE;
        pthread_cond_broadcast(&pThreads->Event);
        
        for (i = 0; i < pThreads->ulWorkThreadCount; i++)
        {
            if (pThreads->pWorkThreads[i].Thread != INVALID_THREAD_HANDLE)
            {
                /* We must pthread_join() outside of the lock */
                UNLOCK_THREADS(pThreads);
                pthread_join(pThreads->pWorkThreads[i].Thread, NULL);
                LOCK_THREADS(pThreads);
            }
        }
        UNLOCK_THREADS(pThreads);

        RtlMemoryFree(pThreads->pWorkThreads);
    }

    if (pThreads->bDestroyLock)
    {        
        pthread_mutex_destroy(&pThreads->Lock);
    }

    if (pThreads->bDestroyEvent)
    {
        pthread_cond_destroy(&pThreads->Event);
    }
}
Example #3
0
VOID
WaitWorkItems(
    PLW_WORK_THREADS pThreads
    )
{
    LOCK_THREADS(pThreads);

    pThreads->bWaiting = TRUE;

    while (pThreads->ulWorkItemCount)
    {
        pthread_cond_wait(&pThreads->Event, &pThreads->Lock);
    }

    pThreads->bWaiting = FALSE;

    UNLOCK_THREADS(pThreads);
}
Example #4
0
VOID
FreeWorkItem(
    LW_IN LW_OUT PLW_WORK_ITEM* ppWorkItem
    )
{
    if (*ppWorkItem)
    {
        LOCK_THREADS((*ppWorkItem)->pThreads);
        (*ppWorkItem)->pThreads->ulWorkItemCount--;
        if ((*ppWorkItem)->pThreads->bWaiting ||
            ((*ppWorkItem)->pThreads->ulWorkItemCount == 0 &&
            (*ppWorkItem)->pThreads->ulStarted == 0))
        {
            pthread_cond_broadcast(&(*ppWorkItem)->pThreads->Event);
        }
        UNLOCK_THREADS((*ppWorkItem)->pThreads);
    }

    RTL_FREE(ppWorkItem);
}
Example #5
0
NTSTATUS
CreateWorkItem(
    LW_IN PLW_WORK_THREADS pThreads,
    LW_OUT PLW_WORK_ITEM* ppWorkItem,
    LW_WORK_ITEM_FUNCTION pfnFunc,
    PVOID pContext
    )
{
    PLW_WORK_ITEM pItem = NULL;
    NTSTATUS status = STATUS_SUCCESS;

    LOCK_THREADS(pThreads);

    if (pThreads->ulStarted == 0)
    {
        /* Make sure at least one thread is running */
        status = StartWorkThread(pThreads, &pThreads->pWorkThreads[0]);
        GOTO_ERROR_ON_STATUS(status);
    }

    status = LW_RTL_ALLOCATE_AUTO(&pItem);
    GOTO_ERROR_ON_STATUS(status);

    RingInit(&pItem->Ring);
    pItem->pThreads = pThreads;
    pItem->pfnFunc = pfnFunc;
    pItem->pContext = pContext;

    pThreads->ulWorkItemCount++;

error:

    UNLOCK_THREADS(pThreads);

    *ppWorkItem = pItem;

    return status;
}
Example #6
0
VOID
ScheduleWorkItem(
    PLW_WORK_THREADS pThreads,
    PLW_WORK_ITEM pItem,
    LW_SCHEDULE_FLAGS Flags
    )
{
    size_t i = 0;

    if (pThreads == NULL)
    {
        pThreads = pItem->pThreads;
    }

    LOCK_THREADS(pThreads);
    
    assert(pThreads->ulStarted > 0);

    /* Enqueue work item */
    if (Flags & LW_SCHEDULE_HIGH_PRIORITY)
    {
        RingEnqueueFront(&pThreads->WorkItems, &pItem->Ring);
    }
    else
    {
        RingEnqueue(&pThreads->WorkItems, &pItem->Ring);
    }

    pThreads->ulQueued++;

    /*
     * If there are more pending work items than there
     * are available threads, and not all threads are started,
     * try to start another one to handle the additional load
     */
    if (pThreads->ulAvailable < pThreads->ulQueued &&
        pThreads->ulStarted < pThreads->ulWorkThreadCount)
    {
        for (i = 0; i < pThreads->ulWorkThreadCount; i++)
        {
            if (!pThreads->pWorkThreads[i].bStarted)
            {
                if (StartWorkThread(pThreads, &pThreads->pWorkThreads[i]) != STATUS_SUCCESS)
                {
                    LW_RTL_LOG_WARNING("Could not start work item thread");
                    /* Signal an existing thread instead */
                    pthread_cond_signal(&pThreads->Event);
                }
                break;
            }
        }
    }
    else if (pThreads->ulAvailable)
    {
        /* Signal an existing thread */
        pthread_cond_signal(&pThreads->Event);
    }


    UNLOCK_THREADS(pThreads);
}