This is my first time contributing wine and there are a lot of things I'm not sure about, so any comments are welcome. :)
-- v3: kernel32: impl sync barrier
From: quininer quininer@live.com
--- dlls/kernel32/kernel32.spec | 3 ++ dlls/kernel32/tests/sync.c | 21 +++++++++++ dlls/kernelbase/kernelbase.spec | 6 ++-- dlls/kernelbase/sync.c | 63 +++++++++++++++++++++++++++++++++ include/synchapi.h | 14 ++++++++ include/winnt.h | 8 +++++ 6 files changed, 112 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 1deeb2a2ca5..081147d827d 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -375,6 +375,7 @@ @ stdcall DisassociateCurrentThreadFromCallback(ptr) NTDLL.TpDisassociateCallback @ stdcall DiscardVirtualMemory(ptr long) kernelbase.DiscardVirtualMemory @ stdcall DeleteTimerQueue(long) +@ stdcall -import DeleteSynchronizationBarrier(ptr) @ stdcall -import DeleteTimerQueueEx(long long) @ stdcall -import DeleteTimerQueueTimer(long long long) @ stdcall -arch=win64 DeleteUmsCompletionList(ptr) @@ -398,6 +399,7 @@ @ stdcall EndUpdateResourceA(long long) @ stdcall EndUpdateResourceW(long long) @ stdcall EnterCriticalSection(ptr) NTDLL.RtlEnterCriticalSection +@ stdcall -import EnterSynchronizationBarrier(ptr long) @ stdcall EnumCalendarInfoA(ptr long long long) @ stdcall EnumCalendarInfoExA(ptr long long long) @ stdcall -import EnumCalendarInfoExEx(ptr wstr long wstr long long) @@ -970,6 +972,7 @@ @ stdcall -import InitializeProcThreadAttributeList(ptr long long ptr) @ stdcall InitializeSListHead(ptr) NTDLL.RtlInitializeSListHead @ stdcall InitializeSRWLock(ptr) NTDLL.RtlInitializeSRWLock +@ stdcall -import InitializeSynchronizationBarrier(ptr long long) @ stdcall -arch=i386 InterlockedCompareExchange (ptr long long) @ stdcall -arch=i386 -ret64 InterlockedCompareExchange64(ptr int64 int64) NTDLL.RtlInterlockedCompareExchange64 @ stdcall -arch=i386 InterlockedDecrement(ptr) diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 56a9d6e4859..a5b4c13b2b7 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -2841,6 +2841,26 @@ static void test_QueueUserAPC(void) ok(apc_count == 1, "APC count %u\n", apc_count); }
+static DWORD WINAPI barrier_worker(LPVOID b) { + SYNCHRONIZATION_BARRIER *barrier = (SYNCHRONIZATION_BARRIER*)b; + EnterSynchronizationBarrier(barrier, 0); + return 0; +} + +static void test_barrier(void) +{ + SYNCHRONIZATION_BARRIER barrier; + DWORD dummy; + + InitializeSynchronizationBarrier(&barrier, 3, 0); + + CreateThread(NULL, 0, barrier_worker, &barrier, 0, &dummy); + CreateThread(NULL, 0, barrier_worker, &barrier, 0, &dummy); + + EnterSynchronizationBarrier(&barrier, 0); + DeleteSynchronizationBarrier(&barrier); +} + START_TEST(sync) { char **argv; @@ -2912,4 +2932,5 @@ START_TEST(sync) test_alertable_wait(); test_apc_deadlock(); test_crit_section(); + test_barrier(); } diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index e85f2b67d74..c3c6d8ed0dd 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -260,7 +260,7 @@ # @ stub DeleteStateAtomValue # @ stub DeleteStateContainer # @ stub DeleteStateContainerValue -# @ stub DeleteSynchronizationBarrier +@ stdcall DeleteSynchronizationBarrier(ptr) @ stdcall DeleteTimerQueueEx(long long) @ stdcall DeleteTimerQueueTimer(long long long) @ stdcall DeleteVolumeMountPointW(wstr) @@ -293,7 +293,7 @@ @ stdcall EncodeSystemPointer(ptr) ntdll.RtlEncodeSystemPointer # @ stub EnterCriticalPolicySectionInternal @ stdcall EnterCriticalSection(ptr) ntdll.RtlEnterCriticalSection -# @ stub EnterSynchronizationBarrier +@ stdcall EnterSynchronizationBarrier(ptr long) @ stdcall EnumCalendarInfoExEx(ptr wstr long wstr long long) @ stdcall EnumCalendarInfoExW(ptr long long long) @ stdcall EnumCalendarInfoW(ptr long long long) @@ -843,7 +843,7 @@ @ stdcall InitializeSRWLock(ptr) ntdll.RtlInitializeSRWLock @ stdcall InitializeSecurityDescriptor(ptr long) @ stdcall InitializeSid(ptr ptr long) -# @ stub InitializeSynchronizationBarrier +@ stdcall InitializeSynchronizationBarrier(ptr long long) # @ stub InstallELAMCertificateInfo @ stdcall -arch=i386 InterlockedCompareExchange(ptr long long) @ stdcall -arch=i386 -ret64 InterlockedCompareExchange64(ptr int64 int64) ntdll.RtlInterlockedCompareExchange64 diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c index b2086207caa..c80e93e27fe 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -1684,6 +1684,69 @@ BOOL WINAPI DECLSPEC_HOTPATCH InitOnceExecuteOnce( INIT_ONCE *once, PINIT_ONCE_F return !RtlRunOnceExecuteOnce( once, (PRTL_RUN_ONCE_INIT_FN)func, param, context ); }
+typedef struct { + SRWLOCK lock; + CONDITION_VARIABLE cond; + LONG count; +} barrier_t; + +/*********************************************************************** + * InitializeSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH InitializeSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER lpBarrier, + LONG lTotalThreads, LONG lSpinCount ) +{ + barrier_t *barrier = (barrier_t*)lpBarrier; + + RtlInitializeSRWLock(&barrier->lock); + RtlInitializeConditionVariable(&barrier->cond); + barrier->count = lTotalThreads; + + return TRUE; +} + +/*********************************************************************** + * EnterSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH EnterSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER lpBarrier, + DWORD dwFlags ) +{ + barrier_t *barrier = (barrier_t*)lpBarrier; + BOOL wait = TRUE; + BOOL hint = FALSE; + + RtlAcquireSRWLockExclusive(&barrier->lock); + + if (barrier->count > 0) { + barrier->count -= 1; + } + + if (barrier->count == 0) { + RtlWakeAllConditionVariable(&barrier->cond); + wait = FALSE; + hint = TRUE; + } + + while (wait) { + SleepConditionVariableSRW(&barrier->cond, &barrier->lock, INFINITE, 0); + wait = barrier->count > 0; + } + + RtlReleaseSRWLockExclusive(&barrier->lock); + + return hint; +} + +/*********************************************************************** + * DeleteSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER lpBarrier ) +{ + return TRUE; +} + + + #ifdef __i386__
/*********************************************************************** diff --git a/include/synchapi.h b/include/synchapi.h index 0b3dcb8ff74..2c33907da6b 100644 --- a/include/synchapi.h +++ b/include/synchapi.h @@ -19,6 +19,8 @@ #ifndef _SYNCHAPI_H #define _SYNCHAPI_H
+#include <winbase.h> + #ifdef __cplusplus extern "C" { #endif @@ -27,6 +29,18 @@ BOOL WINAPI WaitOnAddress(volatile void*, void*, SIZE_T, DWORD); void WINAPI WakeByAddressAll(void*); void WINAPI WakeByAddressSingle(void*);
+typedef RTL_BARRIER SYNCHRONIZATION_BARRIER; +typedef PRTL_BARRIER PSYNCHRONIZATION_BARRIER; +typedef PRTL_BARRIER LPSYNCHRONIZATION_BARRIER; + +#define SYNCHRONIZATION_BARRIER_FLAGS_SPIN_ONLY 0x01 +#define SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY 0x02 +#define SYNCHRONIZATION_BARRIER_FLAGS_NO_DELETE 0x04 + +BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); +BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); +BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); + #ifdef __cplusplus } #endif diff --git a/include/winnt.h b/include/winnt.h index d1c82084f9f..7983b1eea4d 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6097,6 +6097,14 @@ NTSYSAPI DWORD WINAPI RtlRunOnceExecuteOnce(PRTL_RUN_ONCE,PRTL_RUN_ONCE_INIT_FN, NTSYSAPI DWORD WINAPI RtlRunOnceBeginInitialize(PRTL_RUN_ONCE, DWORD, PVOID*); NTSYSAPI DWORD WINAPI RtlRunOnceComplete(PRTL_RUN_ONCE, DWORD, PVOID);
+typedef struct _RTL_BARRIER { + DWORD Reserved1; + DWORD Reserved2; + ULONG_PTR Reserved3[2]; + DWORD Reserved4; + DWORD Reserved5; +} RTL_BARRIER, *PRTL_BARRIER; + #include <pshpack8.h> typedef struct _IO_COUNTERS { ULONGLONG DECLSPEC_ALIGN(8) ReadOperationCount;
This should probably be implemented in ntdll instead. Also, barrier data structure is exposed in headers, so it might make sense to match some of the fields, if possible. Or at least assert that our data size fits in it.