reqpool.cpp revision c999f225d03074008a0c21cdd5d3594da476e243
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/* $Id$ */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/** @file
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * IPRT - Request Pool.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Copyright (C) 2006-2011 Oracle Corporation
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync *
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * available from http://www.virtualbox.org. This file is free software;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * you can redistribute it and/or modify it under the terms of the GNU
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * General Public License (GPL) as published by the Free Software
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync *
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * The contents of this file may alternatively be used under the terms
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * of the Common Development and Distribution License Version 1.0
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * VirtualBox OSE distribution, in which case the provisions of the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * CDDL are applicable instead of those of the GPL.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync *
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * You may elect to license modified versions of this file under the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * terms and conditions of either the GPL or the CDDL or both.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/*******************************************************************************
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync* Header Files *
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync*******************************************************************************/
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/req.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include "internal/iprt.h"
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/assert.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/asm.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/critsect.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/list.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/log.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/mem.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/string.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/time.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/semaphore.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include <iprt/thread.h>
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include "internal/req.h"
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync#include "internal/magics.h"
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/*******************************************************************************
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync* Structures and Typedefs *
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync*******************************************************************************/
316572fd6bf59ec1038f0476f6536fc10163beebvboxsynctypedef struct RTREQPOOLTHREAD
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Node in the RTREQPOOLINT::IdleThreads list. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTLISTNODE IdleNode;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Node in the RTREQPOOLINT::WorkerThreads list. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTLISTNODE ListNode;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The submit timestamp of the pending request. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t uPendingNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The submit timestamp of the request processing. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t uProcessingNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** When this CPU went idle the last time. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t uIdleNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The number of requests processed by this thread. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t cReqProcessed;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Total time the requests processed by this thread took to process. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t cNsTotalReqProcessing;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Total time the requests processed by this thread had to wait in
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * the queue before being scheduled. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t cNsTotalReqQueued;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The CPU this was scheduled last time we checked. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCPUID idLastCpu;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The submitter will put an incoming request here when scheduling an idle
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * thread. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQINT volatile pTodoReq;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The request the thread is currently processing. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQINT volatile pPendingReq;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The thread handle. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTTHREAD hThread;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Nano seconds timestamp representing the birth time of the thread. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t uBirthNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Pointer to the request thread pool instance the thread is associated
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * with. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync struct RTREQPOOLINT *pPool;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync} RTREQPOOLTHREAD;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/** Pointer to a worker thread. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsynctypedef RTREQPOOLTHREAD *PRTREQPOOLTHREAD;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/**
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Request thread pool instance data.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsynctypedef struct RTREQPOOLINT
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Magic value (RTREQPOOL_MAGIC). */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t u32Magic;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The worker thread type. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTTHREADTYPE enmThreadType;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The current number of worker threads. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cCurThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The maximum number of worker threads. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMaxThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The number of threads which should be spawned before throttling kicks
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * in. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cThreadsThreshold;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The minimum number of worker threads. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMinThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The number of milliseconds a thread needs to be idle before it is
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * considered for retirement. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMsMinIdle;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The max number of milliseconds to push back a submitter before creating
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * a new worker thread once the threshold has been reached. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMsMaxPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The minimum number of milliseconds to push back a submitter before
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * creating a new worker thread once the threshold has been reached. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMsMinPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The current submitter push back in milliseconds.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * This is recalculated when worker threads come and go. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMsCurPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Statistics: The total number of threads created. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cThreadsCreated;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Statistics: The timestamp when the last thread was created. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t uLastThreadCreateNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Linked list of worker threads. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTLISTANCHOR WorkerThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Event semaphore that submitters block on when pushing back . */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTSEMEVENT hPushBackEvt;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Critical section serializing access to members of this structure. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCRITSECT CritSect;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Destruction indicator. The worker threads checks in their loop. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync bool volatile fDestructing;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Reference counter. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t volatile cRefs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Number of threads pushing back. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t volatile cPushingBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** The number of idle thread or threads in the process of becoming
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * idle. This is increased before the to-be-idle thread tries to enter
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * the critical section and add itself to the list. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t volatile cIdleThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Linked list of idle threads. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTLISTANCHOR IdleThreads;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Head of the request FIFO. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQINT pPendingRequests;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** Where to insert the next request. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQINT *ppPendingRequests;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync} RTREQPOOLINT;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync/** Pointer to a request thread pool instance. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsynctypedef RTREQPOOLINT *PRTREQPOOLINT;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsyncstatic void rtReqPoolRecalcPushBack(PRTREQPOOLINT pPool)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t const cMsRange = pPool->cMsMaxPushBack - pPool->cMsMinPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t const cSteps = pPool->cMaxThreads - pPool->cThreadsThreshold;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t const iStep = pPool->cCurThreads - pPool->cThreadsThreshold;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t cMsCurPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if ((cMsRange >> 2) >= cSteps)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync cMsCurPushBack = cMsRange / cSteps * iStep;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync else
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync cMsCurPushBack = (uint32_t)( (uint64_t)cMsRange * RT_NS_1MS / cSteps * iStep / RT_NS_1MS );
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync cMsCurPushBack += pPool->cMsMinPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cMsCurPushBack = cMsCurPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync}
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsyncstatic void rtReqPoolThreadProcessRequest(PRTREQPOOLTHREAD pThread, PRTREQINT pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Update thread state.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->uProcessingNanoTs = RTTimeNanoTS();
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->uPendingNanoTs = pReq->uSubmitNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->pPendingReq = pReq;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync Assert(pReq->u32Magic == RTREQ_MAGIC);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Do the actual processing.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** @todo */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Update thread statistics and state.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t const uNsTsEnd = RTTimeNanoTS();
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->cNsTotalReqProcessing += uNsTsEnd - pThread->uProcessingNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->cNsTotalReqQueued += uNsTsEnd - pThread->uPendingNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->cReqProcessed++;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync}
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsyncstatic DECLCALLBACK(int) rtReqPoolThreadProc(RTTHREAD hThreadSelf, void *pvArg)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQPOOLTHREAD pThread = (PRTREQPOOLTHREAD)pvArg;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQPOOLINT pPool = pThread->pPool;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * The work loop.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint64_t cPrevReqProcessed = 0;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync while (pPool->fDestructing)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Pending work?
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQINT pReq = ASMAtomicXchgPtrT(&pThread->pTodoReq, NULL, PRTREQINT);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync rtReqPoolThreadProcessRequest(pThread, pReq);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync else
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync ASMAtomicIncU32(&pPool->cIdleThreads);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectEnter(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /* Recheck the todo request pointer after entering the critsect. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pReq = ASMAtomicXchgPtrT(&pThread->pTodoReq, NULL, PRTREQINT);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (!pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /* Any pending requests in the queue? */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pReq = pPool->pPendingRequests;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->pPendingRequests = pReq->pNext;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (pReq->pNext == NULL)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->ppPendingRequests = &pPool->pPendingRequests;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Un-idle ourselves and process the request.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (!RTListIsEmpty(&pThread->IdleNode))
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListNodeRemove(&pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListInit(&pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync ASMAtomicDecU32(&pPool->cIdleThreads);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync rtReqPoolThreadProcessRequest(pThread, pReq);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync else
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Nothing to do, go idle.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (cPrevReqProcessed != pThread->cReqProcessed)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->cReqProcessed = cPrevReqProcessed;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->uIdleNanoTs = RTTimeNanoTS();
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (RTListIsEmpty(&pThread->IdleNode))
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListPrepend(&pPool->IdleThreads, &pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTThreadUserReset(hThreadSelf);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTThreadUserWait(hThreadSelf, 0);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Clean up on the way out.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectEnter(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** @todo .... */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync rtReqPoolRecalcPushBack(pPool);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync return VINF_SUCCESS;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync}
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsyncstatic void rtReqPoolCreateNewWorker(RTREQPOOL pPool)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQPOOLTHREAD pThread = (PRTREQPOOLTHREAD)RTMemAllocZ(sizeof(RTREQPOOLTHREAD));
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (!pThread)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync return;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->uBirthNanoTs = RTTimeNanoTS();
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->pPool = pPool;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->idLastCpu = NIL_RTCPUID;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pThread->hThread = NIL_RTTHREAD;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListInit(&pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListAppend(&pPool->WorkerThreads, &pThread->ListNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cCurThreads++;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cThreadsCreated++;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync static uint32_t s_idThread = 0;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync int rc = RTThreadCreateF(&pThread->hThread, rtReqPoolThreadProc, pThread, 0 /*default stack size*/,
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->enmThreadType, RTTHREADFLAGS_WAITABLE, "REQPT%02u", ++s_idThread);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (RT_SUCCESS(rc))
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->uLastThreadCreateNanoTs = pThread->uBirthNanoTs;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync else
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cCurThreads--;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListNodeRemove(&pThread->ListNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTMemFree(pThread);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync}
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsyncDECLHIDDEN(int) rtReqPoolSubmit(PRTREQPOOLINT pPool, PRTREQINT pReq)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync{
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Prepare the request.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pReq->uSubmitNanoTs = RTTimeNanoTS();
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectEnter(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Try schedule the request to any currently idle thread.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync PRTREQPOOLTHREAD pThread = RTListGetFirst(&pPool->IdleThreads, RTREQPOOLTHREAD, IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (pThread)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** @todo CPU affinity... */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync ASMAtomicWritePtr(&pThread->pTodoReq, pReq);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListNodeRemove(&pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTListInit(&pThread->IdleNode);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync ASMAtomicDecU32(&pPool->cIdleThreads);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTThreadUserSignal(pThread->hThread);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync return VINF_SUCCESS;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync Assert(RTListIsEmpty(&pPool->IdleThreads));
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Put the request in the pending queue.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pReq->pNext = NULL;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync *pPool->ppPendingRequests = pReq;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->ppPendingRequests = (PRTREQINT*)&pReq->pNext;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * If there is an incoming worker thread already or we've reached the
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * maximum number of worker threads, we're done.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if ( pPool->cIdleThreads > 0
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync || pPool->cCurThreads >= pPool->cMaxThreads)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync return VINF_SUCCESS;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Push back before creating a new worker thread.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if ( pPool->cCurThreads > pPool->cThreadsThreshold
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync && (RTTimeNanoTS() - pReq->uSubmitNanoTs) / RT_NS_1MS >= pPool->cMsCurPushBack )
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTSEMEVENTMULTI hEvt = pReq->hPushBackEvt;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (hEvt == NIL_RTSEMEVENTMULTI)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync int rc = RTSemEventMultiCreate(&hEvt);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (RT_SUCCESS(rc))
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pReq->hPushBackEvt = hEvt;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync else
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync hEvt = NIL_RTSEMEVENTMULTI;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync if (hEvt != NIL_RTSEMEVENTMULTI)
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync {
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync uint32_t const cMsTimeout = pPool->cMsCurPushBack;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cPushingBack++;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** @todo this is everything but perfect... it makes wake up order
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * assumptions. A better solution would be having a lazily
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * allocated push back event on each request. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync int rc = RTSemEventWait(pPool->hPushBackEvt, cMsTimeout);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectEnter(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync pPool->cPushingBack--;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /** @todo check if it's still on the list before going on. */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync }
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync /*
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * Create a new thread for processing the request.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync * For simplicity, we don't bother leaving the critical section while doing so.
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync */
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync rtReqPoolCreateNewWorker(pPool);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync RTCritSectLeave(&pPool->CritSect);
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync return VINF_SUCCESS;
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync}
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync
316572fd6bf59ec1038f0476f6536fc10163beebvboxsync