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