This is my first time contributing wine and there are a lot of things I'm not sure about, so any comments are welcome. :)
-- v6: 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/ntdll/ntdll.spec | 3 ++ dlls/ntdll/sync.c | 61 +++++++++++++++++++++++++++++++++ include/synchapi.h | 14 ++++++++ include/winnt.h | 8 +++++ 7 files changed, 113 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..c908e5cae1a 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) ntdll.RtlDeleteBarrier @ 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) ntdll.RtlBarrier @ 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) ntdll.RtlInitBarrier # @ stub InstallELAMCertificateInfo @ stdcall -arch=i386 InterlockedCompareExchange(ptr long long) @ stdcall -arch=i386 -ret64 InterlockedCompareExchange64(ptr int64 int64) ntdll.RtlInterlockedCompareExchange64 diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index c09157a369b..f9eac0744ef 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -514,6 +514,7 @@ @ stdcall RtlAreBitsSet(ptr long long) # @ stub RtlAssert2 @ stdcall RtlAssert(ptr ptr long str) +@ stdcall RtlBarrier(ptr long) # @ stub RtlCancelTimer @ stdcall -norelay RtlCaptureContext(ptr) @ stdcall RtlCaptureStackBackTrace(long long ptr ptr) @@ -598,6 +599,7 @@ @ stub RtlDelete @ stdcall RtlDeleteAce(ptr long) @ stdcall RtlDeleteAtomFromAtomTable(ptr long) +@ stdcall RtlDeleteBarrier(ptr) @ stdcall RtlDeleteCriticalSection(ptr) @ stdcall -arch=!i386 RtlDeleteGrowableFunctionTable(ptr) @ stub RtlDeleteElementGenericTable @@ -777,6 +779,7 @@ @ stdcall RtlImpersonateSelf(long) @ stdcall RtlInitAnsiString(ptr str) @ stdcall RtlInitAnsiStringEx(ptr str) +@ stdcall RtlInitBarrier(ptr long long) @ stdcall RtlInitCodePageTable(ptr ptr) # @ stub RtlInitMemoryStream @ stdcall RtlInitNlsTables(ptr ptr ptr ptr) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index bb5dcbb66e6..2f8acdf732c 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1000,3 +1000,64 @@ void WINAPI RtlWakeAddressSingle( const void *addr )
if (tid) NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tid ); } + + +typedef struct { + SRWLOCK lock; + CONDITION_VARIABLE cond; + LONG count; +} barrier_entry; +C_ASSERT( sizeof(barrier_entry) <= sizeof(RTL_BARRIER) ); + +/*********************************************************************** + * RtlInitBarrier (NTDLL.@) + */ +NTSTATUS WINAPI RtlInitBarrier( PRTL_BARRIER Barrier, ULONG TotalThreads, ULONG SpinCount ) +{ + barrier_entry *barrier = (barrier_entry*)Barrier; + + RtlInitializeSRWLock(&barrier->lock); + RtlInitializeConditionVariable(&barrier->cond); + barrier->count = TotalThreads; + + return TRUE; +} + +/*********************************************************************** + * RtlBarrier (NTDLL.@) + */ +BOOLEAN WINAPI RtlBarrier( PRTL_BARRIER Barrier, ULONG Flags ) +{ + barrier_entry *barrier = (barrier_entry*)Barrier; + 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) { + RtlSleepConditionVariableSRW(&barrier->cond, &barrier->lock, NULL, 0); + wait = barrier->count > 0; + } + + RtlReleaseSRWLockExclusive(&barrier->lock); + + return hint; +} + +/*********************************************************************** + * RtlDeleteBarrier (NTDLL.@) + */ +NTSTATUS WINAPI RtlDeleteBarrier( PRTL_BARRIER Barrier ) +{ + return TRUE; +} 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;
@nsivov I moved the implement to ntdll and added assert. :)