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 NULL, /* wArrayList* Threads */
58 NULL, /* wQueue* PendingQueue */
59 NULL, /* HANDLE TerminateEvent */
60 NULL, /* wCountdownEvent* WorkComplete */
61};
62
63static DWORD WINAPI thread_pool_work_func(LPVOID arg)
64{
65 DWORD status = 0;
66 PTP_POOL pool = NULL;
67 PTP_WORK work = NULL;
68 HANDLE events[2];
69 PTP_CALLBACK_INSTANCE callbackInstance = NULL;
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 = NULL;
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(NULL, TRUE, FALSE, NULL)))
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 = { 0 };
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 NULL;
168
169 return pool;
170}
171
172PTP_POOL winpr_CreateThreadpool(PVOID reserved)
173{
174 PTP_POOL pool = NULL;
175#ifdef _WIN32
176 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
177 if (pCreateThreadpool)
178 return pCreateThreadpool(reserved);
179#else
180 WINPR_UNUSED(reserved);
181#endif
182 if (!(pool = (PTP_POOL)calloc(1, sizeof(TP_POOL))))
183 return NULL;
184
185 if (!InitializeThreadpool(pool))
186 {
187 winpr_CloseThreadpool(pool);
188 return NULL;
189 }
190
191 return pool;
192}
193
194VOID winpr_CloseThreadpool(PTP_POOL ptpp)
195{
196#ifdef _WIN32
197 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
198 if (pCloseThreadpool)
199 {
200 pCloseThreadpool(ptpp);
201 return;
202 }
203#endif
204 (void)SetEvent(ptpp->TerminateEvent);
205
206 ArrayList_Free(ptpp->Threads);
207 Queue_Free(ptpp->PendingQueue);
208 CountdownEvent_Free(ptpp->WorkComplete);
209 (void)CloseHandle(ptpp->TerminateEvent);
210
211 {
212 TP_POOL empty = { 0 };
213 *ptpp = empty;
214 }
215
216 if (ptpp != &DEFAULT_POOL)
217 free(ptpp);
218}
219
220BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
221{
222 BOOL rc = FALSE;
223#ifdef _WIN32
224 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
225 if (pSetThreadpoolThreadMinimum)
226 return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
227#endif
228 ptpp->Minimum = cthrdMic;
229
230 ArrayList_Lock(ptpp->Threads);
231 while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
232 {
233 HANDLE thread = CreateThread(NULL, 0, thread_pool_work_func, (void*)ptpp, 0, NULL);
234 if (!thread)
235 goto fail;
236
237 if (!ArrayList_Append(ptpp->Threads, thread))
238 {
239 (void)CloseHandle(thread);
240 goto fail;
241 }
242 }
243
244 rc = TRUE;
245fail:
246 ArrayList_Unlock(ptpp->Threads);
247
248 return rc;
249}
250
251VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
252{
253#ifdef _WIN32
254 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
255 if (pSetThreadpoolThreadMaximum)
256 {
257 pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
258 return;
259 }
260#endif
261 ptpp->Maximum = cthrdMost;
262
263 ArrayList_Lock(ptpp->Threads);
264 if (ArrayList_Count(ptpp->Threads) > ptpp->Maximum)
265 {
266 (void)SetEvent(ptpp->TerminateEvent);
267 ArrayList_Clear(ptpp->Threads);
268 (void)ResetEvent(ptpp->TerminateEvent);
269 }
270 ArrayList_Unlock(ptpp->Threads);
271 winpr_SetThreadpoolThreadMinimum(ptpp, ptpp->Minimum);
272}
273
274#endif /* WINPR_THREAD_POOL defined */
This struct contains function pointer to initialize/free objects.
Definition collections.h:57