diff --git a/winpr/include/winpr/synch.h b/winpr/include/winpr/synch.h index 04f4268e4..88e37457e 100644 --- a/winpr/include/winpr/synch.h +++ b/winpr/include/winpr/synch.h @@ -162,15 +162,6 @@ WINPR_API VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection); WINPR_API VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection); -/* Synchronization Barrier */ - -typedef PVOID RTL_SYNCHRONIZATION_BARRIER; -typedef RTL_SYNCHRONIZATION_BARRIER SYNCHRONIZATION_BARRIER, *PSYNCHRONIZATION_BARRIER, *LPSYNCHRONIZATION_BARRIER; - -WINPR_API BOOL InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); -WINPR_API BOOL EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); -WINPR_API BOOL DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); - /* Sleep */ WINPR_API VOID Sleep(DWORD dwMilliseconds); @@ -313,6 +304,33 @@ WINPR_API VOID InitOnceInitialize(PINIT_ONCE InitOnce); #endif +/* Synchronization Barrier */ + +#if (!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) + +typedef struct _RTL_BARRIER +{ + DWORD Reserved1; + DWORD Reserved2; + ULONG_PTR Reserved3[2]; + DWORD Reserved4; + DWORD Reserved5; +} RTL_BARRIER, *PRTL_BARRIER; + +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 + +WINPR_API BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); +WINPR_API BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); +WINPR_API BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); + +#endif + /* Extended API */ WINPR_API VOID USleep(DWORD dwMicroseconds); diff --git a/winpr/libwinpr/handle/handle.h b/winpr/libwinpr/handle/handle.h index 819e7b3db..91a3e9452 100644 --- a/winpr/libwinpr/handle/handle.h +++ b/winpr/libwinpr/handle/handle.h @@ -50,7 +50,7 @@ typedef struct winpr_handle WINPR_HANDLE; #define WINPR_HANDLE_SET_TYPE(_handle, _type) \ _handle->Type = _type -static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObject) +static INLINE BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObject) { WINPR_HANDLE* wHandle; @@ -65,7 +65,6 @@ static inline BOOL winpr_Handle_GetInfo(HANDLE handle, ULONG* pType, PVOID* pObj return TRUE; } - typedef BOOL (*pcIsHandled)(HANDLE handle); typedef BOOL (*pcCloseHandle)(HANDLE handle); diff --git a/winpr/libwinpr/synch/barrier.c b/winpr/libwinpr/synch/barrier.c index 95fef076c..c56bfbee7 100644 --- a/winpr/libwinpr/synch/barrier.c +++ b/winpr/libwinpr/synch/barrier.c @@ -23,26 +23,237 @@ #include -/** - * InitializeSynchronizationBarrier - * EnterSynchronizationBarrier - * DeleteSynchronizationBarrier - */ +#include "synch.h" + +#include #ifndef _WIN32 -BOOL InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount) +BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount) { + int status; + WINPR_BARRIER* pBarrier; + + if (!lpBarrier) + return FALSE; + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); + + pBarrier = (WINPR_BARRIER*) calloc(1, sizeof(WINPR_BARRIER)); + + if (!pBarrier) + return FALSE; + + if (lSpinCount < 0) + lSpinCount = 2000; + + pBarrier->lTotalThreads = lTotalThreads; + pBarrier->lSpinCount = lSpinCount; + + status = pthread_barrier_init(&(pBarrier->barrier), NULL, pBarrier->lTotalThreads); + + if (status != 0) + { + free(pBarrier); + return FALSE; + } + + lpBarrier->Reserved3[0] = (ULONG_PTR) pBarrier; + return TRUE; } -BOOL EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags) +BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags) { + BOOL status; + int waitStatus; + WINPR_BARRIER* pBarrier; + + if (!lpBarrier) + return FALSE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return FALSE; + + waitStatus = pthread_barrier_wait(&(pBarrier->barrier)); + + if (waitStatus == 0) + { + status = FALSE; /* success, this is not the last thread */ + } + else if (waitStatus == PTHREAD_BARRIER_SERIAL_THREAD) + { + status = TRUE; /* success, this is the last thread */ + } + else + { + status = FALSE; /* failure */ + } + + return status; +} + +BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier) +{ + WINPR_BARRIER* pBarrier; + + /** + * According to MSDN, DeleteSynchronizationBarrier always returns TRUE + */ + + if (!lpBarrier) + return TRUE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return TRUE; + + pthread_barrier_destroy(&(pBarrier->barrier)); + + free(pBarrier); + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); + return TRUE; } -BOOL DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier) +#elif (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) + +#include +#include + +static HMODULE g_Kernel32 = NULL; +static BOOL g_NativeBarrier = FALSE; +static INIT_ONCE g_InitOnce = INIT_ONCE_STATIC_INIT; + +typedef BOOL (WINAPI * fnInitializeSynchronizationBarrier)(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount); +typedef BOOL (WINAPI * fnEnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags); +typedef BOOL (WINAPI * fnDeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier); + +static fnInitializeSynchronizationBarrier pfnInitializeSynchronizationBarrier = NULL; +static fnEnterSynchronizationBarrier pfnEnterSynchronizationBarrier = NULL; +static fnDeleteSynchronizationBarrier pfnDeleteSynchronizationBarrier = NULL; + +static BOOL CALLBACK InitOnce_Barrier(PINIT_ONCE once, PVOID param, PVOID *context) { + g_Kernel32 = LoadLibraryA("kernel32.dll"); + + if (!g_Kernel32) + return TRUE; + + pfnInitializeSynchronizationBarrier = (fnInitializeSynchronizationBarrier) + GetProcAddress(g_Kernel32, "InitializeSynchronizationBarrier"); + + pfnEnterSynchronizationBarrier = (fnEnterSynchronizationBarrier) + GetProcAddress(g_Kernel32, "EnterSynchronizationBarrier"); + + pfnDeleteSynchronizationBarrier = (fnDeleteSynchronizationBarrier) + GetProcAddress(g_Kernel32, "DeleteSynchronizationBarrier"); + + if (pfnInitializeSynchronizationBarrier && pfnEnterSynchronizationBarrier + && pfnDeleteSynchronizationBarrier) + { + g_NativeBarrier = TRUE; + } + + return TRUE; +} + +BOOL WINAPI InitializeSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, LONG lTotalThreads, LONG lSpinCount) +{ + WINPR_BARRIER* pBarrier; + + InitOnceExecuteOnce(&g_InitOnce, InitOnce_Barrier, NULL, NULL); + + if (g_NativeBarrier) + return pfnInitializeSynchronizationBarrier(lpBarrier, lTotalThreads, lSpinCount); + + if (!lpBarrier) + return FALSE; + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); + + pBarrier = (WINPR_BARRIER*) calloc(1, sizeof(WINPR_BARRIER)); + + if (!pBarrier) + return FALSE; + + if (lSpinCount < 0) + lSpinCount = 2000; + + pBarrier->lTotalThreads = lTotalThreads; + pBarrier->lSpinCount = lSpinCount; + pBarrier->count = 0; + + pBarrier->event = CreateEvent(NULL, TRUE, FALSE, NULL); + + if (!pBarrier->event) + { + free(pBarrier); + return FALSE; + } + + lpBarrier->Reserved3[0] = (ULONG_PTR) pBarrier; + + return TRUE; +} + +BOOL WINAPI EnterSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier, DWORD dwFlags) +{ + LONG count; + BOOL status = FALSE; + WINPR_BARRIER* pBarrier; + + if (g_NativeBarrier) + return pfnEnterSynchronizationBarrier(lpBarrier, dwFlags); + + if (!lpBarrier) + return FALSE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return FALSE; + + count = InterlockedIncrement(&(pBarrier->count)); + + if (count < pBarrier->lTotalThreads) + { + WaitForSingleObject(pBarrier->event, INFINITE); + } + else + { + SetEvent(pBarrier->event); + status = TRUE; + } + + return status; +} + +BOOL WINAPI DeleteSynchronizationBarrier(LPSYNCHRONIZATION_BARRIER lpBarrier) +{ + WINPR_BARRIER* pBarrier; + + if (g_NativeBarrier) + return pfnDeleteSynchronizationBarrier(lpBarrier); + + if (!lpBarrier) + return TRUE; + + pBarrier = (WINPR_BARRIER*) lpBarrier->Reserved3[0]; + + if (!pBarrier) + return TRUE; + + CloseHandle(pBarrier->event); + + free(pBarrier); + + ZeroMemory(lpBarrier, sizeof(SYNCHRONIZATION_BARRIER)); + return TRUE; } diff --git a/winpr/libwinpr/synch/synch.h b/winpr/libwinpr/synch/synch.h index fbde1d4a8..919255413 100644 --- a/winpr/libwinpr/synch/synch.h +++ b/winpr/libwinpr/synch/synch.h @@ -32,10 +32,10 @@ #define WITH_POSIX_TIMER 1 #endif -#ifndef _WIN32 - #include "../handle/handle.h" +#ifndef _WIN32 + #define WINPR_PIPE_SEMAPHORE 1 #if defined __APPLE__ @@ -144,4 +144,18 @@ struct winpr_timer_queue_timer #endif +struct winpr_barrier +{ + LONG lTotalThreads; + LONG lSpinCount; + +#if !defined(_WIN32) + pthread_barrier_t barrier; +#elif (defined(_WIN32) && (_WIN32_WINNT < 0x0602)) + HANDLE event; + DECLSPEC_ALIGN(4) LONG count; +#endif +}; +typedef struct winpr_barrier WINPR_BARRIER; + #endif /* WINPR_SYNCH_PRIVATE_H */ diff --git a/winpr/libwinpr/synch/test/CMakeLists.txt b/winpr/libwinpr/synch/test/CMakeLists.txt index 0309fb910..68b76faa0 100644 --- a/winpr/libwinpr/synch/test/CMakeLists.txt +++ b/winpr/libwinpr/synch/test/CMakeLists.txt @@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS TestSynchInit.c TestSynchEvent.c TestSynchMutex.c + TestSynchBarrier.c TestSynchCritical.c TestSynchSemaphore.c TestSynchThread.c diff --git a/winpr/libwinpr/synch/test/TestSynchBarrier.c b/winpr/libwinpr/synch/test/TestSynchBarrier.c new file mode 100644 index 000000000..ebdcc7c6e --- /dev/null +++ b/winpr/libwinpr/synch/test/TestSynchBarrier.c @@ -0,0 +1,72 @@ + +#include +#include +#include + +static int g_Count; +static HANDLE g_Event; +static CRITICAL_SECTION g_Lock; +static SYNCHRONIZATION_BARRIER g_Barrier; + +static void* test_synch_barrier_thread_func(void* arg) +{ + BOOL status; + + status = EnterSynchronizationBarrier(&g_Barrier, 0); + + EnterCriticalSection(&g_Lock); + + printf("Thread #%d status: %s\n", g_Count++, + status ? "TRUE" : "FALSE"); + + LeaveCriticalSection(&g_Lock); + + if (status) + { + SetEvent(g_Event); + } + + return NULL; +} + +int TestSynchBarrier(int argc, char* argv[]) +{ + int index; + HANDLE threads[5]; + + g_Count = 0; + + g_Event = CreateEvent(NULL, TRUE, FALSE, NULL); + + InitializeCriticalSectionAndSpinCount(&g_Lock, 4000); + + if (!InitializeSynchronizationBarrier(&g_Barrier, 5, -1)) + return -1; + + for (index = 0; index < 5; index++) + { + threads[index] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) + test_synch_barrier_thread_func, NULL, 0, NULL); + } + + WaitForSingleObject(g_Event, INFINITE); + + if (g_Count != 5) + return -1; + + printf("All threads have reached the barrier\n"); + + for (index = 0; index < 5; index++) + { + CloseHandle(threads[index]); + } + + DeleteSynchronizationBarrier(&g_Barrier); + + DeleteCriticalSection(&g_Lock); + + CloseHandle(g_Event); + + return 0; +} +