20#include <winpr/config.h>
23#include <winpr/sysinfo.h>
24#include <winpr/pool.h>
25#include <winpr/library.h>
29#ifdef WINPR_THREAD_POOL
32static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
33static PTP_POOL(WINAPI* pCreateThreadpool)(PVOID reserved);
34static VOID(WINAPI* pCloseThreadpool)(PTP_POOL ptpp);
35static BOOL(WINAPI* pSetThreadpoolThreadMinimum)(PTP_POOL ptpp, DWORD cthrdMic);
36static VOID(WINAPI* pSetThreadpoolThreadMaximum)(PTP_POOL ptpp, DWORD cthrdMost);
38static BOOL CALLBACK init_module(
PINIT_ONCE once, PVOID param, PVOID* context)
40 HMODULE kernel32 = LoadLibraryA(
"kernel32.dll");
43 pCreateThreadpool = GetProcAddressAs(kernel32,
"CreateThreadpool",
void*);
44 pCloseThreadpool = GetProcAddressAs(kernel32,
"CloseThreadpool",
void*);
45 pSetThreadpoolThreadMinimum =
46 GetProcAddressAs(kernel32,
"SetThreadpoolThreadMinimum",
void*);
47 pSetThreadpoolThreadMaximum =
48 GetProcAddressAs(kernel32,
"SetThreadpoolThreadMaximum",
void*);
54static TP_POOL DEFAULT_POOL = {
63static DWORD WINAPI thread_pool_work_func(LPVOID arg)
66 PTP_POOL pool =
nullptr;
67 PTP_WORK work =
nullptr;
69 PTP_CALLBACK_INSTANCE callbackInstance =
nullptr;
73 events[0] = pool->TerminateEvent;
74 events[1] = Queue_Event(pool->PendingQueue);
78 status = WaitForMultipleObjects(2, events, FALSE, INFINITE);
80 if (status == WAIT_OBJECT_0)
83 if (status != (WAIT_OBJECT_0 + 1))
86 callbackInstance = (PTP_CALLBACK_INSTANCE)Queue_Dequeue(pool->PendingQueue);
90 work = callbackInstance->Work;
91 work->WorkCallback(callbackInstance, work->CallbackParameter, work);
92 CountdownEvent_Signal(pool->WorkComplete, 1);
93 free(callbackInstance);
101static void threads_close(
void* thread)
103 (void)WaitForSingleObject(thread, INFINITE);
104 (void)CloseHandle(thread);
107static BOOL InitializeThreadpool(PTP_POOL pool)
115 if (!(pool->PendingQueue = Queue_New(TRUE, -1, -1)))
118 if (!(pool->WorkComplete = CountdownEvent_New(0)))
121 if (!(pool->TerminateEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
124 if (!(pool->Threads = ArrayList_New(TRUE)))
127 obj = ArrayList_Object(pool->Threads);
130#if !defined(WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
131#error "WINPR_THREADPOOL_DEFAULT_MIN_COUNT must be defined"
133#if !defined(WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
134#error "WINPR_THREADPOOL_DEFAULT_MAX_COUNT must be defined"
139 GetSystemInfo(&info);
141 DWORD min = info.dwNumberOfProcessors;
142 DWORD max = info.dwNumberOfProcessors;
143 if (info.dwNumberOfProcessors < WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
144 min = WINPR_THREADPOOL_DEFAULT_MIN_COUNT;
145 if (info.dwNumberOfProcessors > WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
146 max = WINPR_THREADPOOL_DEFAULT_MAX_COUNT;
150 if (!SetThreadpoolThreadMinimum(pool, min))
153 SetThreadpoolThreadMaximum(pool, max);
162PTP_POOL GetDefaultThreadpool(
void)
164 PTP_POOL pool = &DEFAULT_POOL;
166 if (!InitializeThreadpool(pool))
172PTP_POOL winpr_CreateThreadpool(PVOID reserved)
174 PTP_POOL pool =
nullptr;
176 if (!InitOnceExecuteOnce(&init_once_module, init_module,
nullptr,
nullptr))
178 if (pCreateThreadpool)
179 return pCreateThreadpool(reserved);
181 WINPR_UNUSED(reserved);
183 if (!(pool = (PTP_POOL)calloc(1,
sizeof(TP_POOL))))
186 if (!InitializeThreadpool(pool))
188 winpr_CloseThreadpool(pool);
195VOID winpr_CloseThreadpool(PTP_POOL ptpp)
198 if (!InitOnceExecuteOnce(&init_once_module, init_module,
nullptr,
nullptr))
200 if (pCloseThreadpool)
202 pCloseThreadpool(ptpp);
206 (void)SetEvent(ptpp->TerminateEvent);
208 ArrayList_Free(ptpp->Threads);
209 Queue_Free(ptpp->PendingQueue);
210 CountdownEvent_Free(ptpp->WorkComplete);
211 (void)CloseHandle(ptpp->TerminateEvent);
214 TP_POOL empty = WINPR_C_ARRAY_INIT;
218 if (ptpp != &DEFAULT_POOL)
222BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
226 if (!InitOnceExecuteOnce(&init_once_module, init_module,
nullptr,
nullptr))
228 if (pSetThreadpoolThreadMinimum)
229 return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
231 ptpp->Minimum = cthrdMic;
233 ArrayList_Lock(ptpp->Threads);
234 while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
236 HANDLE thread = CreateThread(
nullptr, 0, thread_pool_work_func, (
void*)ptpp, 0,
nullptr);
240 if (!ArrayList_Append(ptpp->Threads, thread))
242 (void)CloseHandle(thread);
249 ArrayList_Unlock(ptpp->Threads);
254VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
257 if (!InitOnceExecuteOnce(&init_once_module, init_module,
nullptr,
nullptr))
259 if (pSetThreadpoolThreadMaximum)
261 pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
265 ptpp->Maximum = cthrdMost;
267 ArrayList_Lock(ptpp->Threads);
268 if (ArrayList_Count(ptpp->Threads) > ptpp->Maximum)
270 (void)SetEvent(ptpp->TerminateEvent);
271 ArrayList_Clear(ptpp->Threads);
272 (void)ResetEvent(ptpp->TerminateEvent);
274 ArrayList_Unlock(ptpp->Threads);
275 winpr_SetThreadpoolThreadMinimum(ptpp, ptpp->Minimum);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree