mirror of https://github.com/FreeRDP/FreeRDP
libwinpr-synch: add initial synchronization barrier implementation
This commit is contained in:
parent
fdab87cba0
commit
edde16e9d5
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -23,26 +23,237 @@
|
|||
|
||||
#include <winpr/synch.h>
|
||||
|
||||
/**
|
||||
* InitializeSynchronizationBarrier
|
||||
* EnterSynchronizationBarrier
|
||||
* DeleteSynchronizationBarrier
|
||||
*/
|
||||
#include "synch.h"
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#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 <winpr/library.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS
|
|||
TestSynchInit.c
|
||||
TestSynchEvent.c
|
||||
TestSynchMutex.c
|
||||
TestSynchBarrier.c
|
||||
TestSynchCritical.c
|
||||
TestSynchSemaphore.c
|
||||
TestSynchThread.c
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue