This is my first time contributing wine and there are a lot of things I'm not sure about, so any comments are welcome. :)
-- v15: kernel32: add sync barrier test kernel32: impl sync barrier
From: quininer quininer@live.com
--- dlls/kernel32/kernel32.spec | 3 ++ dlls/kernelbase/kernelbase.spec | 6 +-- dlls/kernelbase/sync.c | 25 ++++++++++++ dlls/ntdll/ntdll.spec | 3 ++ dlls/ntdll/sync.c | 70 +++++++++++++++++++++++++++++++++ include/synchapi.h | 14 +++++++ include/winnt.h | 8 ++++ include/winternl.h | 3 ++ 8 files changed, 129 insertions(+), 3 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index bb9c8fbfe0e..e9b87f44fdd 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) @@ -971,6 +973,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/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index ffb153a46ee..e4d4d93d681 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..a7943778891 100644 --- a/dlls/kernelbase/sync.c +++ b/dlls/kernelbase/sync.c @@ -1684,6 +1684,31 @@ BOOL WINAPI DECLSPEC_HOTPATCH InitOnceExecuteOnce( INIT_ONCE *once, PINIT_ONCE_F return !RtlRunOnceExecuteOnce( once, (PRTL_RUN_ONCE_INIT_FN)func, param, context ); }
+/*********************************************************************** + * InitializeSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH InitializeSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER barrier, LONG total_threads, + LONG spin_count ) +{ + return set_ntstatus( RtlInitBarrier( barrier, total_threads, spin_count )); +} + +/*********************************************************************** + * EnterSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH EnterSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER barrier, DWORD flags ) +{ + return RtlBarrier(barrier, flags); +} + +/*********************************************************************** + * DeleteSynchronizationBarrier (kernelbase.@) + */ +BOOL WINAPI DECLSPEC_HOTPATCH DeleteSynchronizationBarrier( LPSYNCHRONIZATION_BARRIER barrier ) +{ + return set_ntstatus( RtlDeleteBarrier( barrier )); +} + #ifdef __i386__
/*********************************************************************** diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 1908a089d44..6f184c2477c 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..2b6039473d2 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1000,3 +1000,73 @@ void WINAPI RtlWakeAddressSingle( const void *addr )
if (tid) NtAlertThreadByThreadId( (HANDLE)(DWORD_PTR)tid ); } + + +typedef struct { + RTL_SRWLOCK lock; + RTL_CONDITION_VARIABLE cond; + ULONG total; + ULONG 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; + + if(!Barrier) + return STATUS_INVALID_PARAMETER; + + RtlInitializeSRWLock(&barrier->lock); + RtlInitializeConditionVariable(&barrier->cond); + barrier->total = TotalThreads; + barrier->count = 0; + + return STATUS_SUCCESS; +} + +/*********************************************************************** + * 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 >= barrier->total) { + barrier->count = 0; + } + + barrier->count += 1; + + if (barrier->count >= barrier->total) { + RtlWakeAllConditionVariable(&barrier->cond); + wait = FALSE; + hint = TRUE; + } + + while (wait) { + RtlSleepConditionVariableSRW(&barrier->cond, &barrier->lock, NULL, 0); + wait = barrier->count < barrier->total; + } + + RtlReleaseSRWLockExclusive(&barrier->lock); + + return hint; +} + +/*********************************************************************** + * RtlDeleteBarrier (NTDLL.@) + */ +NTSTATUS WINAPI RtlDeleteBarrier( PRTL_BARRIER Barrier ) +{ + if(!Barrier) + return STATUS_INVALID_PARAMETER; + return STATUS_SUCCESS; +} 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 20db9a8aabd..c6d80440147 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6090,6 +6090,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; diff --git a/include/winternl.h b/include/winternl.h index ff8756211a1..05edfdbc923 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4642,6 +4642,7 @@ NTSYSAPI BOOLEAN WINAPI RtlAreAllAccessesGranted(ACCESS_MASK,ACCESS_MASK); NTSYSAPI BOOLEAN WINAPI RtlAreAnyAccessesGranted(ACCESS_MASK,ACCESS_MASK); NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP,ULONG,ULONG); NTSYSAPI BOOLEAN WINAPI RtlAreBitsClear(PCRTL_BITMAP,ULONG,ULONG); +NTSYSAPI BOOLEAN WINAPI RtlBarrier(PRTL_BARRIER,ULONG); NTSYSAPI USHORT WINAPI RtlCaptureStackBackTrace(ULONG,ULONG,PVOID*,ULONG*); NTSYSAPI NTSTATUS WINAPI RtlCharToInteger(PCSZ,ULONG,PULONG); NTSYSAPI NTSTATUS WINAPI RtlCheckRegistryKey(ULONG, PWSTR); @@ -4687,6 +4688,7 @@ NTSYSAPI NTSTATUS WINAPI RtlDecompressFragment(USHORT,PUCHAR,ULONG,PUCHAR,ULONG NTSYSAPI NTSTATUS WINAPI RtlDefaultNpAcl(PACL*); NTSYSAPI NTSTATUS WINAPI RtlDeleteAce(PACL,DWORD); NTSYSAPI NTSTATUS WINAPI RtlDeleteAtomFromAtomTable(RTL_ATOM_TABLE,RTL_ATOM); +NTSYSAPI NTSTATUS WINAPI RtlDeleteBarrier(PRTL_BARRIER); NTSYSAPI NTSTATUS WINAPI RtlDeleteCriticalSection(RTL_CRITICAL_SECTION *); NTSYSAPI NTSTATUS WINAPI RtlDeleteRegistryValue(ULONG, PCWSTR, PCWSTR); NTSYSAPI void WINAPI RtlDeleteResource(LPRTL_RWLOCK); @@ -4817,6 +4819,7 @@ NTSYSAPI PVOID WINAPI RtlImageRvaToVa(const IMAGE_NT_HEADERS *,HMODULE,DWORD NTSYSAPI NTSTATUS WINAPI RtlImpersonateSelf(SECURITY_IMPERSONATION_LEVEL); NTSYSAPI void WINAPI RtlInitAnsiString(PANSI_STRING,PCSZ); NTSYSAPI NTSTATUS WINAPI RtlInitAnsiStringEx(PANSI_STRING,PCSZ); +NTSYSAPI NTSTATUS WINAPI RtlInitBarrier(PRTL_BARRIER,ULONG,ULONG); NTSYSAPI void WINAPI RtlInitCodePageTable(USHORT*,CPTABLEINFO*); NTSYSAPI void WINAPI RtlInitNlsTables(USHORT*,USHORT*,USHORT*,NLSTABLEINFO*); NTSYSAPI void WINAPI RtlInitString(PSTRING,PCSZ);
From: quininer quininer@live.com
--- dlls/kernel32/tests/sync.c | 54 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 56a9d6e4859..a486f4b7319 100644 --- a/dlls/kernel32/tests/sync.c +++ b/dlls/kernel32/tests/sync.c @@ -2841,6 +2841,59 @@ static void test_QueueUserAPC(void) ok(apc_count == 1, "APC count %u\n", apc_count); }
+typedef struct { + SYNCHRONIZATION_BARRIER barrier; + LONG flag; +} barrier_test_entry; + +static DWORD WINAPI barrier_worker(LPVOID b) { + barrier_test_entry *test = (barrier_test_entry*)b; + + Sleep(550); + InterlockedIncrement(&test->flag); + + EnterSynchronizationBarrier(&test->barrier, 0); + return 0; +} + +static void test_barrier(void) +{ + barrier_test_entry test; + DWORD dummy; + DWORD r; + DWORD start, dur; + + test.flag = 0; + r = InitializeSynchronizationBarrier(&test.barrier, 3, 0); + ok( r == TRUE, "init sync barrier failed\n"); + + start = GetTickCount(); + + CreateThread(NULL, 0, barrier_worker, &test, 0, &dummy); + CreateThread(NULL, 0, barrier_worker, &test, 0, &dummy); + + EnterSynchronizationBarrier(&test.barrier, 0); + + dur = GetTickCount() - start; + ok( dur >= 500, "barrier time too short: %ld\n", dur); + ok( test.flag == 2, "barrier flag check failed: %ld\n", test.flag ); + + /* reuse barrier object */ + start = GetTickCount(); + + CreateThread(NULL, 0, barrier_worker, &test, 0, &dummy); + CreateThread(NULL, 0, barrier_worker, &test, 0, &dummy); + + EnterSynchronizationBarrier(&test.barrier, 0); + + dur = GetTickCount() - start; + ok( dur >= 500, "barrier time too short: %ld\n", dur); + ok( test.flag == 4, "barrier flag check failed: %ld\n", test.flag ); + + r = DeleteSynchronizationBarrier(&test.barrier); + ok( r == TRUE, "delete sync barrier failed\n"); +} + START_TEST(sync) { char **argv; @@ -2912,4 +2965,5 @@ START_TEST(sync) test_alertable_wait(); test_apc_deadlock(); test_crit_section(); + test_barrier(); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=141606
Your paranoid android.
=== w8 (32 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== w8adm (32 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== w864 (32 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== w1064v1507 (32 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== w864 (64 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== w1064v1507 (64 bit report) ===
kernel32: sync.c:2894: Test failed: delete sync barrier failed
=== debian11 (32 bit ar:MA report) ===
kernel32: Unhandled exception: page fault on execute access to 0x005c0057 in 32-bit code (0x005c0057).
=== debian11 (32 bit zh:CN report) ===
kernel32: Unhandled exception: page fault on execute access to 0x005c0057 in 32-bit code (0x005c0057).
=== debian11b (32 bit WoW report) ===
kernel32: Unhandled exception: page fault on execute access to 0x005c0057 in wow64 32-bit code (0x005c0057).
This merge request was closed by quininer.
I've updated code, but I've lost interest in it for time being. anyone can continue this PR. sorry.