libwinpr-synch: add initial synchronization barrier implementation

This commit is contained in:
Marc-André Moreau 2014-08-08 17:34:30 -04:00
parent fdab87cba0
commit edde16e9d5
6 changed files with 336 additions and 21 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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 */

View File

@ -8,6 +8,7 @@ set(${MODULE_PREFIX}_TESTS
TestSynchInit.c
TestSynchEvent.c
TestSynchMutex.c
TestSynchBarrier.c
TestSynchCritical.c
TestSynchSemaphore.c
TestSynchThread.c

View File

@ -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;
}