FreeRDP
Loading...
Searching...
No Matches
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 = nullptr;
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 = nullptr;
60static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier = nullptr;
61static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier = nullptr;
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 = nullptr;
94 HANDLE hEvent1 = nullptr;
95
96#ifdef _WIN32
97 if (!InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier, nullptr, nullptr))
98 return FALSE;
99
100 if (g_NativeBarrier)
101 return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount);
102#endif
103
104 if (!lpBarrier || lTotalThreads < 1 || lSpinCount < -1)
105 {
106 SetLastError(ERROR_INVALID_PARAMETER);
107 return FALSE;
108 }
109
110 ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER));
111
112 if (lSpinCount == -1)
113 lSpinCount = 2000;
114
115 if (!(hEvent0 = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
116 return FALSE;
117
118 if (!(hEvent1 = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
119 {
120 (void)CloseHandle(hEvent0);
121 return FALSE;
122 }
123
124 GetNativeSystemInfo(&sysinfo);
125
126 WINPR_ASSERT(lTotalThreads >= 0);
127 lpBarrier->Reserved1 = (DWORD)lTotalThreads;
128 lpBarrier->Reserved2 = (DWORD)lTotalThreads;
129 lpBarrier->Reserved3[0] = (ULONG_PTR)hEvent0;
130 lpBarrier->Reserved3[1] = (ULONG_PTR)hEvent1;
131 lpBarrier->Reserved4 = sysinfo.dwNumberOfProcessors;
132 WINPR_ASSERT(lSpinCount >= 0);
133 lpBarrier->Reserved5 = (DWORD)lSpinCount;
134
135 return TRUE;
136}
137
138BOOL WINAPI winpr_EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags)
139{
140 LONG remainingThreads = 0;
141 HANDLE hCurrentEvent = nullptr;
142 HANDLE hDormantEvent = nullptr;
143
144#ifdef _WIN32
145 if (g_NativeBarrier)
146 return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags);
147#endif
148
149 if (!lpBarrier)
150 return FALSE;
151
173 hCurrentEvent = (HANDLE)lpBarrier->Reserved3[0];
174 hDormantEvent = (HANDLE)lpBarrier->Reserved3[1];
175
176 remainingThreads = InterlockedDecrement((LONG*)&lpBarrier->Reserved1);
177
178 WINPR_ASSERT(remainingThreads >= 0);
179
180 if (remainingThreads > 0)
181 {
182 DWORD dwProcessors = lpBarrier->Reserved4;
183 BOOL spinOnly = (dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY) != 0;
184 BOOL blockOnly = (dwFlags & SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY) != 0;
185 BOOL block = TRUE;
186
196 if (spinOnly || (((ULONG)remainingThreads < dwProcessors) && !blockOnly))
197 {
198 DWORD dwSpinCount = lpBarrier->Reserved5;
199 DWORD sp = 0;
204 volatile ULONG_PTR* cmp = &lpBarrier->Reserved3[0];
205 /* we spin until the last thread _completed_ the event switch */
206 while ((block = (*cmp == (ULONG_PTR)hCurrentEvent)))
207 if (!spinOnly && ++sp > dwSpinCount)
208 break;
209 }
210
211 if (block)
212 (void)WaitForSingleObject(hCurrentEvent, INFINITE);
213
214 return FALSE;
215 }
216
217 /* reset the dormant event first */
218 (void)ResetEvent(hDormantEvent);
219
220 /* reset the remaining counter */
221 lpBarrier->Reserved1 = lpBarrier->Reserved2;
222
223 /* switch events - this will also unblock the spinning threads */
224 lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
225 lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
226
227 /* signal the blocked threads */
228 (void)SetEvent(hCurrentEvent);
229
230 return TRUE;
231}
232
233BOOL WINAPI winpr_DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier)
234{
235#ifdef _WIN32
236 if (g_NativeBarrier)
237 return pfnDeleteSynchronizationBarrier(lpBarrier);
238#endif
239
246 if (!lpBarrier)
247 return TRUE;
248
249 while (lpBarrier->Reserved1 != lpBarrier->Reserved2)
250 SwitchToThread();
251
252 if (lpBarrier->Reserved3[0])
253 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[0]);
254
255 if (lpBarrier->Reserved3[1])
256 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[1]);
257
258 ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER));
259
260 return TRUE;
261}
262
263#endif