FreeRDP
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
32 static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
33 static PTP_POOL(WINAPI* pCreateThreadpool)(PVOID reserved);
34 static VOID(WINAPI* pCloseThreadpool)(PTP_POOL ptpp);
35 static BOOL(WINAPI* pSetThreadpoolThreadMinimum)(PTP_POOL ptpp, DWORD cthrdMic);
36 static VOID(WINAPI* pSetThreadpoolThreadMaximum)(PTP_POOL ptpp, DWORD cthrdMost);
37 
38 static 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 
54 static 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 
63 static 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 
101 static void threads_close(void* thread)
102 {
103  (void)WaitForSingleObject(thread, INFINITE);
104  (void)CloseHandle(thread);
105 }
106 
107 static 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 
140 fail:
141  return rc;
142 }
143 
144 PTP_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 
156 PTP_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 
178 VOID 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 
204 BOOL 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;
229 fail:
230  ArrayList_Unlock(ptpp->Threads);
231 
232  return rc;
233 }
234 
235 VOID 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