commit 2a895e681beb2b2cba66c6a69953867b8cf16a5b parent 2bc43ba669eab4e630ef645fe1228c1c9c9689cb Author: Michael Savage <mikejsavage@gmail.com> Date: Sat Apr 1 19:38:23 +0300 Add optimised Semaphore and semaphore_destroy Diffstat:
darwin_semaphore.h | | | 16 | ++++++++++++---- |
platform_semaphore.h | | | 31 | +++++++++++++++++++++++++++++++ |
unix_semaphore.h | | | 34 | +++++++++++++++++++++++++--------- |
win32_semaphore.h | | | 20 | +++++++++++++------- |
diff --git a/darwin_semaphore.h b/darwin_semaphore.h @@ -2,18 +2,26 @@ #include <dispatch/dispatch.h> -struct Semaphore { +struct PlatformSemaphore { dispatch_semaphore_t sem; }; -inline void semaphore_init( Semaphore * sem ) { +inline void platform_semaphore_init( PlatformSemaphore * sem ) { sem->sem = dispatch_semaphore_create( 0 ); + if( sem->sem == NULL ) { + FATAL( "dispatch_semaphore_create" ); + } } -inline void semaphore_signal( Semaphore * sem ) { +inline void platform_semaphore_signal( PlatformSemaphore * sem ) { dispatch_semaphore_signal( sem->sem ); } -inline void semaphore_wait( Semaphore * sem ) { +inline void platform_semaphore_wait( PlatformSemaphore * sem ) { dispatch_semaphore_wait( sem->sem, DISPATCH_TIME_FOREVER ); } + +inline void platform_semaphore_destroy( PlatformSemaphore * sem ) { + // TODO: might need a cast to dispatch_object_t + dispatch_release( sem->sem ); +} diff --git a/platform_semaphore.h b/platform_semaphore.h @@ -1,6 +1,7 @@ #pragma once #include "platform.h" +#include "platform_atomic.h" #if PLATFORM_WINDOWS #include "win32_semaphore.h" @@ -11,3 +12,33 @@ #else #error new platform #endif + +struct Semaphore { + PlatformSemaphore sem; + // when n < 0, n = - number of waiting threads + // when n >= 0, n = number of tasks remaining + atomic_s32 n; +}; + +inline void semaphore_init( Semaphore * sem ) { + platform_semaphore_init( &sem->sem ); + store_release( &sem->n, 0 ); +} + +inline void semaphore_signal( Semaphore * sem ) { + // if n was < 0, wake up a waiting thread + if( fetch_add_acqrel( &sem->n, 1 ) < 0 ) { + platform_semaphore_signal( &sem->sem ); + } +} + +inline void semaphore_wait( Semaphore * sem ) { + // if n is now < 0, put this thread to sleep + if( fetch_add_acqrel( &sem->n, -1 ) <= 0 ) { + platform_semaphore_wait( &sem->sem ); + } +} + +inline void semaphore_destroy( Semaphore * sem ) { + platform_semaphore_destroy( &sem->sem ); +} diff --git a/unix_semaphore.h b/unix_semaphore.h @@ -1,23 +1,39 @@ #pragma once -#include <err.h> #include <semaphore.h> -struct Semaphore { +#include "log.h" + +struct PlatformSemaphore { sem_t sem; }; -inline void semaphore_init( Semaphore * sem ) { +inline void platform_semaphore_init( PlatformSemaphore * sem ) { int ok = sem_init( &sem->sem, 0, 0 ); - if( ok == -1 ) { - err( 1, "sem_init failed" ); + if( ok != 0 ) { + FATAL( "sem_init" ); + } +} + +inline void platform_semaphore_signal( PlatformSemaphore * sem ) { + int ok = sem_post( &sem->sem ); + if( ok != 0 && errno != EOVERFLOW ) { + FATAL( "sem_post" ); } } -inline void semaphore_signal( Semaphore * sem ) { - sem_post( &sem->sem ); +inline void platform_semaphore_wait( PlatformSemaphore * sem ) { + while( true ) { + int ok = sem_wait( &sem->sem ); + if( ok == 0 ) break; + if( errno == EINTR ) continue; + FATAL( "sem_wait" ); + } } -inline void semaphore_wait( Semaphore * sem ) { - sem_wait( &sem->sem ); +inline void platform_semaphore_destroy( PlatformSemaphore * sem ) { + int ok = sem_destroy( &sem->sem ); + if( ok != 0 ) { + FATAL( "sem_destroy" ); + } } diff --git a/win32_semaphore.h b/win32_semaphore.h @@ -4,31 +4,37 @@ #include "log.h" -struct Semaphore { +struct PlatformSemaphore { HANDLE sem; }; -inline void semaphore_init( Semaphore * sem ) { +inline void platform_semaphore_init( PlatformSemaphore * sem ) { LONG max = 1024; // TODO sem->sem = CreateSemaphore( NULL, 0, max, NULL ); if( sem->sem == NULL ) { - FATAL( "CreateSemaphore failed" ); + FATAL( "CreateSemaphore" ); } } -inline void semaphore_signal( Semaphore * sem ) { +inline void platform_semaphore_signal( PlatformSemaphore * sem ) { if( ReleaseSemaphore( sem->sem, 1, NULL ) == 0 ) { DWORD error = GetLastError(); if( error == ERROR_TOO_MANY_POSTS ) { return; } - FATAL( "ReleaseSemaphore failed" ); + FATAL( "ReleaseSemaphore" ); } } -inline void semaphore_wait( Semaphore * sem ) { +inline void platform_semaphore_wait( PlatformSemaphore * sem ) { if( WaitForSingleObject( sem->sem, INFINITE ) == WAIT_FAILED ) { - FATAL( "WaitForSingleObject failed" ); + FATAL( "WaitForSingleObject" ); + } +} + +inline void platform_semaphore_destroy( PlatformSemaphore * sem ) { + if( CloseHandle( sem->sem ) == NULL ) { + FATAL( "CloseHandle" ); } }