21#include <winpr/config.h>
23#include <winpr/synch.h>
24#include <winpr/assert.h>
30#ifdef WINPR_SYNCHRONIZATION_BARRIER
32#include <winpr/sysinfo.h>
33#include <winpr/library.h>
34#include <winpr/interlocked.h>
35#include <winpr/thread.h>
49static HMODULE g_Kernel32 =
nullptr;
50static BOOL g_NativeBarrier = FALSE;
51static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;
54 LONG lTotalThreads, LONG lSpinCount);
59static fnInitializeSynchronizationBarrier pfnInitializeSynchronizationBarrier =
nullptr;
60static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier =
nullptr;
61static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier =
nullptr;
63static BOOL CALLBACK InitOnce_Barrier(
PINIT_ONCE once, PVOID param, PVOID* context)
65 g_Kernel32 = LoadLibraryA(
"kernel32.dll");
70 pfnInitializeSynchronizationBarrier = GetProcAddressAs(
71 g_Kernel32,
"InitializeSynchronizationBarrier", fnInitializeSynchronizationBarrier);
73 pfnEnterSynchronizationBarrier =
74 GetProcAddressAs(g_Kernel32,
"EnterSynchronizationBarrier", fnEnterSynchronizationBarrier);
75 pfnDeleteSynchronizationBarrier = GetProcAddressAs(g_Kernel32,
"DeleteSynchronizationBarrier",
76 fnDeleteSynchronizationBarrier);
78 if (pfnInitializeSynchronizationBarrier && pfnEnterSynchronizationBarrier &&
79 pfnDeleteSynchronizationBarrier)
81 g_NativeBarrier = TRUE;
90 LONG lTotalThreads, LONG lSpinCount)
93 HANDLE hEvent0 =
nullptr;
94 HANDLE hEvent1 =
nullptr;
97 if (!InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier,
nullptr,
nullptr))
101 return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount);
104 if (!lpBarrier || lTotalThreads < 1 || lSpinCount < -1)
106 SetLastError(ERROR_INVALID_PARAMETER);
112 if (lSpinCount == -1)
115 if (!(hEvent0 = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
118 if (!(hEvent1 = CreateEvent(
nullptr, TRUE, FALSE,
nullptr)))
120 (void)CloseHandle(hEvent0);
124 GetNativeSystemInfo(&sysinfo);
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;
140 LONG remainingThreads = 0;
141 HANDLE hCurrentEvent =
nullptr;
142 HANDLE hDormantEvent =
nullptr;
146 return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags);
173 hCurrentEvent = (HANDLE)lpBarrier->Reserved3[0];
174 hDormantEvent = (HANDLE)lpBarrier->Reserved3[1];
176 remainingThreads = InterlockedDecrement((LONG*)&lpBarrier->Reserved1);
178 WINPR_ASSERT(remainingThreads >= 0);
180 if (remainingThreads > 0)
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;
196 if (spinOnly || (((ULONG)remainingThreads < dwProcessors) && !blockOnly))
198 DWORD dwSpinCount = lpBarrier->Reserved5;
204 volatile ULONG_PTR* cmp = &lpBarrier->Reserved3[0];
206 while ((block = (*cmp == (ULONG_PTR)hCurrentEvent)))
207 if (!spinOnly && ++sp > dwSpinCount)
212 (void)WaitForSingleObject(hCurrentEvent, INFINITE);
218 (void)ResetEvent(hDormantEvent);
221 lpBarrier->Reserved1 = lpBarrier->Reserved2;
224 lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
225 lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
228 (void)SetEvent(hCurrentEvent);
237 return pfnDeleteSynchronizationBarrier(lpBarrier);
249 while (lpBarrier->Reserved1 != lpBarrier->Reserved2)
252 if (lpBarrier->Reserved3[0])
253 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[0]);
255 if (lpBarrier->Reserved3[1])
256 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[1]);