Added mutex.h and thread.h
This commit is contained in:
1 parent
f520c38583
commit
ea36906d02
3 files changed
+392
-4
No files matched your search
+7
-4
@@ -26,15 +26,18 @@ static struct
|
|||||||
int RANGE; // Index out of range
|
int RANGE; // Index out of range
|
||||||
int DUPLICATE; // Duplicate key or value
|
int DUPLICATE; // Duplicate key or value
|
||||||
int ERROR; // Generic error, usually caused by algorithm error
|
int ERROR; // Generic error, usually caused by algorithm error
|
||||||
} cmc_flags = { 0, 1, 2, 3, 4, 5, 6, 7 };
|
int THREAD; // Generic error regarding threads
|
||||||
|
int MUTEX; // Generic error regarding mutexes
|
||||||
|
} cmc_flags = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cmc_flags_to_str
|
* cmc_flags_to_str
|
||||||
*
|
*
|
||||||
* Maps the error codes to their character representation.
|
* Maps the error codes to their character representation.
|
||||||
*/
|
*/
|
||||||
const char *cmc_flags_to_str[8] = { "OK", "ALLOC", "EMPTY",
|
const char *cmc_flags_to_str[10] = { "OK", "ALLOC", "EMPTY",
|
||||||
"NOT_FOUND", "INVALID", "RANGE",
|
"NOT_FOUND", "INVALID", "RANGE",
|
||||||
"DUPLICATE", "ERROR" };
|
"DUPLICATE", "ERROR", "THREAD",
|
||||||
|
"MUTEX" };
|
||||||
|
|
||||||
#endif /* CMC_FLAGS_H */
|
#endif /* CMC_FLAGS_H */
|
||||||
+212
@@ -0,0 +1,212 @@
|
|||||||
|
/**
|
||||||
|
* mutex.h
|
||||||
|
*
|
||||||
|
* Creation Date: 14/05/2020
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A very simple, header-only and minimalistic cross-platform mutex
|
||||||
|
*
|
||||||
|
* Types
|
||||||
|
* - cmc_mutex
|
||||||
|
*
|
||||||
|
* Functions
|
||||||
|
* - cmc_mtx_init
|
||||||
|
* - cmc_mtx_destroy
|
||||||
|
* - cmc_mtx_lock
|
||||||
|
* - cmc_mtx_unlock
|
||||||
|
* - cmc_mtx_trylock
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "../cor/flags.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define CMC_MUTEX_WINDOWS
|
||||||
|
#elif defined(__unix__)
|
||||||
|
#define CMC_MUTEX_UNIX
|
||||||
|
#else
|
||||||
|
#error "Unknown platform for CMC Mutex"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Platform specific includes */
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cmc_mutex
|
||||||
|
*
|
||||||
|
* A mutex wrapper.
|
||||||
|
*/
|
||||||
|
struct cmc_mutex
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
HANDLE mutex;
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
#endif
|
||||||
|
int flag;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire resources for a mutex.
|
||||||
|
*
|
||||||
|
* \param mtx An uninitialized mutex wrapper.
|
||||||
|
* \return True or false if the mutex was successfully initialized.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_mtx_init(struct cmc_mutex *mtx)
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
mtx->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||||
|
|
||||||
|
if (mtx->mutex == NULL)
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
else
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return mtx->mutex != NULL;
|
||||||
|
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
int err = pthread_mutex_init(&(mtx->mutex), NULL);
|
||||||
|
|
||||||
|
if (err != 0)
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
else
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return err == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release all resources from a mutex. Calling this function on a locked mutex
|
||||||
|
* causes undefined behavior.
|
||||||
|
*
|
||||||
|
* \param mtx A mutex to be destroyed.
|
||||||
|
* \return True or false if the mutex was successfully destroyed.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_mtx_destroy(struct cmc_mutex *mtx)
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
if (!CloseHandle(mtx->mutex))
|
||||||
|
{
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
if (pthread_mutex_destroy(&(mtx->mutex)) != 0)
|
||||||
|
{
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locks a mutex. If the mutex is already locked, the thread is blocked until
|
||||||
|
* the mutex can be acquired.
|
||||||
|
*
|
||||||
|
* \param mtx A mutex to be locked.
|
||||||
|
* \return True or false if the lock on the mutex was successfully acquired.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_mtx_lock(struct cmc_mutex *mtx)
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
DWORD result = WaitForSingleObject(mtx->mutex, INFINITE);
|
||||||
|
|
||||||
|
if (result == WAIT_FAILED || result == WAIT_ABANDONED)
|
||||||
|
{
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
if (pthread_mutex_lock(&mtx->mutex) != 0)
|
||||||
|
{
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlocks a mutex. If the mutex is already locked, the thread is blocked until
|
||||||
|
* the mutex can be acquired.
|
||||||
|
*
|
||||||
|
* \param mtx A mutex to be unlocked.
|
||||||
|
* \return True or false if the mutex was successfully unlocked.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_mtx_unlock(struct cmc_mutex *mtx)
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
if (!ReleaseMutex(mtx->mutex))
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
else
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return mtx->flag == cmc_flags.OK;
|
||||||
|
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
if (pthread_mutex_unlock(&mtx->mutex) != 0)
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
else
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return mtx->flag == cmc_flags.OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tries to lock a mutex. If the mutex is already locked, the thread is not
|
||||||
|
* blocked and the function returns false.
|
||||||
|
*
|
||||||
|
* \param mtx A mutex to try to lock.
|
||||||
|
* \return True or false if the lock on the mutex was successfully acquired.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_mtx_trylock(struct cmc_mutex *mtx)
|
||||||
|
{
|
||||||
|
#if defined(CMC_MUTEX_WINDOWS)
|
||||||
|
DWORD result = WaitForSingleObject(mtx->mutex, 0);
|
||||||
|
|
||||||
|
if (result == WAIT_FAILED || result == WAIT_ABANDONED)
|
||||||
|
{
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
return result != WAIT_TIMEOUT;
|
||||||
|
|
||||||
|
#elif defined(CMC_MUTEX_UNIX)
|
||||||
|
int err = pthread_mutex_trylock(&mtx->mutex);
|
||||||
|
|
||||||
|
if (err == EINVAL || err == EFAULT)
|
||||||
|
mtx->flag = cmc_flags.MUTEX;
|
||||||
|
else
|
||||||
|
mtx->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return err == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/**
|
||||||
|
* thread.h
|
||||||
|
*
|
||||||
|
* Creation Date: 14/05/2020
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Leonardo Vencovsky (https://github.com/LeoVen)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A very simple, header-only utility for spawning and joining threads
|
||||||
|
*
|
||||||
|
* Types
|
||||||
|
* - cmc_thread
|
||||||
|
* - cmc_thread_proc
|
||||||
|
*
|
||||||
|
* Functions
|
||||||
|
* - cmc_thrd_create
|
||||||
|
* - cmc_thrd_join
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "../cor/flags.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define CMC_THREAD_WINDOWS
|
||||||
|
#elif defined(__unix__)
|
||||||
|
#define CMC_THREAD_UNIX
|
||||||
|
#else
|
||||||
|
#error "Unknown platform for CMC Threads"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* The type of a process run by a thread */
|
||||||
|
typedef int (*cmc_thread_proc)(void *);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct cmc_thread
|
||||||
|
*
|
||||||
|
* A thread wrapper.
|
||||||
|
*/
|
||||||
|
struct cmc_thread
|
||||||
|
{
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
HANDLE thread;
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
pthread_t thread;
|
||||||
|
#endif
|
||||||
|
int flag;
|
||||||
|
void *args;
|
||||||
|
cmc_thread_proc process;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* A thread wrapper */
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
static DWORD cmc_thread_wrapper(void *arg)
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
static void *cmc_thread_wrapper(void *arg)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
struct cmc_thread *thr = (struct cmc_thread *)arg;
|
||||||
|
|
||||||
|
int result = thr->process(thr->args);
|
||||||
|
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
return result;
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
return (void *)(intptr_t)result;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and spawns a new thread.
|
||||||
|
*
|
||||||
|
* \param thr An uninitialized thread wrapper.
|
||||||
|
* \param proc Pointer to a function that will run in a new thread.
|
||||||
|
* \param args The arguments passed to the proc function.
|
||||||
|
* \return True or false if the thread creation was successfull.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_thrd_create(struct cmc_thread *thr, cmc_thread_proc proc,
|
||||||
|
void *args)
|
||||||
|
{
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
thr->args = args;
|
||||||
|
thr->process = proc;
|
||||||
|
thr->thread = CreateThread(NULL, 0, cmc_thread_wrapper, thr, 0, NULL);
|
||||||
|
|
||||||
|
if (!thr->thread)
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
else
|
||||||
|
thr->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return thr->flag == cmc_flags.OK;
|
||||||
|
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
thr->args = args;
|
||||||
|
thr->process = proc;
|
||||||
|
if (pthread_create(&(thr->thread), NULL, cmc_thread_wrapper, thr) != 0)
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
else
|
||||||
|
thr->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
return thr->flag == cmc_flags.OK;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blocks the current thread until the target thread terminates.
|
||||||
|
*
|
||||||
|
* \param thr The target thread to wait on.
|
||||||
|
* \param result The value returned by the target thread. Optional.
|
||||||
|
* \return True or false if the join was successfull.
|
||||||
|
*/
|
||||||
|
static inline bool cmc_thrd_join(struct cmc_thread *thr, int *result)
|
||||||
|
{
|
||||||
|
#if defined(CMC_THREAD_WINDOWS)
|
||||||
|
if (WaitForSingleObject(thr->thread, INFINITE) == WAIT_FAILED)
|
||||||
|
{
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD exit_code;
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
if (GetExitCodeThread(thr->thread, &exit_code) == 0)
|
||||||
|
{
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*result = (int)exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
thr->flag = cmc_flags.OK;
|
||||||
|
|
||||||
|
if (CloseHandle(thr->thread) == 0)
|
||||||
|
{
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
thr->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#elif defined(CMC_THREAD_UNIX)
|
||||||
|
void *exit_value;
|
||||||
|
|
||||||
|
if (pthread_join(thr->thread, &exit_value) != 0)
|
||||||
|
{
|
||||||
|
thr->flag = cmc_flags.THREAD;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
*result = (int)(intptr_t)exit_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
thr->flag = cmc_flags.OK;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
Reference in new issue
Block a user