21 #include <winpr/config.h>
23 #include <winpr/synch.h>
24 #include <winpr/assert.h>
28 #include <winpr/crt.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>
49 static HMODULE g_Kernel32 = NULL;
50 static BOOL g_NativeBarrier = FALSE;
51 static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT;
54 LONG lTotalThreads, LONG lSpinCount);
59 static fnInitializeSynchronizationBarrier pfnInitializeSynchronizationBarrier = NULL;
60 static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier = NULL;
61 static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier = NULL;
63 static 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 = NULL;
94 HANDLE hEvent1 = NULL;
97 InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier, NULL, NULL);
100 return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount);
103 if (!lpBarrier || lTotalThreads < 1 || lSpinCount < -1)
105 SetLastError(ERROR_INVALID_PARAMETER);
111 if (lSpinCount == -1)
114 if (!(hEvent0 = CreateEvent(NULL, TRUE, FALSE, NULL)))
117 if (!(hEvent1 = CreateEvent(NULL, TRUE, FALSE, NULL)))
119 (void)CloseHandle(hEvent0);
123 GetNativeSystemInfo(&sysinfo);
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;
139 LONG remainingThreads = 0;
140 HANDLE hCurrentEvent = NULL;
141 HANDLE hDormantEvent = NULL;
145 return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags);
172 hCurrentEvent = (HANDLE)lpBarrier->Reserved3[0];
173 hDormantEvent = (HANDLE)lpBarrier->Reserved3[1];
175 remainingThreads = InterlockedDecrement((LONG*)&lpBarrier->Reserved1);
177 WINPR_ASSERT(remainingThreads >= 0);
179 if (remainingThreads > 0)
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;
195 if (spinOnly || (((ULONG)remainingThreads < dwProcessors) && !blockOnly))
197 DWORD dwSpinCount = lpBarrier->Reserved5;
203 volatile ULONG_PTR* cmp = &lpBarrier->Reserved3[0];
205 while ((block = (*cmp == (ULONG_PTR)hCurrentEvent)))
206 if (!spinOnly && ++sp > dwSpinCount)
211 (void)WaitForSingleObject(hCurrentEvent, INFINITE);
217 (void)ResetEvent(hDormantEvent);
220 lpBarrier->Reserved1 = lpBarrier->Reserved2;
223 lpBarrier->Reserved3[1] = (ULONG_PTR)hCurrentEvent;
224 lpBarrier->Reserved3[0] = (ULONG_PTR)hDormantEvent;
227 (void)SetEvent(hCurrentEvent);
236 return pfnDeleteSynchronizationBarrier(lpBarrier);
248 while (lpBarrier->Reserved1 != lpBarrier->Reserved2)
251 if (lpBarrier->Reserved3[0])
252 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[0]);
254 if (lpBarrier->Reserved3[1])
255 (void)CloseHandle((HANDLE)lpBarrier->Reserved3[1]);