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_COVERAGE OFF CACHE BOOL "Enable coverage")
|
||||||
set(ENABLE_EXAMPLES ON CACHE BOOL "Enable building examples")
|
set(ENABLE_EXAMPLES ON CACHE BOOL "Enable building examples")
|
||||||
set(ENABLE_LTO ON CACHE BOOL "Enable LTO support")
|
set(ENABLE_LTO ON CACHE BOOL "Enable LTO support")
|
||||||
|
set(ENABLE_MT ON CACHE BOOL "Enable multithreading support")
|
||||||
|
|
||||||
# Enable IPO/LTO
|
# Enable IPO/LTO
|
||||||
if(ENABLE_LTO)
|
if(ENABLE_LTO)
|
||||||
@@ -102,6 +103,57 @@ set(BH_HEADER
|
|||||||
include/BH/Math.h
|
include/BH/Math.h
|
||||||
include/BH/Queue.h
|
include/BH/Queue.h
|
||||||
include/BH/Util.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
|
set(BH_INCLUDE_DIRS
|
||||||
@@ -114,23 +166,36 @@ if(WIN32)
|
|||||||
message(STATUS "Platform - Win32")
|
message(STATUS "Platform - Win32")
|
||||||
|
|
||||||
# Add platform dependent files
|
# Add platform dependent files
|
||||||
list(APPEND BH_SOURCE
|
list(APPEND BH_SOURCE ${BH_SOURCE_WIN32})
|
||||||
src/Platform/Win32/File.c
|
|
||||||
)
|
# 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)
|
elseif(UNIX)
|
||||||
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
|
message(STATUS "Platform: Unix (Linux/BSD/MacOS X)")
|
||||||
|
|
||||||
# Add platform dependent files
|
# Add platform dependent files
|
||||||
list(APPEND BH_SOURCE
|
list(APPEND BH_SOURCE BH_SOURCE_POSIX)
|
||||||
src/Platform/Posix/File.c
|
|
||||||
)
|
# 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()
|
else()
|
||||||
message(STATUS "Platform: Unknown")
|
message(STATUS "Platform: Unknown")
|
||||||
|
|
||||||
# Add platform dependent files
|
# Add platform dependent files
|
||||||
list(APPEND BH_SOURCE
|
list(APPEND BH_SOURCE ${BH_SOURCE_DUMMY} ${BH_SOURCE_DUMMY_MT})
|
||||||
src/Platform/Dummy/File.c
|
list(APPEND BH_HEADER ${BH_HEADER_DUMMY_MT})
|
||||||
)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Library
|
# 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