diff options
Diffstat (limited to 'winpr/libwinpr/pool/pool.c')
-rw-r--r-- | winpr/libwinpr/pool/pool.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/winpr/libwinpr/pool/pool.c b/winpr/libwinpr/pool/pool.c new file mode 100644 index 0000000..6c66b42 --- /dev/null +++ b/winpr/libwinpr/pool/pool.c @@ -0,0 +1,251 @@ +/** + * WinPR: Windows Portable Runtime + * Thread Pool API (Pool) + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <winpr/crt.h> +#include <winpr/pool.h> +#include <winpr/library.h> + +#include "pool.h" + +#ifdef WINPR_THREAD_POOL + +#ifdef _WIN32 +static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT; +static PTP_POOL(WINAPI* pCreateThreadpool)(PVOID reserved); +static VOID(WINAPI* pCloseThreadpool)(PTP_POOL ptpp); +static BOOL(WINAPI* pSetThreadpoolThreadMinimum)(PTP_POOL ptpp, DWORD cthrdMic); +static VOID(WINAPI* pSetThreadpoolThreadMaximum)(PTP_POOL ptpp, DWORD cthrdMost); + +static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context) +{ + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + if (kernel32) + { + pCreateThreadpool = (void*)GetProcAddress(kernel32, "CreateThreadpool"); + pCloseThreadpool = (void*)GetProcAddress(kernel32, "CloseThreadpool"); + pSetThreadpoolThreadMinimum = (void*)GetProcAddress(kernel32, "SetThreadpoolThreadMinimum"); + pSetThreadpoolThreadMaximum = (void*)GetProcAddress(kernel32, "SetThreadpoolThreadMaximum"); + } + return TRUE; +} +#endif + +static TP_POOL DEFAULT_POOL = { + 0, /* DWORD Minimum */ + 500, /* DWORD Maximum */ + NULL, /* wArrayList* Threads */ + NULL, /* wQueue* PendingQueue */ + NULL, /* HANDLE TerminateEvent */ + NULL, /* wCountdownEvent* WorkComplete */ +}; + +static DWORD WINAPI thread_pool_work_func(LPVOID arg) +{ + DWORD status = 0; + PTP_POOL pool = NULL; + PTP_WORK work = NULL; + HANDLE events[2]; + PTP_CALLBACK_INSTANCE callbackInstance = NULL; + + pool = (PTP_POOL)arg; + + events[0] = pool->TerminateEvent; + events[1] = Queue_Event(pool->PendingQueue); + + while (1) + { + status = WaitForMultipleObjects(2, events, FALSE, INFINITE); + + if (status == WAIT_OBJECT_0) + break; + + if (status != (WAIT_OBJECT_0 + 1)) + break; + + callbackInstance = (PTP_CALLBACK_INSTANCE)Queue_Dequeue(pool->PendingQueue); + + if (callbackInstance) + { + work = callbackInstance->Work; + work->WorkCallback(callbackInstance, work->CallbackParameter, work); + CountdownEvent_Signal(pool->WorkComplete, 1); + free(callbackInstance); + } + } + + ExitThread(0); + return 0; +} + +static void threads_close(void* thread) +{ + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); +} + +static BOOL InitializeThreadpool(PTP_POOL pool) +{ + BOOL rc = FALSE; + wObject* obj = NULL; + HANDLE thread = NULL; + + if (pool->Threads) + return TRUE; + + pool->Minimum = 0; + pool->Maximum = 500; + + if (!(pool->PendingQueue = Queue_New(TRUE, -1, -1))) + goto fail; + + if (!(pool->WorkComplete = CountdownEvent_New(0))) + goto fail; + + if (!(pool->TerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + goto fail; + + if (!(pool->Threads = ArrayList_New(TRUE))) + goto fail; + + obj = ArrayList_Object(pool->Threads); + obj->fnObjectFree = threads_close; + + for (int index = 0; index < 4; index++) + { + if (!(thread = CreateThread(NULL, 0, thread_pool_work_func, (void*)pool, 0, NULL))) + { + goto fail; + } + + if (!ArrayList_Append(pool->Threads, thread)) + { + CloseHandle(thread); + goto fail; + } + } + + rc = TRUE; + +fail: + return rc; +} + +PTP_POOL GetDefaultThreadpool(void) +{ + PTP_POOL pool = NULL; + + pool = &DEFAULT_POOL; + + if (!InitializeThreadpool(pool)) + return NULL; + + return pool; +} + +PTP_POOL winpr_CreateThreadpool(PVOID reserved) +{ + PTP_POOL pool = NULL; +#ifdef _WIN32 + InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL); + if (pCreateThreadpool) + return pCreateThreadpool(reserved); +#else + WINPR_UNUSED(reserved); +#endif + if (!(pool = (PTP_POOL)calloc(1, sizeof(TP_POOL)))) + return NULL; + + if (!InitializeThreadpool(pool)) + { + winpr_CloseThreadpool(pool); + return NULL; + } + + return pool; +} + +VOID winpr_CloseThreadpool(PTP_POOL ptpp) +{ +#ifdef _WIN32 + InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL); + if (pCloseThreadpool) + { + pCloseThreadpool(ptpp); + return; + } +#endif + SetEvent(ptpp->TerminateEvent); + + ArrayList_Free(ptpp->Threads); + Queue_Free(ptpp->PendingQueue); + CountdownEvent_Free(ptpp->WorkComplete); + CloseHandle(ptpp->TerminateEvent); + + { + TP_POOL empty = { 0 }; + *ptpp = empty; + } + + if (ptpp != &DEFAULT_POOL) + free(ptpp); +} + +BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic) +{ + HANDLE thread = NULL; +#ifdef _WIN32 + InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL); + if (pSetThreadpoolThreadMinimum) + return pSetThreadpoolThreadMinimum(ptpp, cthrdMic); +#endif + ptpp->Minimum = cthrdMic; + + while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum) + { + if (!(thread = CreateThread(NULL, 0, thread_pool_work_func, (void*)ptpp, 0, NULL))) + { + return FALSE; + } + + if (!ArrayList_Append(ptpp->Threads, thread)) + { + CloseHandle(thread); + return FALSE; + } + } + + return TRUE; +} + +VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost) +{ +#ifdef _WIN32 + InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL); + if (pSetThreadpoolThreadMaximum) + { + pSetThreadpoolThreadMaximum(ptpp, cthrdMost); + return; + } +#endif + ptpp->Maximum = cthrdMost; +} + +#endif /* WINPR_THREAD_POOL defined */ |