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 SYSTEM_INFO info = { 0 };
138 GetSystemInfo(&info);
139
140 DWORD min = info.dwNumberOfProcessors;
141 DWORD max = info.dwNumberOfProcessors;
142 if (info.dwNumberOfProcessors < WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
143 min = WINPR_THREADPOOL_DEFAULT_MIN_COUNT;
144 if (info.dwNumberOfProcessors > WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
145 max = WINPR_THREADPOOL_DEFAULT_MAX_COUNT;
146 if (min > max)
147 min = max;
148
149 if (!SetThreadpoolThreadMinimum(pool, min))
150 goto fail;
151
152 SetThreadpoolThreadMaximum(pool, max);
153
154 rc = TRUE;
155
156fail:
157 return rc;
158}
159
160PTP_POOL GetDefaultThreadpool(void)
161{
162 PTP_POOL pool = &DEFAULT_POOL;
163
164 if (!InitializeThreadpool(pool))
165 return NULL;
166
167 return pool;
168}
169
170PTP_POOL winpr_CreateThreadpool(PVOID reserved)
171{
172 PTP_POOL pool = NULL;
173#ifdef _WIN32
174 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
175 if (pCreateThreadpool)
176 return pCreateThreadpool(reserved);
177#else
178 WINPR_UNUSED(reserved);
179#endif
180 if (!(pool = (PTP_POOL)calloc(1, sizeof(TP_POOL))))
181 return NULL;
182
183 if (!InitializeThreadpool(pool))
184 {
185 winpr_CloseThreadpool(pool);
186 return NULL;
187 }
188
189 return pool;
190}
191
192VOID winpr_CloseThreadpool(PTP_POOL ptpp)
193{
194#ifdef _WIN32
195 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
196 if (pCloseThreadpool)
197 {
198 pCloseThreadpool(ptpp);
199 return;
200 }
201#endif
202 (void)SetEvent(ptpp->TerminateEvent);
203
204 ArrayList_Free(ptpp->Threads);
205 Queue_Free(ptpp->PendingQueue);
206 CountdownEvent_Free(ptpp->WorkComplete);
207 (void)CloseHandle(ptpp->TerminateEvent);
208
209 {
210 TP_POOL empty = { 0 };
211 *ptpp = empty;
212 }
213
214 if (ptpp != &DEFAULT_POOL)
215 free(ptpp);
216}
217
218BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
219{
220 BOOL rc = FALSE;
221#ifdef _WIN32
222 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
223 if (pSetThreadpoolThreadMinimum)
224 return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
225#endif
226 ptpp->Minimum = cthrdMic;
227
228 ArrayList_Lock(ptpp->Threads);
229 while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
230 {
231 HANDLE thread = CreateThread(NULL, 0, thread_pool_work_func, (void*)ptpp, 0, NULL);
232 if (!thread)
233 goto fail;
234
235 if (!ArrayList_Append(ptpp->Threads, thread))
236 {
237 (void)CloseHandle(thread);
238 goto fail;
239 }
240 }
241
242 rc = TRUE;
243fail:
244 ArrayList_Unlock(ptpp->Threads);
245
246 return rc;
247}
248
249VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
250{
251#ifdef _WIN32
252 InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
253 if (pSetThreadpoolThreadMaximum)
254 {
255 pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
256 return;
257 }
258#endif
259 ptpp->Maximum = cthrdMost;
260
261 ArrayList_Lock(ptpp->Threads);
262 if (ArrayList_Count(ptpp->Threads) > ptpp->Maximum)
263 {
264 (void)SetEvent(ptpp->TerminateEvent);
265 ArrayList_Clear(ptpp->Threads);
266 (void)ResetEvent(ptpp->TerminateEvent);
267 }
268 ArrayList_Unlock(ptpp->Threads);
269 winpr_SetThreadpoolThreadMinimum(ptpp, ptpp->Minimum);
270}
271
272#endif /* WINPR_THREAD_POOL defined */
This struct contains function pointer to initialize/free objects.
Definition collections.h:57