/******************************************************************************* * * Copyright (c) 2000-2003 Intel Corporation * All rights reserved. * Copyright (c) 2012 France Telecom All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ #ifndef THREADPOOL_H #define THREADPOOL_H /*! * \file */ #include "FreeList.h" #include "ithread.h" #include "LinkedList.h" #include "UpnpInet.h" #include "UpnpGlobal.h" /* for UPNP_INLINE, EXPORT_SPEC */ #include #ifdef WIN32 #include struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz); #else /* WIN32 */ #include #include /* for gettimeofday() */ #if defined(__OSX__) || defined(__APPLE__) || defined(__NetBSD__) #include /* for setpriority() */ #endif #endif #ifdef __cplusplus extern "C" { #endif /*! Size of job free list */ #define JOBFREELISTSIZE 100 #define INFINITE_THREADS -1 #define EMAXTHREADS (-8 & 1<<29) /*! Invalid Policy */ #define INVALID_POLICY (-9 & 1<<29) /*! Invalid JOB Id */ #define INVALID_JOB_ID (-2 & 1<<29) typedef enum duration { SHORT_TERM, PERSISTENT } Duration; typedef enum priority { LOW_PRIORITY, MED_PRIORITY, HIGH_PRIORITY } ThreadPriority; /*! default priority used by TPJobInit */ #define DEFAULT_PRIORITY MED_PRIORITY /*! default minimum used by TPAttrInit */ #define DEFAULT_MIN_THREADS 1 /*! default max used by TPAttrInit */ #define DEFAULT_MAX_THREADS 10 /*! default stack size used by TPAttrInit */ #define DEFAULT_STACK_SIZE 0u /*! default jobs per thread used by TPAttrInit */ #define DEFAULT_JOBS_PER_THREAD 10 /*! default starvation time used by TPAttrInit */ #define DEFAULT_STARVATION_TIME 500 /*! default idle time used by TPAttrInit */ #define DEFAULT_IDLE_TIME 10 * 1000 /*! default free routine used TPJobInit */ #define DEFAULT_FREE_ROUTINE NULL /*! default max jobs used TPAttrInit */ #define DEFAULT_MAX_JOBS_TOTAL 100 /*! * \brief Statistics. * * Always include stats because code change is minimal. */ #define STATS 1 #ifdef _DEBUG #define DEBUG 1 #endif typedef int PolicyType; #define DEFAULT_POLICY SCHED_OTHER /*! Function for freeing a thread argument. */ typedef void (*free_routine)(void *arg); /*! Attributes for thread pool. Used to set and change parameters of thread * pool. */ typedef struct THREADPOOLATTR { /*! ThreadPool will always maintain at least this many threads. */ int minThreads; /*! ThreadPool will never have more than this number of threads. */ int maxThreads; /*! This is the minimum stack size allocated for each thread. */ size_t stackSize; /*! This is the maximum time a thread will * remain idle before dying (in milliseconds). */ int maxIdleTime; /*! Jobs per thread to maintain. */ int jobsPerThread; /*! Maximum number of jobs that can be queued totally. */ int maxJobsTotal; /*! the time a low priority or med priority job waits before getting * bumped up a priority (in milliseconds). */ int starvationTime; /*! scheduling policy to use. */ PolicyType schedPolicy; } ThreadPoolAttr; /*! Internal ThreadPool Job. */ typedef struct THREADPOOLJOB { start_routine func; void *arg; free_routine free_func; struct timeval requestTime; ThreadPriority priority; int jobId; } ThreadPoolJob; /*! Structure to hold statistics. */ typedef struct TPOOLSTATS { double totalTimeHQ; int totalJobsHQ; double avgWaitHQ; double totalTimeMQ; int totalJobsMQ; double avgWaitMQ; double totalTimeLQ; int totalJobsLQ; double avgWaitLQ; double totalWorkTime; double totalIdleTime; int workerThreads; int idleThreads; int persistentThreads; int totalThreads; int maxThreads; int currentJobsHQ; int currentJobsLQ; int currentJobsMQ; } ThreadPoolStats; /*! * \brief A thread pool similar to the thread pool in the UPnP SDK. * * Allows jobs to be scheduled for running by threads in a * thread pool. The thread pool is initialized with a * minimum and maximum thread number as well as a max idle time * and a jobs per thread ratio. If a worker thread waits the whole * max idle time without receiving a job and the thread pool * currently has more threads running than the minimum * then the worker thread will exit. If when * scheduling a job the current job to thread ratio * becomes greater than the set ratio and the thread pool currently has * less than the maximum threads then a new thread will * be created. */ typedef struct THREADPOOL { /*! Mutex to protect job qs. */ ithread_mutex_t mutex; /*! Condition variable to signal Q. */ ithread_cond_t condition; /*! Condition variable for start and stop. */ ithread_cond_t start_and_shutdown; /*! ids for jobs */ int lastJobId; /*! whether or not we are shutting down */ int shutdown; /*! total number of threads */ int totalThreads; /*! flag that's set when waiting for a new worker thread to start */ int pendingWorkerThreadStart; /*! number of threads that are currently executing jobs */ int busyThreads; /*! number of persistent threads */ int persistentThreads; /*! free list of jobs */ FreeList jobFreeList; /*! low priority job Q */ LinkedList lowJobQ; /*! med priority job Q */ LinkedList medJobQ; /*! high priority job Q */ LinkedList highJobQ; /*! persistent job */ ThreadPoolJob *persistentJob; /*! thread pool attributes */ ThreadPoolAttr attr; /*! statistics */ ThreadPoolStats stats; } ThreadPool; /*! * \brief Initializes and starts ThreadPool. Must be called first and * only once for ThreadPool. * * \return * \li \c 0 on success. * \li \c EAGAIN if not enough system resources to create minimum threads. * \li \c INVALID_POLICY if schedPolicy can't be set. * \li \c EMAXTHREADS if minimum threads is greater than maximum threads. */ int ThreadPoolInit( /*! Must be valid, non null, pointer to ThreadPool. */ ThreadPool *tp, /*! Can be null. if not null then attr contains the following fields: * \li \c minWorkerThreads - minimum number of worker threads thread * pool will never have less than this number of threads. * \li \c maxWorkerThreads - maximum number of worker threads thread * pool will never have more than this number of threads. * \li \c 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, then the worker thread * exits. * \li \c 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. * \li \c schedPolicy - scheduling policy to try and set (OS dependent). */ ThreadPoolAttr *attr); /*! * \brief Adds a persistent job to the thread pool. * * Job will be run as soon as possible. Call will block until job is scheduled. * * \return * \li \c 0 on success. * \li \c EOUTOFMEM not enough memory to add job. * \li \c EMAXTHREADS not enough threads to add persistent job. */ int ThreadPoolAddPersistent( /*! Valid thread pool pointer. */ ThreadPool*tp, /*! Valid thread pool job. */ ThreadPoolJob *job, /*! . */ int *jobId); /*! * \brief Gets the current set of attributes associated with the thread pool. * * \return * \li \c 0 on success, nonzero on failure. */ int ThreadPoolGetAttr( /*! valid thread pool pointer. */ ThreadPool *tp, /*! non null pointer to store attributes. */ ThreadPoolAttr *out); /*! * \brief Sets the attributes for the thread pool. * Only affects future calculations. * * \return * \li \c 0 on success, nonzero on failure. * \li \c INVALID_POLICY if policy can not be set. */ int ThreadPoolSetAttr( /*! valid thread pool pointer. */ ThreadPool *tp, /*! pointer to attributes, null sets attributes to default. */ ThreadPoolAttr *attr); /*! * \brief Adds a job to the thread pool. Job will be run as soon as possible. * * \return * \li \c 0 on success, nonzero on failure. * \li \c EOUTOFMEM if not enough memory to add job. */ int ThreadPoolAdd( /*! valid thread pool pointer. */ ThreadPool*tp, /*! . */ ThreadPoolJob *job, /*! id of job. */ int *jobId); /*! * \brief Removes a job from the thread pool. Can only remove jobs which * are not currently running. * * \return * \li \c 0 on success, nonzero on failure. * \li \c INVALID_JOB_ID if job not found. */ int ThreadPoolRemove( /*! valid thread pool pointer. */ ThreadPool *tp, /*! id of job. */ int jobId, /*! space for removed job. */ ThreadPoolJob *out); /*! * \brief Shuts the thread pool down. Waits for all threads to finish. * May block indefinitely if jobs do not exit. * * \return 0 on success, nonzero on failure */ int ThreadPoolShutdown( /*! must be valid tp. */ ThreadPool *tp); /*! * \brief Initializes thread pool job. Sets the priority to default defined * in ThreadPool.h. Sets the free_routine to default defined in ThreadPool.h. * * \return Always returns 0. */ int TPJobInit( /*! must be valid thread pool attributes. */ ThreadPoolJob *job, /*! function to run, must be valid. */ start_routine func, /*! argument to pass to function. */ void *arg); /*! * \brief Sets the max threads for the thread pool attributes. * * \return Always returns 0. */ int TPJobSetPriority( /*! must be valid thread pool attributes. */ ThreadPoolJob *job, /*! value to set. */ ThreadPriority priority); /*! * \brief Sets the max threads for the thread pool attributes. * * \return Always returns 0. */ int TPJobSetFreeFunction( /*! must be valid thread pool attributes. */ ThreadPoolJob *job, /*! value to set. */ free_routine func); /*! * \brief Initializes thread pool attributes. Sets values to defaults defined * in ThreadPool.h. * * \return Always returns 0. */ int TPAttrInit( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr); /*! * \brief Sets the max threads for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetMaxThreads( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! value to set. */ int maxThreads); /*! * \brief Sets the min threads for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetMinThreads( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! value to set. */ int minThreads); /*! * \brief Sets the stack size for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetStackSize( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! value to set. */ size_t stackSize); /*! * \brief Sets the idle time for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetIdleTime( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! . */ int idleTime); /*! * \brief Sets the jobs per thread ratio * * \return Always returns 0. */ int TPAttrSetJobsPerThread( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! number of jobs per thread to maintain. */ int jobsPerThread); /*! * \brief Sets the starvation time for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetStarvationTime( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! milliseconds. */ int starvationTime); /*! * \brief Sets the scheduling policy for the thread pool attributes. * * \return Always returns 0. */ int TPAttrSetSchedPolicy( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! must be a valid policy type. */ PolicyType schedPolicy); /*! * \brief Sets the maximum number jobs that can be qeued totally. * * \return Always returns 0. */ int TPAttrSetMaxJobsTotal( /*! must be valid thread pool attributes. */ ThreadPoolAttr *attr, /*! maximum number of jobs. */ int maxJobsTotal); /*! * \brief Returns various statistics about the thread pool. * * Only valid if STATS has been defined. * * \return Always returns 0. */ #ifdef STATS EXPORT_SPEC int ThreadPoolGetStats( /*! Valid initialized threadpool. */ ThreadPool *tp, /*! Valid stats, out parameter. */ ThreadPoolStats *stats); #else static UPNP_INLINE int ThreadPoolGetStats( /*! Valid initialized threadpool. */ ThreadPool *tp, /*! Valid stats, out parameter. */ ThreadPoolStats *stats) {} #endif /*! * \brief */ #ifdef STATS EXPORT_SPEC void ThreadPoolPrintStats( /*! . */ ThreadPoolStats *stats); #else static UPNP_INLINE void ThreadPoolPrintStats( /*! . */ ThreadPoolStats *stats) {} #endif #ifdef __cplusplus } #endif #endif /* THREADPOOL_H */