#ifndef __TBB_tbb_semaphore_H
#define __TBB_tbb_semaphore_H
#include "tbb/tbb_stddef.h"
#if _WIN32||_WIN64
#include "tbb/machine/windows_api.h"
#elif __APPLE__
#include <mach/semaphore.h>
#include <mach/task.h>
#include <mach/mach_init.h>
#include <mach/error.h>
#else
#include <semaphore.h>
#ifdef TBB_USE_DEBUG
#include <errno.h>
#endif
#endif
namespace tbb {
namespace internal {
#if _WIN32||_WIN64
typedef LONG sem_count_t;
class semaphore : no_copy {
static const int max_semaphore_cnt = MAXLONG;
public:
semaphore(size_t start_cnt_ = 0) {init_semaphore(start_cnt_);}
~semaphore() {CloseHandle( sem );}
void P() {WaitForSingleObjectEx( sem, INFINITE, FALSE );}
void V() {ReleaseSemaphore( sem, 1, NULL );}
private:
HANDLE sem;
void init_semaphore(size_t start_cnt_) {
sem = CreateSemaphoreEx( NULL, LONG(start_cnt_), max_semaphore_cnt, NULL, 0, SEMAPHORE_ALL_ACCESS );
}
};
#elif __APPLE__
class semaphore : no_copy {
public:
semaphore(int start_cnt_ = 0) : sem(start_cnt_) { init_semaphore(start_cnt_); }
~semaphore() {
kern_return_t ret = semaphore_destroy( mach_task_self(), sem );
__TBB_ASSERT_EX( ret==err_none, NULL );
}
void P() {
int ret;
do {
ret = semaphore_wait( sem );
} while( ret==KERN_ABORTED );
__TBB_ASSERT( ret==KERN_SUCCESS, "semaphore_wait() failed" );
}
void V() { semaphore_signal( sem ); }
private:
semaphore_t sem;
void init_semaphore(int start_cnt_) {
kern_return_t ret = semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, start_cnt_ );
__TBB_ASSERT_EX( ret==err_none, "failed to create a semaphore" );
}
};
#else
typedef uint32_t sem_count_t;
class semaphore : no_copy {
public:
semaphore(int start_cnt_ = 0 ) { init_semaphore( start_cnt_ ); }
~semaphore() {
int ret = sem_destroy( &sem );
__TBB_ASSERT_EX( !ret, NULL );
}
void P() {
while( sem_wait( &sem )!=0 )
__TBB_ASSERT( errno==EINTR, NULL );
}
void V() { sem_post( &sem ); }
private:
sem_t sem;
void init_semaphore(int start_cnt_) {
int ret = sem_init( &sem, 0, start_cnt_ );
__TBB_ASSERT_EX( !ret, NULL );
}
};
#endif
#if _WIN32||_WIN64
#if !__TBB_USE_SRWLOCK
class binary_semaphore : no_copy {
public:
binary_semaphore() { my_sem = CreateEventEx( NULL, NULL, 0, EVENT_ALL_ACCESS ); }
~binary_semaphore() { CloseHandle( my_sem ); }
void P() { WaitForSingleObjectEx( my_sem, INFINITE, FALSE ); }
void V() { SetEvent( my_sem ); }
private:
HANDLE my_sem;
};
#else
union srwl_or_handle {
SRWLOCK lock;
HANDLE h;
};
class binary_semaphore : no_copy {
public:
binary_semaphore();
~binary_semaphore();
void P();
void V();
private:
srwl_or_handle my_sem;
};
#endif
#elif __APPLE__
class binary_semaphore : no_copy {
public:
binary_semaphore() : my_sem(0) {
kern_return_t ret = semaphore_create( mach_task_self(), &my_sem, SYNC_POLICY_FIFO, 0 );
__TBB_ASSERT_EX( ret==err_none, "failed to create a semaphore" );
}
~binary_semaphore() {
kern_return_t ret = semaphore_destroy( mach_task_self(), my_sem );
__TBB_ASSERT_EX( ret==err_none, NULL );
}
void P() {
int ret;
do {
ret = semaphore_wait( my_sem );
} while( ret==KERN_ABORTED );
__TBB_ASSERT( ret==KERN_SUCCESS, "semaphore_wait() failed" );
}
void V() { semaphore_signal( my_sem ); }
private:
semaphore_t my_sem;
};
#else
#if __TBB_USE_FUTEX
class binary_semaphore : no_copy {
public:
binary_semaphore() { my_sem = 1; }
~binary_semaphore() {}
void P() {
int s;
if( (s = my_sem.compare_and_swap( 1, 0 ))!=0 ) {
if( s!=2 )
s = my_sem.fetch_and_store( 2 );
while( s!=0 ) {
futex_wait( &my_sem, 2 );
s = my_sem.fetch_and_store( 2 );
}
}
}
void V() {
__TBB_ASSERT( my_sem>=1, "multiple V()'s in a row?" );
if( my_sem--!=1 ) {
my_sem = 0;
futex_wakeup_one( &my_sem );
}
}
private:
atomic<int> my_sem;
};
#else
typedef uint32_t sem_count_t;
class binary_semaphore : no_copy {
public:
binary_semaphore() {
int ret = sem_init( &my_sem, 0, 0 );
__TBB_ASSERT_EX( !ret, NULL );
}
~binary_semaphore() {
int ret = sem_destroy( &my_sem );
__TBB_ASSERT_EX( !ret, NULL );
}
void P() {
while( sem_wait( &my_sem )!=0 )
__TBB_ASSERT( errno==EINTR, NULL );
}
void V() { sem_post( &my_sem ); }
private:
sem_t my_sem;
};
#endif
#endif
}
}
#endif