FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
barrier.c
1
21#include <winpr/config.h>
22
23#include <winpr/synch.h>
24#include <winpr/assert.h>
25
26#include "synch.h"
27
28#include <winpr/crt.h>
29
30#ifdef WINPR_SYNCHRONIZATION_BARRIER
31
32#include <winpr/sysinfo.h>
33#include <winpr/library.h>
34#include <winpr/interlocked.h>
35#include <winpr/thread.h>
36
47#ifdef _WIN32
48
49static HMODULE g_Kernel32 = NULL;
50static BOOL g_NativeBarrier = FALSE;
51static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;
52
53typedef BOOL(WINAPI* fnInitializeSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier,
54 LONG lTotalThreads, LONG lSpinCount);
55typedef BOOL(WINAPI* fnEnterSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier,
56 DWORD dwFlags);
57typedef BOOL(WINAPI* fnDeleteSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier);
58
59static fnInitializeSynchronizationBarrier pfnInitializeSynchronizationBarrier = NULL;
60static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier = NULL;
61static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier = NULL;
62
63static BOOL CALLBACK InitOnce_Barrier(PINIT_ONCE once, PVOID param, PVOID* context)
64{
65 g_Kernel32 = LoadLibraryA("kernel32.dll");
66
67 if (!g_Kernel32)
68 return TRUE;
69
70 pfnInitializeSynchronizationBarrier = GetProcAddressAs(
71 g_Kernel32, "InitializeSynchronizationBarrier", fnInitializeSynchronizationBarrier);
72
73 pfnEnterSynchronizationBarrier =
74 GetProcAddressAs(g_Kernel32, "EnterSynchronizationBarrier", fnEnterSynchronizationBarrier);
75 pfnDeleteSynchronizationBarrier = GetProcAddressAs(g_Kernel32, "DeleteSynchronizationBarrier",
76 fnDeleteSynchronizationBarrier);
77
78 if (pfnInitializeSynchronizationBarrier && pfnEnterSynchronizationBarrier &&
79 pfnDeleteSynchronizationBarrier)
80 {
81 g_NativeBarrier = TRUE;
82 }
83
84 return TRUE;
85}
86
87#endif
88
89BOOL WINAPI winpr_InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier,
90 LONG lTotalThreads, LONG lSpinCount)
91{
92 SYSTEM_INFO sysinfo;
93 HANDLE hEvent0 = NULL;
94 HANDLE hEvent1 = NULL;
95
96#ifdef _WIN32
97 InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier, NULL, NULL);
98
99 if (g_NativeBarrier)
100 return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount);
101#endif
102
103 if (!lpBarrier || lTotalThreads < 1 || lSpinCount < -1)
104 {
105 SetLastError(ERROR_INVALID_PARAMETER);
106 return FALSE;
107 }
108
109 ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER));
110
111 if (lSpinCount == -1)
112 lSpinCount = 2000;
113
114 if (!(hEvent0 = CreateEvent(NULL, TRUE, FALSE, NULL)))
115 return FALSE;
116
117 if (!(hEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL)))
118 {
119 (void)CloseHandle(hEvent0);
120 return FALSE;
121 }
122
123 GetNativeSystemInfo(&sysinfo);
124
125 WINPR_ASSERT(lTotalThreads >= 0);
126 lpBarrier->Reserved1 = (DWORD)lTotalThreads;
127 lpBarrier->Reserved2 = (DWORD)lTotalThreads;
128 lpBarrier->Reserved3[0] = (ULONG_PTR)hEvent0;
129 lpBarrier->Reserved3[1] = (ULONG_PTR)hEvent1;
130 lpBarrier->Reserved4 = sysinfo.dwNumberOfProcessors;
131 WINPR_ASSERT(lSpinCount >= 0);
132 lpBarrier->Reserved5 = (DWORD)lSpinCount;
133
134 return TRUE;
135}
136
137BOOL WINAPI winpr_EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags)
138{
139 LONG remainingThreads = 0;
140 HANDLE hCurrentEvent = NULL;
141 HANDLE hDormantEvent = NULL;
142
143#ifdef _WIN32
144 if (g_NativeBarrier)
145 return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags);
146#endif
147
148 if (!lpBarrier)
149 return FALSE;
150
172 hCurrentEvent = (HANDLE)lpBarrier->Reserved3[0];
173 hDormantEvent = (HANDLE)lpBarrier->Reserved3[1];
174
175 remainingThreads = InterlockedDecrement((LONG*)&lpBarrier->Reserved1);
176
177 WINPR_ASSERT(remainingThreads >= 0);
178
179 if (remainingThreads > 0)
180 {
181 DWORD dwProcessors = lpBarrier->Reserved4;
182 BOOL spinOnly = (dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY) ? TRUE : FALSE;
183 BOOL blockOnly = (dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) ? TRUE : FALSE;
184 BOOL block = TRUE;
185
195 if (spinOnly || (((ULONG)remainingThreads < dwProcessors) && !blockOnly))
196 {
197 DWORD dwSpinCount = lpBarrier->Reserved5;
198 DWORD sp = 0;
203 volatile ULONG_PTR* cmp = &lpBarrier->Reserved3[0];
204 /* we spin until the last thread _completed_ the event switch */
205 while ((block = (*cmp == (ULONG_PTR)hCurrentEvent)))
206 if (!spinOnly && ++sp > dwSpinCount)
207 break;
208 }
209
210 if (block)
211 (void)WaitForSingleObject(hCurrentEvent, INFINITE);
212
213 return FALSE;
214 }
215
216 /* reset the dormant event first */
217 (void)ResetEvent(hDormantEvent);
218
219 /* reset the remaining counter */
220 lpBarrier->Reserved1 = lpBarrier->Reserved2;
221
222 /* switch events - this will also unblock the spinning threads */
223 lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
224 lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
225
226 /* signal the blocked threads */
227 (void)SetEvent(hCurrentEvent);
228
229 return TRUE;
230}
231
232BOOL WINAPI winpr_DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier)
233{
234#ifdef _WIN32
235 if (g_NativeBarrier)
236 return pfnDeleteSynchronizationBarrier(lpBarrier);
237#endif
238
245 if (!lpBarrier)
246 return TRUE;
247
248 while (lpBarrier->Reserved1 != lpBarrier->Reserved2)
249 SwitchToThread();
250
251 if (lpBarrier->Reserved3[0])
252 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[0]);
253
254 if (lpBarrier->Reserved3[1])
255 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[1]);
256
257 ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER));
258
259 return TRUE;
260}
261
262#endif