Add initial implementation of threads/mutexes/semaphores/cvs/spinlocks
Added initial implementation (or wrapper) of the threading library. It's rather basic, but should work for most of the tasks. Unfortunately, spinlock implementation relies on GCC/Clang compiler built-ins (or in-worst-case-scenario on Win32 - InterlockExchange). In the future, I should revisit this code and fix/reimplement some stuff (or add support for Windows XP).
This commit is contained in:
@@ -51,6 +51,7 @@ set(ENABLE_TESTING ON CACHE BOOL "Enable unit-testing")
|
||||
set(ENABLE_COVERAGE OFF CACHE BOOL "Enable coverage")
|
||||
set(ENABLE_EXAMPLES ON CACHE BOOL "Enable building examples")
|
||||
set(ENABLE_LTO ON CACHE BOOL "Enable LTO support")
|
||||
set(ENABLE_MT ON CACHE BOOL "Enable multithreading support")
|
||||
|
||||
# Enable IPO/LTO
|
||||
if(ENABLE_LTO)
|
||||
@@ -102,6 +103,57 @@ set(BH_HEADER
|
||||
include/BH/Math.h
|
||||
include/BH/Queue.h
|
||||
include/BH/Util.h
|
||||
include/BH/Thread.h
|
||||
)
|
||||
|
||||
set(BH_SOURCE_DUMMY
|
||||
src/Platform/Dummy/File.c
|
||||
)
|
||||
|
||||
set(BH_SOURCE_WIN32
|
||||
src/Platform/Win32/File.c
|
||||
)
|
||||
|
||||
set(BH_SOURCE_POSIX
|
||||
src/Platform/Posix/File.c
|
||||
)
|
||||
|
||||
set(BH_SOURCE_WIN32_MT
|
||||
src/Platform/Win32/Condition.c
|
||||
src/Platform/Win32/Mutex.c
|
||||
src/Platform/Win32/Semaphore.c
|
||||
src/Platform/Win32/Thread.c
|
||||
src/Platform/Win32/Tss.c
|
||||
src/Platform/Spinlock.c
|
||||
)
|
||||
|
||||
set(BH_HEADER_WIN32_MT
|
||||
src/Platform/Win32/Thread.h
|
||||
)
|
||||
|
||||
set(BH_SOURCE_POSIX_MT
|
||||
src/Platform/Posix/Condition.c
|
||||
src/Platform/Posix/Mutex.c
|
||||
src/Platform/Posix/Semaphore.c
|
||||
src/Platform/Posix/Thread.c
|
||||
src/Platform/Posix/Tss.c
|
||||
src/Platform/Spinlock.c
|
||||
)
|
||||
|
||||
set(BH_HEADER_POSIX_MT
|
||||
src/Platform/Posix/Thread.h
|
||||
)
|
||||
|
||||
set(BH_SOURCE_DUMMY_MT
|
||||
src/Platform/Dummy/Condition.c
|
||||
src/Platform/Dummy/Mutex.c
|
||||
src/Platform/Dummy/Semaphore.c
|
||||
src/Platform/Dummy/Thread.c
|
||||
src/Platform/Dummy/Tss.c
|
||||
)
|
||||
|
||||
set(BH_HEADER_DUMMY_MT
|
||||
src/Platform/Dummy/Thread.h
|
||||
)
|
||||
|
||||
set(BH_INCLUDE_DIRS
|
||||
@@ -114,23 +166,36 @@ if(WIN32)
|
||||
message(STATUS "Platform - Win32")
|
||||
|
||||
# Add platform dependent files
|
||||
list(APPEND BH_SOURCE
|
||||
src/Platform/Win32/File.c
|
||||
)
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_WIN32})
|
||||
|
||||
# Add platform dependent multithreading support
|
||||
if(ENABLE_MT)
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_WIN32_MT})
|
||||
list(APPEND BH_HEADER ${BH_HEADER_WIN32_MT})
|
||||
else()
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_DUMMY_MT})
|
||||
list(APPEND BH_HEADER ${BH_HEADER_DUMMY_MT})
|
||||
endif()
|
||||
elseif(UNIX)
|
||||
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
|
||||
|
||||
# Add platform dependent files
|
||||
list(APPEND BH_SOURCE
|
||||
src/Platform/Posix/File.c
|
||||
)
|
||||
list(APPEND BH_SOURCE BH_SOURCE_POSIX)
|
||||
|
||||
# Add platform dependent multithreading support
|
||||
if(ENABLE_MT)
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_POSIX_MT})
|
||||
list(APPEND BH_HEADER ${BH_HEADER_POSIX_MT})
|
||||
else()
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_POSIX_MT})
|
||||
list(APPEND BH_HEADER ${BH_HEADER_POSIX_MT})
|
||||
endif()
|
||||
else()
|
||||
message(STATUS "Platform: Unknown")
|
||||
|
||||
# Add platform dependent files
|
||||
list(APPEND BH_SOURCE
|
||||
src/Platform/Dummy/File.c
|
||||
)
|
||||
list(APPEND BH_SOURCE ${BH_SOURCE_DUMMY} ${BH_SOURCE_DUMMY_MT})
|
||||
list(APPEND BH_HEADER ${BH_HEADER_DUMMY_MT})
|
||||
endif()
|
||||
|
||||
# Library
|
||||
|
||||
302
include/BH/Thread.h
Normal file
302
include/BH/Thread.h
Normal file
@@ -0,0 +1,302 @@
|
||||
#ifndef BH_THREAD_H
|
||||
#define BH_THREAD_H
|
||||
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
|
||||
#define BH_MAX_TSS 128
|
||||
|
||||
|
||||
typedef struct BH_Lock BH_Lock;
|
||||
typedef struct BH_Thread BH_Thread;
|
||||
typedef struct BH_Mutex BH_Mutex;
|
||||
typedef struct BH_Semaphore BH_Semaphore;
|
||||
typedef struct BH_Condition BH_Condition;
|
||||
typedef int (*BH_ThreadCallback)(void *);
|
||||
|
||||
|
||||
/**
|
||||
* Creates new thread with specified \a stack size, thread \a callback
|
||||
* function and \a data.
|
||||
*
|
||||
* \param stack Stack size
|
||||
* \param callback Callback function
|
||||
* \param data User data
|
||||
*
|
||||
* \return On success, returns thread pointer.
|
||||
* \return On failure, returns NULL pointer.
|
||||
*/
|
||||
BH_Thread *BH_ThreadNew(size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data);
|
||||
|
||||
|
||||
/**
|
||||
* Joins the specified \a thread.
|
||||
*
|
||||
* \param thread Thread
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ThreadJoin(BH_Thread *thread);
|
||||
|
||||
|
||||
/**
|
||||
* Detaches the specified \a thread.
|
||||
*
|
||||
* \param thread Thread
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ThreadDetach(BH_Thread *thread);
|
||||
|
||||
|
||||
/**
|
||||
* Creates new mutex.
|
||||
*
|
||||
* \return On success, returns mutex pointer.
|
||||
* \return On failure, returns NULL pointer.
|
||||
*/
|
||||
BH_Mutex *BH_MutexNew(void);
|
||||
|
||||
|
||||
/**
|
||||
* Frees the \a mutex.
|
||||
*
|
||||
* \param mutex Mutex
|
||||
*/
|
||||
void BH_MutexFree(BH_Mutex *mutex);
|
||||
|
||||
|
||||
/**
|
||||
* Locks the \a mutex.
|
||||
*
|
||||
* \param mutex Mutex
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_MutexLock(BH_Mutex *mutex);
|
||||
|
||||
|
||||
/**
|
||||
* Unlocks the \a mutex.
|
||||
*
|
||||
* \param mutex Mutex
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_MutexUnlock(BH_Mutex *mutex);
|
||||
|
||||
|
||||
/**
|
||||
* Tries to lock the \a mutex.
|
||||
*
|
||||
* \param mutex Mutex
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_MutexLockTry(BH_Mutex *mutex);
|
||||
|
||||
|
||||
/**
|
||||
* Creates new semaphore.
|
||||
*
|
||||
* \param value Semaphore value
|
||||
*
|
||||
* \return On success, returns thread pointer.
|
||||
* \return On failure, returns NULL pointer.
|
||||
*/
|
||||
BH_Semaphore *BH_SemaphoreNew(int value);
|
||||
|
||||
|
||||
/**
|
||||
* Frees the \a semaphore.
|
||||
*
|
||||
* \param semaphore Semaphore
|
||||
*/
|
||||
void BH_SemaphoreFree(BH_Semaphore *semaphore);
|
||||
|
||||
|
||||
/**
|
||||
* Posts/increments the \a semaphore.
|
||||
*
|
||||
* \param semaphore Semaphore
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_SemaphorePost(BH_Semaphore *semaphore);
|
||||
|
||||
|
||||
/**
|
||||
* Waits/decrements the \a semaphore.
|
||||
*
|
||||
* \param semaphore Semaphore
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_SemaphoreWait(BH_Semaphore *semaphore);
|
||||
|
||||
|
||||
/**
|
||||
* Tries to wait/decrement the \a semaphore.
|
||||
*
|
||||
* \param semaphore Semaphore
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_SemaphoreWaitTry(BH_Semaphore *semaphore);
|
||||
|
||||
|
||||
/**
|
||||
* Waits/decrements the \a semaphore with \a timeout.
|
||||
*
|
||||
* If timeout occures, return code will be BH_TIMEOUT.
|
||||
*
|
||||
* \param semaphore Semaphore
|
||||
* \param timeout Timeout in milliseconds
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_SemaphoreWaitFor(BH_Semaphore *semaphore,
|
||||
uint32_t timeout);
|
||||
|
||||
|
||||
/**
|
||||
* Creates new condition variable.
|
||||
*
|
||||
* \return On success, returns condition variable pointer.
|
||||
* \return On failure, returns NULL pointer.
|
||||
*/
|
||||
BH_Condition *BH_ConditionNew(void);
|
||||
|
||||
|
||||
/**
|
||||
* Frees the \a condition variable.
|
||||
*
|
||||
* \param condition Condition
|
||||
*/
|
||||
void BH_ConditionFree(BH_Condition *condition);
|
||||
|
||||
|
||||
/**
|
||||
* Unlocks the \a mutex and waits for the \a condition variable.
|
||||
*
|
||||
* \param condition Condition variable
|
||||
* \param mutex Mutex
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ConditionWait(BH_Condition *condition,
|
||||
BH_Mutex *mutex);
|
||||
|
||||
|
||||
/**
|
||||
* Unlocks the \a mutex and waits for the \a condition variable with \a timeout.
|
||||
*
|
||||
* If timeout occures, return code will be BH_TIMEOUT.
|
||||
*
|
||||
* \param condition Condition variable
|
||||
* \param mutex Mutex
|
||||
* \param timeout Timeout in milliseconds
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ConditionWaitFor(BH_Condition *condition,
|
||||
BH_Mutex *mutex,
|
||||
uint32_t timeout);
|
||||
|
||||
|
||||
/**
|
||||
* Signals the \a condition variable.
|
||||
*
|
||||
* \param condition Condition variable
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ConditionSignal(BH_Condition *condition);
|
||||
|
||||
|
||||
/**
|
||||
* Broadcasts the \a condition variable.
|
||||
*
|
||||
* \param condition Condition variable
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_ConditionBroadcast(BH_Condition *condition);
|
||||
|
||||
|
||||
/**
|
||||
* Locks the \a spinlock.
|
||||
*
|
||||
* \param lock Spinlock
|
||||
*/
|
||||
void BH_SpinlockLock(int *lock);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tries to lock the \a spinlock.
|
||||
*
|
||||
* \param lock Spinlock
|
||||
*
|
||||
* \return On success, returns zero.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_SpinlockLockTry(int *lock);
|
||||
|
||||
|
||||
/**
|
||||
* Unlocks the \a spinlock.
|
||||
*
|
||||
* \param lock Spinlock
|
||||
*/
|
||||
void BH_SpinlockUnlock(int *lock);
|
||||
|
||||
|
||||
/**
|
||||
* Create new TSS/TLS slot index and destruction \a callback.
|
||||
*
|
||||
* \param callback Destruction callback
|
||||
*
|
||||
* \return On success, returns slot index.
|
||||
* \return On failure, returns error code.
|
||||
*/
|
||||
int BH_TssCreate(BH_GenericCallback callback);
|
||||
|
||||
|
||||
/**
|
||||
* Reads the value associated with the TSS \a index.
|
||||
*
|
||||
* \param index TSS index
|
||||
*
|
||||
* \return Index value
|
||||
*/
|
||||
void *BH_TssRead(int index);
|
||||
|
||||
|
||||
/**
|
||||
* Writes the \a value to the TSS \a index.
|
||||
*
|
||||
* \param index TSS index to
|
||||
* \param value Value
|
||||
*/
|
||||
void BH_TssWrite(int index,
|
||||
void *value);
|
||||
|
||||
|
||||
#endif /* BH_THREAD_H */
|
||||
53
src/Platform/Dummy/Condition.c
Normal file
53
src/Platform/Dummy/Condition.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Condition *BH_ConditionNew(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void BH_ConditionFree(BH_Condition *condition)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWait(BH_Condition *condition,
|
||||
BH_Mutex *mutex)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
BH_UNUSED(mutex);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWaitFor(BH_Condition *condition,
|
||||
BH_Mutex *mutex,
|
||||
uint32_t timeout)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
BH_UNUSED(mutex);
|
||||
BH_UNUSED(timeout);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionSignal(BH_Condition *condition)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionBroadcast(BH_Condition *condition)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
39
src/Platform/Dummy/Mutex.c
Normal file
39
src/Platform/Dummy/Mutex.c
Normal file
@@ -0,0 +1,39 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Mutex *BH_MutexNew(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void BH_MutexFree(BH_Mutex *mutex)
|
||||
{
|
||||
BH_UNUSED(mutex);
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLock(BH_Mutex *mutex)
|
||||
{
|
||||
BH_UNUSED(mutex);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexUnlock(BH_Mutex *mutex)
|
||||
{
|
||||
BH_UNUSED(mutex);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLockTry(BH_Mutex *mutex)
|
||||
{
|
||||
BH_UNUSED(mutex);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
51
src/Platform/Dummy/Semaphore.c
Normal file
51
src/Platform/Dummy/Semaphore.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Semaphore *BH_SemaphoreNew(int value)
|
||||
{
|
||||
BH_UNUSED(value);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void BH_SemaphoreFree(BH_Semaphore *semaphore)
|
||||
{
|
||||
BH_UNUSED(semaphore);
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphorePost(BH_Semaphore *semaphore)
|
||||
{
|
||||
BH_UNUSED(semaphore);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWait(BH_Semaphore *semaphore)
|
||||
{
|
||||
BH_UNUSED(semaphore);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitTry(BH_Semaphore *semaphore)
|
||||
{
|
||||
BH_UNUSED(semaphore);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitFor(BH_Semaphore *semaphore,
|
||||
uint32_t timeout)
|
||||
{
|
||||
BH_UNUSED(semaphore);
|
||||
BH_UNUSED(timeout);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
31
src/Platform/Dummy/Thread.c
Normal file
31
src/Platform/Dummy/Thread.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Thread *BH_ThreadNew(size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data)
|
||||
{
|
||||
BH_UNUSED(stack);
|
||||
BH_UNUSED(callback);
|
||||
BH_UNUSED(data);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadJoin(BH_Thread *thread)
|
||||
{
|
||||
BH_UNUSED(thread);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadDetach(BH_Thread *thread)
|
||||
{
|
||||
BH_UNUSED(thread);
|
||||
|
||||
return BH_NOIMPL;
|
||||
}
|
||||
33
src/Platform/Dummy/Thread.h
Normal file
33
src/Platform/Dummy/Thread.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef BH_PLATFORM_DUMMY_THREAD_H
|
||||
#define BH_PLATFORM_DUMMY_THREAD_H
|
||||
|
||||
|
||||
struct BH_Condition
|
||||
{
|
||||
int implement;
|
||||
int me;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Mutex
|
||||
{
|
||||
int implement;
|
||||
int me;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Semaphore
|
||||
{
|
||||
int implement;
|
||||
int me;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Thread
|
||||
{
|
||||
int implement;
|
||||
int me;
|
||||
};
|
||||
|
||||
|
||||
#endif /* BH_PLATFORM_DUMMY_THREAD_H */
|
||||
24
src/Platform/Dummy/Tss.c
Normal file
24
src/Platform/Dummy/Tss.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
int BH_TssCreate(BH_GenericCallback callback)
|
||||
{
|
||||
|
||||
BH_UNUSED(callback);
|
||||
}
|
||||
|
||||
|
||||
void *BH_TssRead(int index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void BH_TssWrite(int index,
|
||||
void *value)
|
||||
{
|
||||
BH_UNUSED(index);
|
||||
BH_UNUSED(value);
|
||||
}
|
||||
74
src/Platform/Posix/Condition.c
Normal file
74
src/Platform/Posix/Condition.c
Normal file
@@ -0,0 +1,74 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
BH_Condition *BH_ConditionNew(void)
|
||||
{
|
||||
BH_Condition *condition;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
condition = malloc(sizeof(BH_Condition));
|
||||
if (condition && pthread_cond_init(&condition->handle, NULL))
|
||||
{
|
||||
free(condition);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
|
||||
void BH_ConditionFree(BH_Condition *condition)
|
||||
{
|
||||
pthread_cond_destroy(&condition->handle);
|
||||
free(condition);
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWait(BH_Condition *condition,
|
||||
BH_Mutex *mutex)
|
||||
{
|
||||
if (pthread_cond_wait(&condition->handle, &mutex->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWaitFor(BH_Condition *condition,
|
||||
BH_Mutex *mutex,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
|
||||
|
||||
switch (pthread_cond_timedwait(&condition->handle, &mutex->handle, &ts))
|
||||
{
|
||||
case 0: return BH_OK;
|
||||
case ETIMEDOUT: return BH_TIMEOUT;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionSignal(BH_Condition *condition)
|
||||
{
|
||||
if (pthread_cond_signal(&condition->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionBroadcast(BH_Condition *condition)
|
||||
{
|
||||
if (pthread_cond_broadcast(&condition->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
57
src/Platform/Posix/Mutex.c
Normal file
57
src/Platform/Posix/Mutex.c
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
BH_Mutex *BH_MutexNew(void)
|
||||
{
|
||||
BH_Mutex *mutex;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
mutex = malloc(sizeof(BH_Mutex));
|
||||
if (mutex && pthread_mutex_init(&mutex->handle, NULL))
|
||||
{
|
||||
free(mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
||||
void BH_MutexFree(BH_Mutex *mutex)
|
||||
{
|
||||
pthread_mutex_destroy(&mutex->handle);
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLock(BH_Mutex *mutex)
|
||||
{
|
||||
if (pthread_mutex_lock(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexUnlock(BH_Mutex *mutex)
|
||||
{
|
||||
if (pthread_mutex_unlock(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLockTry(BH_Mutex *mutex)
|
||||
{
|
||||
switch (pthread_mutex_trylock(&mutex->handle))
|
||||
{
|
||||
case 0: return BH_OK;
|
||||
case EBUSY: return BH_TIMEOUT;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
73
src/Platform/Posix/Semaphore.c
Normal file
73
src/Platform/Posix/Semaphore.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
BH_Semaphore *BH_SemaphoreNew(int value)
|
||||
{
|
||||
BH_Semaphore *semaphore;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
semaphore = malloc(sizeof(BH_Semaphore));
|
||||
if (semaphore && sem_init(&semaphore->handle, 0, value))
|
||||
{
|
||||
free(semaphore);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
|
||||
void BH_SemaphoreFree(BH_Semaphore *semaphore)
|
||||
{
|
||||
sem_destroy(&semaphore->handle);
|
||||
free(semaphore);
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphorePost(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (sem_post(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWait(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (sem_wait(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitTry(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (sem_trywait(&semaphore->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitFor(BH_Semaphore *semaphore,
|
||||
uint32_t timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = timeout / 1000;
|
||||
ts.tv_nsec = (timeout - ts.tv_sec * 1000) * 1000000;
|
||||
|
||||
switch (sem_timedwait(&semaphore->handle, &ts))
|
||||
{
|
||||
case 0: return BH_OK;
|
||||
case ETIMEDOUT: return BH_TIMEOUT;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
98
src/Platform/Posix/Thread.c
Normal file
98
src/Platform/Posix/Thread.c
Normal file
@@ -0,0 +1,98 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
struct BH_ThreadContext
|
||||
{
|
||||
BH_ThreadCallback callback;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
static void *BH_ThreadRun(void *context)
|
||||
{
|
||||
BH_ThreadCallback callback;
|
||||
void *data, *result;
|
||||
|
||||
callback = ((struct BH_ThreadContext *)context)->callback;
|
||||
data = ((struct BH_ThreadContext *)context)->data;
|
||||
free(context);
|
||||
|
||||
callback(data);
|
||||
BH_TssCleanup();
|
||||
|
||||
pthread_exit(0);
|
||||
}
|
||||
|
||||
|
||||
static int BH_ThreadInit(BH_Thread *thread,
|
||||
size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data)
|
||||
{
|
||||
struct BH_ThreadContext *context;
|
||||
pthread_attr_t attributes;
|
||||
int result;
|
||||
|
||||
context = malloc(sizeof(*context));
|
||||
if (!context)
|
||||
return BH_ERROR;
|
||||
context->callback = callback;
|
||||
context->data = data;
|
||||
|
||||
/* Create thread with specified stack size */
|
||||
pthread_attr_init(&attributes);
|
||||
|
||||
if (!stack)
|
||||
result = pthread_create(&thread->handle, NULL, BH_ThreadRun, context);
|
||||
else
|
||||
{
|
||||
if (stack < PTHREAD_STACK_MIN)
|
||||
stack = PTHREAD_STACK_MIN;
|
||||
pthread_attr_setstacksize(&attributes, stack);
|
||||
result = pthread_create(&thread->handle, &attributes, BH_ThreadRun, context);
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attributes);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
BH_Thread *BH_ThreadNew(size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data)
|
||||
{
|
||||
BH_Thread *thread;
|
||||
|
||||
thread = malloc(sizeof(BH_Thread));
|
||||
if (thread && BH_ThreadInit(thread, stack, callback, data))
|
||||
{
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadJoin(BH_Thread *thread)
|
||||
{
|
||||
if (pthread_join(thread->handle, NULL))
|
||||
return BH_ERROR;
|
||||
|
||||
free(thread);
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadDetach(BH_Thread *thread)
|
||||
{
|
||||
if (pthread_detach(thread->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
free(thread);
|
||||
return BH_OK;
|
||||
}
|
||||
35
src/Platform/Posix/Thread.h
Normal file
35
src/Platform/Posix/Thread.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef BH_PLATFORM_POSIX_THREAD_H
|
||||
#define BH_PLATFORM_POSIX_THREAD_H
|
||||
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
|
||||
struct BH_Condition
|
||||
{
|
||||
pthread_cond_t handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Mutex
|
||||
{
|
||||
pthread_mutex_t handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Semaphore
|
||||
{
|
||||
sem_t handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Thread
|
||||
{
|
||||
pthread_t handle;
|
||||
};
|
||||
|
||||
|
||||
void BH_TssCleanup(void);
|
||||
|
||||
#endif /* BH_PLATFORM_POSIX_THREAD_H */
|
||||
97
src/Platform/Posix/Tss.c
Normal file
97
src/Platform/Posix/Tss.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static int tssCleanupLock = 0;
|
||||
static int tssCleanupSize = 0;
|
||||
static BH_GenericCallback tssCleanupData[BH_MAX_TSS];
|
||||
|
||||
static int tssLock = 0;
|
||||
static int tssReady = 0;
|
||||
static pthread_key_t tssKey;
|
||||
|
||||
|
||||
static void BH_TssKeyCleanup(void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Lock cleanup table and call cleanups */
|
||||
BH_SpinlockLock(&tssCleanupLock);
|
||||
for (i = 0; i < tssCleanupSize; i++)
|
||||
tssCleanupData[i](((void **)data)[i]);
|
||||
BH_SpinlockUnlock(&tssCleanupLock);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static void **BH_TssDataFetch(void)
|
||||
{
|
||||
void **result;
|
||||
|
||||
/* Get or setup TSS data */
|
||||
BH_SpinlockLock(&tssLock);
|
||||
if (!tssReady)
|
||||
{
|
||||
if (pthread_key_create(&tssKey, BH_TssKeyCleanup))
|
||||
abort();
|
||||
tssReady = 1;
|
||||
}
|
||||
BH_SpinlockUnlock(&tssLock);
|
||||
|
||||
/* Get or setup TSS data */
|
||||
result = pthread_getspecific(tssKey);
|
||||
if (!result)
|
||||
{
|
||||
result = malloc(sizeof(void *) * BH_MAX_TSS);
|
||||
if (!result)
|
||||
abort();
|
||||
|
||||
memset(result, 0, sizeof(sizeof(void *) * BH_MAX_TSS));
|
||||
if (pthread_setspecific(tssKey, result))
|
||||
abort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void BH_TssCleanup(void)
|
||||
{
|
||||
BH_TssKeyCleanup(BH_TssDataFetch());
|
||||
}
|
||||
|
||||
|
||||
int BH_TssCreate(BH_GenericCallback callback)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Lock info and set up cleanup function */
|
||||
BH_SpinlockLock(&tssCleanupLock);
|
||||
if (tssCleanupSize < BH_MAX_TSS)
|
||||
{
|
||||
tssCleanupData[tssCleanupSize] = callback;
|
||||
result = tssCleanupSize++;
|
||||
}
|
||||
else
|
||||
result = BH_ERROR;
|
||||
BH_SpinlockUnlock(&tssCleanupLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void *BH_TssRead(int index)
|
||||
{
|
||||
return BH_TssDataFetch()[index];
|
||||
}
|
||||
|
||||
|
||||
void BH_TssWrite(int index,
|
||||
void *value)
|
||||
{
|
||||
BH_TssDataFetch()[index] = value;
|
||||
}
|
||||
50
src/Platform/Spinlock.c
Normal file
50
src/Platform/Spinlock.c
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
/* Using built-ins */
|
||||
#elif defined(_WIN32)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
|
||||
void BH_SpinlockLock(int *lock)
|
||||
{
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
while (__sync_lock_test_and_set(lock, 1));
|
||||
#elif defined(_WIN32)
|
||||
while (InterlockedExchange(lock, 1));
|
||||
#else
|
||||
#error "Spinlocks are not supported"
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int BH_SpinlockLockTry(int *lock)
|
||||
{
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
if (__sync_lock_test_and_set(lock, 1))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
#elif defined(_WIN32)
|
||||
if (InterlockedExchange(lock, 1))
|
||||
return BH_ERROR;
|
||||
return BH_OK;
|
||||
#else
|
||||
#error "Spinlocks are not supported"
|
||||
return BH_NOIMPL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void BH_SpinlockUnlock(int *lock)
|
||||
{
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
__sync_lock_release(lock);
|
||||
#elif defined(_WIN32)
|
||||
InterlockedExchange(lock, 0);
|
||||
#else
|
||||
#error "Spinlocks are not supported"
|
||||
#endif
|
||||
}
|
||||
58
src/Platform/Win32/Condition.c
Normal file
58
src/Platform/Win32/Condition.c
Normal file
@@ -0,0 +1,58 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Condition *BH_ConditionNew(void)
|
||||
{
|
||||
BH_Condition *condition;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
condition = malloc(sizeof(BH_Condition));
|
||||
if (condition)
|
||||
{
|
||||
InitializeConditionVariable(&condition->handle);
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
|
||||
void BH_ConditionFree(BH_Condition *condition)
|
||||
{
|
||||
BH_UNUSED(condition);
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWait(BH_Condition *condition,
|
||||
BH_Mutex *mutex)
|
||||
{
|
||||
return BH_ConditionWaitFor(condition, mutex, INFINITE);
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionWaitFor(BH_Condition *condition,
|
||||
BH_Mutex *mutex,
|
||||
uint32_t timeout)
|
||||
{
|
||||
switch (SleepConditionVariableCS(&condition->handle, &mutex->handle, timeout))
|
||||
{
|
||||
case 0: return BH_ERROR;
|
||||
case ERROR_TIMEOUT: return BH_TIMEOUT;
|
||||
default: return BH_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionSignal(BH_Condition *condition)
|
||||
{
|
||||
WakeConditionVariable(&condition->handle);
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_ConditionBroadcast(BH_Condition *condition)
|
||||
{
|
||||
WakeAllConditionVariable(&condition->handle);
|
||||
return BH_OK;
|
||||
}
|
||||
51
src/Platform/Win32/Mutex.c
Normal file
51
src/Platform/Win32/Mutex.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Mutex *BH_MutexNew(void)
|
||||
{
|
||||
BH_Mutex *mutex;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
mutex = malloc(sizeof(BH_Mutex));
|
||||
if (mutex && !InitializeCriticalSectionAndSpinCount(&mutex->handle, 0x400))
|
||||
{
|
||||
free(mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
||||
void BH_MutexFree(BH_Mutex *mutex)
|
||||
{
|
||||
DeleteCriticalSection(&mutex->handle);
|
||||
free(mutex);
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLock(BH_Mutex *mutex)
|
||||
{
|
||||
EnterCriticalSection(&mutex->handle);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexUnlock(BH_Mutex *mutex)
|
||||
{
|
||||
LeaveCriticalSection(&mutex->handle);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_MutexLockTry(BH_Mutex *mutex)
|
||||
{
|
||||
if (!TryEnterCriticalSection(&mutex->handle))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
69
src/Platform/Win32/Semaphore.c
Normal file
69
src/Platform/Win32/Semaphore.c
Normal file
@@ -0,0 +1,69 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
|
||||
|
||||
BH_Semaphore *BH_SemaphoreNew(int value)
|
||||
{
|
||||
BH_Semaphore *semaphore;
|
||||
|
||||
/* Allocate space for mutex and initialize it */
|
||||
semaphore = malloc(sizeof(BH_Semaphore));
|
||||
if (semaphore)
|
||||
{
|
||||
semaphore->handle = CreateSemaphore(NULL, value, 0x7FFF, NULL);
|
||||
if (!semaphore->handle)
|
||||
{
|
||||
free(semaphore);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return semaphore;
|
||||
}
|
||||
|
||||
|
||||
void BH_SemaphoreFree(BH_Semaphore *semaphore)
|
||||
{
|
||||
CloseHandle(semaphore->handle);
|
||||
free(semaphore);
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphorePost(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (!ReleaseSemaphore(semaphore->handle, 1, NULL))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWait(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (WaitForSingleObject(semaphore->handle, INFINITE))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitTry(BH_Semaphore *semaphore)
|
||||
{
|
||||
if (WaitForSingleObject(semaphore->handle, 0))
|
||||
return BH_ERROR;
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_SemaphoreWaitFor(BH_Semaphore *semaphore,
|
||||
uint32_t timeout)
|
||||
{
|
||||
switch (WaitForSingleObject(semaphore->handle, timeout))
|
||||
{
|
||||
case 0: return BH_OK;
|
||||
case WAIT_TIMEOUT: return BH_TIMEOUT;
|
||||
default: return BH_ERROR;
|
||||
}
|
||||
}
|
||||
90
src/Platform/Win32/Thread.c
Normal file
90
src/Platform/Win32/Thread.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <process.h>
|
||||
|
||||
|
||||
struct BH_ThreadContext
|
||||
{
|
||||
BH_ThreadCallback callback;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
||||
static unsigned __stdcall BH_ThreadRun(void *context)
|
||||
{
|
||||
|
||||
BH_ThreadCallback callback;
|
||||
void *data;
|
||||
|
||||
callback = ((struct BH_ThreadContext *)context)->callback;
|
||||
data = ((struct BH_ThreadContext *)context)->data;
|
||||
free(context);
|
||||
|
||||
callback(data);
|
||||
BH_TssCleanup();
|
||||
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
|
||||
static int BH_ThreadInit(BH_Thread *thread,
|
||||
size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data)
|
||||
{
|
||||
struct BH_ThreadContext *context;
|
||||
|
||||
context = malloc(sizeof(*context));
|
||||
if (!context)
|
||||
return BH_ERROR;
|
||||
context->callback = callback;
|
||||
context->data = data;
|
||||
|
||||
thread->handle = (HANDLE)_beginthreadex(NULL, stack, BH_ThreadRun, context, 0, NULL);
|
||||
if (!thread->handle)
|
||||
{
|
||||
free(context);
|
||||
return BH_ERROR;
|
||||
}
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
BH_Thread *BH_ThreadNew(size_t stack,
|
||||
BH_ThreadCallback callback,
|
||||
void *data)
|
||||
{
|
||||
BH_Thread *thread;
|
||||
|
||||
thread = malloc(sizeof(BH_Thread));
|
||||
if (thread && BH_ThreadInit(thread, stack, callback, data))
|
||||
{
|
||||
free(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadJoin(BH_Thread *thread)
|
||||
{
|
||||
/* Join the thread */
|
||||
WaitForSingleObject(thread->handle, INFINITE);
|
||||
CloseHandle(thread->handle);
|
||||
free(thread);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
|
||||
|
||||
int BH_ThreadDetach(BH_Thread *thread)
|
||||
{
|
||||
/* Detach from thread */
|
||||
CloseHandle(thread->handle);
|
||||
free(thread);
|
||||
|
||||
return BH_OK;
|
||||
}
|
||||
34
src/Platform/Win32/Thread.h
Normal file
34
src/Platform/Win32/Thread.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef BH_PLATFORM_WIN32_THREAD_H
|
||||
#define BH_PLATFORM_WIN32_THREAD_H
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
struct BH_Condition
|
||||
{
|
||||
CONDITION_VARIABLE handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Mutex
|
||||
{
|
||||
CRITICAL_SECTION handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Semaphore
|
||||
{
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
|
||||
struct BH_Thread
|
||||
{
|
||||
HANDLE handle;
|
||||
};
|
||||
|
||||
|
||||
void BH_TssCleanup(void);
|
||||
|
||||
|
||||
#endif /* BH_PLATFORM_WIN32_THREAD_H */
|
||||
99
src/Platform/Win32/Tss.c
Normal file
99
src/Platform/Win32/Tss.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "Thread.h"
|
||||
|
||||
#include <BH/Thread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static int tssCleanupLock = 0;
|
||||
static int tssCleanupSize = 0;
|
||||
static BH_GenericCallback tssCleanupData[BH_MAX_TSS];
|
||||
|
||||
|
||||
static int tssLock = 0;
|
||||
static int tssReady = 0;
|
||||
static DWORD tssKey;
|
||||
|
||||
|
||||
static void __stdcall BH_TssKeyCleanup(void *data)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Lock cleanup table and call cleanups */
|
||||
BH_SpinlockLock(&tssCleanupLock);
|
||||
for (i = 0; i < tssCleanupSize; i++)
|
||||
tssCleanupData[i](((void **)data)[i]);
|
||||
BH_SpinlockUnlock(&tssCleanupLock);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
static void **BH_TssDataFetch(void)
|
||||
{
|
||||
void **result;
|
||||
|
||||
/* Get or setup TSS data */
|
||||
BH_SpinlockLock(&tssLock);
|
||||
if (!tssReady)
|
||||
{
|
||||
tssKey = FlsAlloc(BH_TssKeyCleanup);
|
||||
if (tssKey == FLS_OUT_OF_INDEXES)
|
||||
abort();
|
||||
tssReady = 1;
|
||||
}
|
||||
BH_SpinlockUnlock(&tssLock);
|
||||
|
||||
/* Get or setup TSS data */
|
||||
result = FlsGetValue(tssKey);
|
||||
if (!result)
|
||||
{
|
||||
result = malloc(sizeof(void *) * BH_MAX_TSS);
|
||||
if (!result)
|
||||
abort();
|
||||
|
||||
memset(result, 0, sizeof(sizeof(void *) * BH_MAX_TSS));
|
||||
if (FlsSetValue(tssKey, result))
|
||||
abort();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void BH_TssCleanup(void)
|
||||
{
|
||||
BH_TssKeyCleanup(BH_TssDataFetch());
|
||||
}
|
||||
|
||||
|
||||
int BH_TssCreate(BH_GenericCallback callback)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Lock info and set up cleanup function */
|
||||
BH_SpinlockLock(&tssCleanupLock);
|
||||
if (tssCleanupSize < BH_MAX_TSS)
|
||||
{
|
||||
tssCleanupData[tssCleanupSize] = callback;
|
||||
result = tssCleanupSize++;
|
||||
}
|
||||
else
|
||||
result = BH_ERROR;
|
||||
BH_SpinlockUnlock(&tssCleanupLock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void *BH_TssRead(int index)
|
||||
{
|
||||
return BH_TssDataFetch()[index];
|
||||
}
|
||||
|
||||
|
||||
void BH_TssWrite(int index,
|
||||
void *value)
|
||||
{
|
||||
BH_TssDataFetch()[index] = value;
|
||||
}
|
||||
Reference in New Issue
Block a user