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