From 117001b8986d46040da5c7b07330b5fb99fc7f70 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov <0x7fffff@guattari.ru> Date: Sun, 14 Aug 2022 04:50:43 +0400 Subject: thread, atomic --- source/kit/CMakeLists.txt | 7 +++-- source/kit/atomic.c | 42 +++++++++++++++++++++++++ source/kit/atomic.h | 59 ++++++++++++++++++++++++++++++++++++ source/kit/thread.c | 45 +++++++++++++++++++++++++++ source/kit/thread.h | 23 ++++++++++++++ source/test/unittests/CMakeLists.txt | 5 +-- source/test/unittests/atomic.test.c | 26 ++++++++++++++++ source/test/unittests/thread.test.c | 18 +++++++++++ 8 files changed, 221 insertions(+), 4 deletions(-) create mode 100644 source/kit/atomic.c create mode 100644 source/kit/atomic.h create mode 100644 source/kit/thread.c create mode 100644 source/kit/thread.h create mode 100644 source/test/unittests/atomic.test.c create mode 100644 source/test/unittests/thread.test.c (limited to 'source') diff --git a/source/kit/CMakeLists.txt b/source/kit/CMakeLists.txt index c7bb204..21cfd1e 100644 --- a/source/kit/CMakeLists.txt +++ b/source/kit/CMakeLists.txt @@ -1,11 +1,14 @@ target_sources( ${KIT_LIBRARY} PRIVATE - input_buffer.c input_stream.c lower_bound.c string_ref.c - async_function.c allocator.c array_ref.c dynamic_array.c + atomic.c input_buffer.c input_stream.c lower_bound.c + thread.c string_ref.c async_function.c allocator.c array_ref.c + dynamic_array.c PUBLIC + $ $ $ + $ $ $ $ diff --git a/source/kit/atomic.c b/source/kit/atomic.c new file mode 100644 index 0000000..4321700 --- /dev/null +++ b/source/kit/atomic.c @@ -0,0 +1,42 @@ +#include "atomic.h" + +#ifdef _MSC_VEC +# include + +# ifdef _WIN64 +# pragma intrinsic(_InterlockedExchange64) +# pragma intrinsic(_InterlockedExchangeAdd64) + +# define InterlockedExchange_ _InterlockedExchange64 +# define InterlockedExchangeAdd_ _InterlockedExchangeAdd64 +# else +# pragma intrinsic(_InterlockedExchange32) +# pragma intrinsic(_InterlockedExchangeAdd32) + +# define InterlockedExchange_ _InterlockedExchange32 +# define InterlockedExchangeAdd_ _InterlockedExchangeAdd32 +# endif + +void kit_atomic_store_explicit(volatile KIT_ATOMIC_VAR *var, + KIT_ATOMIC_VAR value, + int memory_order) { + InterlockedExchange_(var, value); +} + +KIT_ATOMIC_VAR kit_atomic_load_explicit(volatile KIT_ATOMIC_VAR *var, + int memory_order) { + return *var; +} + +KIT_ATOMIC_VAR kit_atomic_fetch_add_explicit( + volatile KIT_ATOMIC_VAR *var, KIT_ATOMIC_VAR value, + int memory_order) { + return InterlockedExchangeAdd_(var, value); +} + +KIT_ATOMIC_VAR kit_atomic_exchange_explicit( + volatile KIT_ATOMIC_VAR *var, KIT_ATOMIC_VAR value, + int memory_order) { + return InterlockedExchange_(var, value); +} +#endif diff --git a/source/kit/atomic.h b/source/kit/atomic.h new file mode 100644 index 0000000..b9242c2 --- /dev/null +++ b/source/kit/atomic.h @@ -0,0 +1,59 @@ +#ifndef KIT_ATOMIC_H +#define KIT_ATOMIC_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef _MSC_VER +# include + +# define KIT_ATOMIC(type_) _Atomic type_ +#else +enum { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst +}; +# ifdef _WIN64 +# define KIT_ATOMIC_VAR uint64_t +# else +# define KIT_ATOMIC_VAR volatile uint32_t +# endif +# define KIT_ATOMIC(type_) volatile KIT_ATOMIC_VAR + +void kit_atomic_store_explicit(volatile KIT_ATOMIC_VAR *var, + KIT_ATOMIC_VAR value, + int memory_order); + +KIT_ATOMIC_VAR kit_atomic_load_explicit(volatile KIT_ATOMIC_VAR *var, + int memory_order); + +KIT_ATOMIC_VAR kit_atomic_fetch_add_explicit( + volatile KIT_ATOMIC_VAR *var, KIT_ATOMIC_VAR value, + int memory_order); + +KIT_ATOMIC_VAR kit_atomic_exchange_explicit( + volatile KIT_ATOMIC_VAR *var, KIT_ATOMIC_VAR value, + int memory_order); + +# define atomic_store_explicit kit_atomic_store_explicit +# define atomic_load_explicit kit_atomic_load_explicit +# define atomic_fetch_add_explicit kit_atomic_fetch_add_explicit +# define atomic_exchange_explicit kit_atomic_exchange_explicit +#endif + +#ifndef KIT_DISABLE_SHORT_NAMES +# define ATOMIC KIT_ATOMIC +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/kit/thread.c b/source/kit/thread.c new file mode 100644 index 0000000..71437eb --- /dev/null +++ b/source/kit/thread.c @@ -0,0 +1,45 @@ +#include "thread.h" + +#ifdef _MSC_VER +# include "atomic.h" + +# include +# include + +typedef struct { + HANDLE thread; + kit_thread_routine routine; + void *user_data; + void *return_value; +} thread_data; + +DWORD __stdcall run_thread_(void *p) { + thread_data *data = (thread_data *) p; + data->return_value = data->routine(data->user_data); +} + +int pthread_create(pthread_t *new_thread, void *attrs, + void *(*routine)(void *), void *user_data) { + thread_data *data = (thread_data *) malloc(sizeof(thread_data)); + if (data == NULL) + return -1; + data->routine = routine; + data->user_data = user_data; + data->thread = CreateThread(NULL, 0, run_thread_, data, 0, NULL); + if (data->thread == NULL) + return -1; + if (new_thread != NULL) + *new_thread = data; + return 0; +} + +void *pthread_join(pthread_t thread, void *return_value) { + thread_data *data = (thread_data *) thread; + if (data == NULL || data->thread == NULL) + return (void *) 0; + WaitForSingleObject(data->thread, INFINITE); + void *return_value = data->return_value; + free(data); + return return_value; +} +#endif diff --git a/source/kit/thread.h b/source/kit/thread.h new file mode 100644 index 0000000..a1138ae --- /dev/null +++ b/source/kit/thread.h @@ -0,0 +1,23 @@ +#ifndef KIT_THREAD_H +#define KIT_THREAD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _MSC_VER +# include "pthread.h" +#else +typedef void *pthread_t; + +int pthread_create(pthread_t *new_thread, void *attrs, + void *(*routine)(void *), void *user_data); + +void *pthread_join(pthread_t thread, void *return_value); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/test/unittests/CMakeLists.txt b/source/test/unittests/CMakeLists.txt index 674f442..853d896 100644 --- a/source/test/unittests/CMakeLists.txt +++ b/source/test/unittests/CMakeLists.txt @@ -2,5 +2,6 @@ target_sources( ${KIT_TEST_SUITE} PRIVATE async_function.test.c test_duration.test.c main.test.c - string_ref.test.c array_ref.test.c input_stream.test.c lower_bound.test.c - input_buffer.test.c dynamic_array.test.c) + string_ref.test.c atomic.test.c thread.test.c array_ref.test.c + input_stream.test.c lower_bound.test.c input_buffer.test.c + dynamic_array.test.c) diff --git a/source/test/unittests/atomic.test.c b/source/test/unittests/atomic.test.c new file mode 100644 index 0000000..9f1a10b --- /dev/null +++ b/source/test/unittests/atomic.test.c @@ -0,0 +1,26 @@ +#include "../../kit/atomic.h" + +#define KIT_TEST_FILE atomic +#include "../../kit_test/test.h" + +TEST("atomic store and load") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 20); +} + +TEST("atomic exchange") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_exchange_explicit(&value, 42, + memory_order_relaxed) == 20); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 42); +} + +TEST("atomic fetch add") { + ATOMIC(int) value; + atomic_store_explicit(&value, 20, memory_order_relaxed); + REQUIRE(atomic_fetch_add_explicit(&value, 22, + memory_order_relaxed) == 20); + REQUIRE(atomic_load_explicit(&value, memory_order_relaxed) == 42); +} diff --git a/source/test/unittests/thread.test.c b/source/test/unittests/thread.test.c new file mode 100644 index 0000000..fed564b --- /dev/null +++ b/source/test/unittests/thread.test.c @@ -0,0 +1,18 @@ +#include "../../kit/thread.h" + +#define KIT_TEST_FILE thread +#include "../../kit_test/test.h" + +static void *test_thread_fn(void *data) { + ptrdiff_t *value = (ptrdiff_t *) data; + return (void *) (*value + 20); +} + +TEST("run thread") { + pthread_t t; + ptrdiff_t value = 22; + pthread_create(&t, NULL, test_thread_fn, &value); + void *result; + pthread_join(t, &result); + REQUIRE((ptrdiff_t) result == 42); +} -- cgit v1.2.3