/* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISHTO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * threadpool.h * * Abstract: * * Thread pool API * * Authors: Brian Koropoff (bkoropoff@likewise.com) * */ #ifndef __LWBASE_THREADPOOL_H__ #define __LWBASE_THREADPOOL_H__ #include #include /** * @file threadpool.h * @brief Thread pool API */ /** * @defgroup threadpool Thread pool * @brief Event-triggered task subsystem * * The thread pool API exposes a simple interface for creating * asynchronous tasks that wake up (run) whenever certain trigger * conditions are met, such as a file descriptor becoming readable * or a timeout expiring. The thread pool interface abstracts * away the underlying event polling mechanism and thread * architecture. */ /*@{*/ /** * @brief Thread pool * * An opaque structure representing a particular thread pool. * All tasks and task groups are created within the context of a thread * pool which is responsible for their implementation and lifecycle. */ typedef struct _LW_THREAD_POOL LW_THREAD_POOL, *PLW_THREAD_POOL; /** * @brief Task group * * An opaque structure which represents a group of related tasks. * Task groups allow multiple tasks to be triggered, cancelled, or * waited upon simultaneously */ typedef struct _LW_TASK_GROUP LW_TASK_GROUP, *PLW_TASK_GROUP; /** * @brief Task * * An opaque structure representing a single task. Each task has * an associated #LW_TASK_FUNCTION which is run whenever the * conditions for task wakeup are met. */ typedef struct _LW_TASK LW_TASK, *PLW_TASK; /** * @brief Event mask * * A bitmask representing a set of events. */ typedef enum _LW_TASK_EVENT_MASK { /** * A special value which indicates that * the task is complete when returned by an * #LW_TASK_FUNCTION through the pWaitMask parameter. * * @hideinitializer */ LW_TASK_EVENT_COMPLETE = 0x00, /** * A special bit which indicates that a task has been * run for the first time when passed as WakeMask * parameter to an #LW_TASK_FUNCTION * * @hideinitializer */ LW_TASK_EVENT_INIT = 0x01, /** * Indicates that the task was explicitly woken by * an external caller, such as through #LwRtlWakeTask() * or #LwRtlCancelTask() * * @hideinitializer */ LW_TASK_EVENT_EXPLICIT = 0x02, /** * Indicates that the task has been cancelled. * Once cancelled, this bit will continue to be set * on the WakeMask parameter of the #LW_TASK_FUNCTION * for all subsequent wakeups until the task completes. * * @hideinitializer */ LW_TASK_EVENT_CANCEL = 0x04, /** * Indicates that the last set timeout has expired. * * @hideinitializer */ LW_TASK_EVENT_TIME = 0x08, /** * Indicates that a file descriptor has become readable. * * @hideinitializer */ LW_TASK_EVENT_FD_READABLE = 0x10, /** * Indicates that a file descriptor has become writable. * * @hideinitializer */ LW_TASK_EVENT_FD_WRITABLE = 0x20, /** * Indicates that an exception event occurred on a file * descriptor. * * @hideinitializer */ LW_TASK_EVENT_FD_EXCEPTION = 0x40, /** * Indicates that the task should be immediately run * again after other tasks have had a chance to run. * * @hideinitializer */ LW_TASK_EVENT_YIELD = 0x80 } LW_TASK_EVENT_MASK, *PLW_TASK_EVENT_MASK; /** * @brief Work item flags * * Controls how work items are run. */ typedef enum LW_WORK_ITEM_FLAGS { /** * Indicates that a work item should be * given its own dedicated thread in which to * run. */ LW_WORK_ITEM_DEDICATED = 0x00 } LW_WORK_ITEM_FLAGS; /** * @brief Main task function * * A function which is run whenever the trigger conditions of * a task are met. Before returning, the function should set * the pWaitMask parameter to the mask of conditions under * which it should next wake up, and the pllTime parameter to the * next timeout. Setting an empty mask indicates that * the task is complete and should no longer be scheduled * to run. * * If a non-zero time is set and the task is woken before * the time expires, on the next call to the function the pllTime * parameter will contain how much time was remaining. Note that * the time parameter will be updated in this manner even if * #LW_TASK_EVENT_TIME is not one of the trigger conditions. * Once the time reaches 0, it will not decrease further. * * Several trigger flags have special significance: * * - #LW_TASK_EVENT_INIT
* This flag is always set on the first wakeup and never on * subsequent wakeups. * * - #LW_TASK_EVENT_EXPLICIT
* Explicit wakeups always take effect, even if #LW_TASK_EVENT_EXPLICIT * was not set in the wait mask. It is still useful to set this flag in * the wait mask if the task wishes to wait only for explicit wakeups. * * - #LW_TASK_EVENT_CANCEL
* Once a task is cancelled, this flag will always be set on * every subsequent wakeup until the task completes. * * - #LW_TASK_EVENT_YIELD
* If this flag is set in the wait mask, it indicates that the task is * not yet finished doing work but is yielding to allow other tasks * to run. When the task is run again, the wake mask will contain * #LW_TASK_EVENT_YIELD and all other bits that were set in the wait * mask, modulo the special flags above. Additional events may occur * during a yield and will be added to the wake mask. * * - #LW_TASK_EVENT_COMPLETE
* If the wait mask is set to this value, the task will be considered * complete and will no longer run. Callers waiting in #LwRtlWaitTask * and related functions will be unblocked. * * @param[in] pTask the task * @param[in] pContex user context pointer * @param[in] WakeMask the mask of trigger conditions which woke the task * @param[in, out] pWaitMask the mask of trigger conditions to wait for * before the next wakeup * @param[in,out] pllTime the time remaining until the next timeout */ typedef LW_VOID (*LW_TASK_FUNCTION)( LW_IN PLW_TASK pTask, LW_IN LW_PVOID pContext, LW_IN LW_TASK_EVENT_MASK WakeMask, LW_IN LW_OUT LW_TASK_EVENT_MASK* pWaitMask, LW_IN LW_OUT LW_LONG64* pllTime ); /** * @brief Work item function * * A function which is queued and dispatched by * #LwRtlQueueWorkItem(). Unlike tasks, work item * functions are synchronous and may block. * * @param[in] pContext the user context pointer */ typedef LW_VOID (*LW_WORK_ITEM_FUNCTION)( LW_PVOID pContext ); /** * @brief Create a new task * * Creates a new task with the specified thread pool within * the specified group. The task will be immediately ready to * run but will not be woken until an explicit trigger is caused * by #LwRtlWakeTask() or similar. On first wakeup, the * #LW_TASK_EVENT_INIT bit will be set on pMask parameter * to the #LW_TASK_FUNCTION. * * When the task is no longer referenced externally (outside of * the #LW_TASK_FUNCTION itself), it should be released with * #LwRtlReleaseTask(). The task will not be completely freed * until it has been released and the #LW_TASK_FUNCTION has * indicated completion by setting an empty wake mask. * * @param[in] pPool the thread pool * @param[out] ppTask the created task * @param[in] pGroup an optional task group for the task * @param[in] pfnFunc the task wakeup function * @param[in] pData the user context pointer passed to pfnFunc * @retval #LW_STATUS_SUCCESS success * @retval #LW_INSUFFICIENT_RESOURCES out of memory */ LW_NTSTATUS LwRtlCreateTask( LW_IN PLW_THREAD_POOL pPool, LW_OUT PLW_TASK* ppTask, LW_IN LW_OPTIONAL PLW_TASK_GROUP pGroup, LW_IN LW_TASK_FUNCTION pfnFunc, LW_IN LW_PVOID pContext ); /** * @brief Create a new task group * * Creates a new task group. Whenever tasks are created, they may optionally * be assigned to a task group. All tasks in a group can be conveniently * woken, cancelled, or waited upon simultaneously. * * @param[in] pPool the thread pool * @param[out] ppGroup the created task * @retval #LW_STATUS_SUCCESS success * @retval #LW_INSUFFICIENT_RESOURCES out of memory */ LW_NTSTATUS LwRtlCreateTaskGroup( LW_IN PLW_THREAD_POOL pPool, LW_OUT PLW_TASK_GROUP* ppGroup ); /** * @brief Release task * * Indicates that the given task will no longer be externally referenced * (i.e. outside of its own #LW_TASK_FUNCTION). This function may safely * be called with *ppTask equal to NULL. It sets *ppTask to NULL if it * was not already. * * @param[in,out] ppTask a pointer to the task pointer to release */ LW_VOID LwRtlReleaseTask( LW_IN LW_OUT PLW_TASK* ppTask ); /** * @brief Free task group * * Deletes the given task group. This function may safely be called * with *ppGroup equal to NULL. It sets *ppGroup to NULL if it was not already. * * @warning The results of calling this function * are undefined if incomplete tasks still remain inside the group. * To be safe, first call #LwRtlCancelTaskGroup() and #LwRtlWaitTaskGroup() * to ensure that all tasks in the group have completed. * * @param[in,out] ppGroup a pointer to the group pointer to free */ LW_VOID LwRtlFreeTaskGroup( LW_IN LW_OUT PLW_TASK_GROUP* ppGroup ); /** * @brief Configure file descriptor for wakeup events * * Configures a file descriptor for subsequent wakeup events. * A file descriptor remains configured until it is explictly * unconfigured by calling this function with an empty trigger mask. * A wakeup on a given file descriptor trigger condition (e.g. * LW_TASK_EVENT_FD_READ) will occur only when the condition is * set both on the mask passed to this function and in the mask * specified when the #LW_TASK_FUNCTION returns. * * @warning The result of calling this function from outside of an * #LW_TASK_FUNCTION is undefined. * * @param[in] pTask the task * @param[in] Fd the file descriptor * @param[in] Mask the mask of trigger conditions which for which * wakeups will be generated for the given descriptor * @retval #LW_STATUS_SUCCESS success * @retval #LW_STATUS_INSUFFICIENT_RESOURCES out of memory * @retval #LW_STATUS_INVALID_HANDLE the provided fd was invalid */ LW_NTSTATUS LwRtlSetTaskFd( LW_IN PLW_TASK pTask, LW_IN int Fd, LW_IN LW_TASK_EVENT_MASK Mask ); /** * @brief Query file descriptor trigger mask * * Queries for the most recent mask of trigger conditions which * are set for the given file descriptor. * * @warning The result of calling this function from outside of an * #LW_TASK_FUNCTION is undefined. * * @param[in] pTask the task * @param[in] Fd the file descriptor * @param[out] pMask the mask of trigger conditions which were true * for the given fd on this wakeup * @retval #LW_STATUS_SUCCESS success * @retval #LW_STATUS_INVALID_HANDLE the provided fd was invalid or * was not previously set on the given task */ LW_NTSTATUS LwRtlQueryTaskFd( LW_IN PLW_TASK pTask, LW_IN int Fd, LW_OUT PLW_TASK_EVENT_MASK pMask ); /** * @brief Manually wake task * * Causes the specified task to wake up immediately with the * #LW_TASK_EVENT_EXPLICIT flag set. * * @param[in] pTask the task */ LW_VOID LwRtlWakeTask( LW_IN PLW_TASK pTask ); /** * @brief Cancel task * * Cancels the specified task. In addition to having the same * immediate effects as #LwRtlWakeTask(), the #LW_TASK_EVENT_CANCEL * flag will be set on all task wakeups until the task completes. * * @param[in] pTask the task */ LW_VOID LwRtlCancelTask( LW_IN PLW_TASK pTask ); /** * @brief Wait for task completion * * Waits for the specified task to complete by indicating an empty * wakeup trigger mask. * * @param[in] pTask the task */ LW_VOID LwRtlWaitTask( LW_IN PLW_TASK pTask ); /** * @brief Wake task group * * Equivalent to calling #LwRtlWakeTask() on all tasks in the * given task group. * * @param[in] pGroup the task group */ LW_VOID LwRtlWakeTaskGroup( LW_IN PLW_TASK_GROUP pGroup ); /** * @brief Cancel task group * * Equivalent to calling #LwRtlCancelTask() on all tasks in the * given task group. * * @param[in] pGroup the task group */ LW_VOID LwRtlCancelTaskGroup( LW_IN PLW_TASK_GROUP pGroup ); /** * @brief Wait for task group to complete * * Equivalent to calling #LwRtlWaitTask() on all tasks in the * given task group. * * @param[in] pGroup the task group */ LW_VOID LwRtlWaitTaskGroup( LW_IN PLW_TASK_GROUP pGroup ); /** * @brief Queue synchronous work item * * Schedules a work item to be run in another thread. Unlike tasks, * work items are not asynchronous and may block arbitrarily. This * functionality is provided as a convenience for tasks which may need * to make calls into blocking code. * * @param[in] pPool the thread pool * @param[in] pfnFunc a work item function to run * @param[in] pContext the user context pointer to pass to the work item function * @param[in] Flags control flags for the work item */ LW_NTSTATUS LwRtlQueueWorkItem( LW_IN PLW_THREAD_POOL pPool, LW_IN LW_WORK_ITEM_FUNCTION pfnFunc, LW_IN LW_PVOID pContext, LW_IN LW_WORK_ITEM_FLAGS Flags ); /** * @brief Create new thread pool * * Creates a new thread pool. * * @param[out] ppPool the created pool * @retval #LW_STATUS_SUCCESS success * @retval #LW_STATUS_INSUFFICIENT_RESOURCES out of memory */ LW_NTSTATUS LwRtlCreateThreadPool( LW_OUT PLW_THREAD_POOL* ppPool ); /** * @brief Free thread pool * * Frees the given thread pool. It is safe for *ppPool * to be NULL. This function will set *ppPool to NULL if * it was not already. * * @param[in,out] ppPool a pointer to the thread pool pointer */ LW_VOID LwRtlFreeThreadPool( LW_IN LW_OUT PLW_THREAD_POOL* ppPool ); /*@}*/ #endif /* __LWBASE_THREADPOOL_H__ */