FreeRDP
Loading...
Searching...
No Matches
pool.c
1
20#include <winpr/config.h>
21
22#include <winpr/crt.h>
23#include <winpr/sysinfo.h>
24#include <winpr/pool.h>
25#include <winpr/library.h>
26
27#include "pool.h"
28
29#ifdef WINPR_THREAD_POOL
30
31#ifdef _WIN32
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);
37
38static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
39{
40 HMODULE kernel32 = LoadLibraryA("kernel32.dll");
41 if (kernel32)
42 {
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*);
49 }
50 return TRUE;
51}
52#endif
53
54static TP_POOL DEFAULT_POOL = {
55 0, /* DWORD Minimum */
56 500, /* DWORD Maximum */
57 nullptr, /* wArrayList* Threads */
58 nullptr, /* wQueue* PendingQueue */
59 nullptr, /* HANDLE TerminateEvent */
60 nullptr, /* wCountdownEvent* WorkComplete */
61};
62
63static DWORD WINAPI thread_pool_work_func(LPVOID arg)
64{
65 DWORD status = 0;
66 PTP_POOL pool = nullptr;
67 PTP_WORK work = nullptr;
68 HANDLE events[2];
69 PTP_CALLBACK_INSTANCE callbackInstance = nullptr;
70
71 pool = (PTP_POOL)arg;
72
73 events[0] = pool->TerminateEvent;
74 events[1] = Queue_Event(pool->PendingQueue);
75
76 while (1)
77 {
78 status = WaitForMultipleObjects(2, events, FALSE, INFINITE);
79
80 if (status == WAIT_OBJECT_0)
81 break;
82
83 if (status != (WAIT_OBJECT_0 + 1))
84 break;
85
86 callbackInstance = (PTP_CALLBACK_INSTANCE)Queue_Dequeue(pool->PendingQueue);
87
88 if (callbackInstance)
89 {
90 work = callbackInstance->Work;
91 work->WorkCallback(callbackInstance, work->CallbackParameter, work);
92 CountdownEvent_Signal(pool->WorkComplete, 1);
93 free(callbackInstance);
94 }
95 }
96
97 ExitThread(0);
98 return 0;
99}
100
101static void threads_close(void* thread)
102{
103 (void)WaitForSingleObject(thread, INFINITE);
104 (void)CloseHandle(thread);
105}
106
107static BOOL InitializeThreadpool(PTP_POOL pool)
108{
109 BOOL rc = FALSE;
110 wObject* obj = nullptr;
111
112 if (pool->Threads)
113 return TRUE;
114
115 if (!(pool->PendingQueue = Queue_New(TRUE, -1, -1)))
116 goto fail;
117
118 if (!(pool->WorkComplete = CountdownEvent_New(0)))
119 goto fail;
120
121 if (!(pool->TerminateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
122 goto fail;
123
124 if (!(pool->Threads = ArrayList_New(TRUE)))
125 goto fail;
126
127 obj = ArrayList_Object(pool->Threads);
128 obj->fnObjectFree = threads_close;
129
130#if !defined(WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
131#error "WINPR_THREADPOOL_DEFAULT_MIN_COUNT must be defined"
132#endif
133#if !defined(WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
134#error "WINPR_THREADPOOL_DEFAULT_MAX_COUNT must be defined"
135#endif
136
137 {
138 SYSTEM_INFO info = WINPR_C_ARRAY_INIT;
139 GetSystemInfo(&info);
140
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;
147 if (min > max)
148 min = max;
149
150 if (!SetThreadpoolThreadMinimum(pool, min))
151 goto fail;
152
153 SetThreadpoolThreadMaximum(pool, max);
154 }
155
156 rc = TRUE;
157
158fail:
159 return rc;
160}
161
162PTP_POOL GetDefaultThreadpool(void)
163{
164 PTP_POOL pool = &DEFAULT_POOL;
165
166 if (!InitializeThreadpool(pool))
167 return nullptr;
168
169 return pool;
170}
171
172PTP_POOL winpr_CreateThreadpool(PVOID reserved)
173{
174 PTP_POOL pool = nullptr;
175#ifdef _WIN32
176 if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
177 return nullptr;
178 if (pCreateThreadpool)
179 return pCreateThreadpool(reserved);
180#else
181 WINPR_UNUSED(reserved);
182#endif
183 if (!(pool = (PTP_POOL)calloc(1, sizeof(TP_POOL))))
184 return nullptr;
185
186 if (!InitializeThreadpool(pool))
187 {
188 winpr_CloseThreadpool(pool);
189 return nullptr;
190 }
191
192 return pool;
193}
194
195VOID winpr_CloseThreadpool(PTP_POOL ptpp)
196{
197#ifdef _WIN32
198 if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
199 return;
200 if (pCloseThreadpool)
201 {
202 pCloseThreadpool(ptpp);
203 return;
204 }
205#endif
206 (void)SetEvent(ptpp->TerminateEvent);
207
208 ArrayList_Free(ptpp->Threads);
209 Queue_Free(ptpp->PendingQueue);
210 CountdownEvent_Free(ptpp->WorkComplete);
211 (void)CloseHandle(ptpp->TerminateEvent);
212
213 {
214 TP_POOL empty = WINPR_C_ARRAY_INIT;
215 *ptpp = empty;
216 }
217
218 if (ptpp != &DEFAULT_POOL)
219 free(ptpp);
220}
221
222BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
223{
224 BOOL rc = FALSE;
225#ifdef _WIN32
226 if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
227 return FALSE;
228 if (pSetThreadpoolThreadMinimum)
229 return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
230#endif
231 ptpp->Minimum = cthrdMic;
232
233 ArrayList_Lock(ptpp->Threads);
234 while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
235 {
236 HANDLE thread = CreateThread(nullptr, 0, thread_pool_work_func, (void*)ptpp, 0, nullptr);
237 if (!thread)
238 goto fail;
239
240 if (!ArrayList_Append(ptpp->Threads, thread))
241 {
242 (void)CloseHandle(thread);
243 goto fail;
244 }
245 }
246
247 rc = TRUE;
248fail:
249 ArrayList_Unlock(ptpp->Threads);
250
251 return rc;
252}
253
254VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
255{
256#ifdef _WIN32
257 if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
258 return;
259 if (pSetThreadpoolThreadMaximum)
260 {
261 pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
262 return;
263 }
264#endif
265 ptpp->Maximum = cthrdMost;
266
267 ArrayList_Lock(ptpp->Threads);
268 if (ArrayList_Count(ptpp->Threads) > ptpp->Maximum)
269 {
270 (void)SetEvent(ptpp->TerminateEvent);
271 ArrayList_Clear(ptpp->Threads);
272 (void)ResetEvent(ptpp->TerminateEvent);
273 }
274 ArrayList_Unlock(ptpp->Threads);
275 winpr_SetThreadpoolThreadMinimum(ptpp, ptpp->Minimum);
276}
277
278#endif /* WINPR_THREAD_POOL defined */
This struct contains function pointer to initialize/free objects.
Definition collections.h:52
OBJECT_FREE_FN fnObjectFree
Definition collections.h:58