diff --git a/source/reflect/source/reflect_class.c b/source/reflect/source/reflect_class.c index 37d6f9cca..e00d03dea 100644 --- a/source/reflect/source/reflect_class.c +++ b/source/reflect/source/reflect_class.c @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -40,7 +42,7 @@ struct class_type enum accessor_type_id accessor; class_impl impl; class_interface interface; - size_t ref_count; + struct threading_atomic_ref_count_type ref; vector constructors; map methods; map static_methods; @@ -106,7 +108,7 @@ klass class_create(const char *name, enum accessor_type_id accessor, class_impl cls->impl = impl; cls->accessor = accessor; - cls->ref_count = 0; + threading_atomic_ref_count_store(&cls->ref, 0); cls->interface = singleton ? singleton() : NULL; cls->constructors = vector_create_type(constructor); cls->methods = map_create(&hash_callback_str, &comparable_callback_str); @@ -144,12 +146,11 @@ int class_increment_reference(klass cls) return 1; } - if (cls->ref_count == SIZE_MAX) + if (threading_atomic_ref_count_increment(&cls->ref) == 1) { return 1; } - ++cls->ref_count; reflect_memory_tracker_increment(class_stats); return 0; @@ -162,12 +163,11 @@ int class_decrement_reference(klass cls) return 1; } - if (cls->ref_count == 0) + if (threading_atomic_ref_count_decrement(&cls->ref) == 1) { return 1; } - --cls->ref_count; reflect_memory_tracker_decrement(class_stats); return 0; @@ -843,7 +843,7 @@ void class_destroy(klass cls) log_write("metacall", LOG_LEVEL_ERROR, "Invalid reference counter in class: %s", cls->name ? cls->name : ""); } - if (cls->ref_count == 0) + if (threading_atomic_ref_count_load(&cls->ref) == 0) { if (cls->name == NULL) { diff --git a/source/reflect/source/reflect_exception.c b/source/reflect/source/reflect_exception.c index 04c68366f..e20e66b82 100644 --- a/source/reflect/source/reflect_exception.c +++ b/source/reflect/source/reflect_exception.c @@ -20,6 +20,7 @@ #include +#include #include #include @@ -36,7 +37,7 @@ struct exception_type int64_t code; /* Numeric code of error */ char *stacktrace; /* Stack trace of the error */ uint64_t id; /* Thread id where the error was raised */ - size_t ref_count; + struct threading_atomic_ref_count_type ref; /* TODO: value attributes; // This should implement a map for representing the extra attributes of an exception */ }; @@ -56,7 +57,8 @@ exception exception_create(char *message, char *label, int64_t code, char *stack ex->code = code; ex->stacktrace = stacktrace; ex->id = thread_id_get_current(); - ex->ref_count = 0; + + threading_atomic_ref_count_store(&ex->ref, 0); reflect_memory_tracker_allocation(exception_stats); @@ -128,7 +130,8 @@ exception exception_create_const(const char *message, const char *label, int64_t ex->code = code; ex->id = thread_id_get_current(); - ex->ref_count = 0; + + threading_atomic_ref_count_store(&ex->ref, 0); reflect_memory_tracker_allocation(exception_stats); @@ -151,12 +154,11 @@ int exception_increment_reference(exception ex) return 1; } - if (ex->ref_count == SIZE_MAX) + if (threading_atomic_ref_count_increment(&ex->ref) == 1) { return 1; } - ++ex->ref_count; reflect_memory_tracker_increment(exception_stats); return 0; @@ -169,12 +171,11 @@ int exception_decrement_reference(exception ex) return 1; } - if (ex->ref_count == 0) + if (threading_atomic_ref_count_decrement(&ex->ref) == 1) { return 1; } - --ex->ref_count; reflect_memory_tracker_decrement(exception_stats); return 0; @@ -234,7 +235,7 @@ void exception_destroy(exception ex) log_write("metacall", LOG_LEVEL_ERROR, "Invalid reference counter in exception: %s", ex->label ? ex->label : ""); } - if (ex->ref_count == 0) + if (threading_atomic_ref_count_load(&ex->ref) == 0) { if (ex->message != NULL) { diff --git a/source/reflect/source/reflect_function.c b/source/reflect/source/reflect_function.c index f6d3f75c3..98db6a311 100644 --- a/source/reflect/source/reflect_function.c +++ b/source/reflect/source/reflect_function.c @@ -21,6 +21,8 @@ #include #include +#include + #include #include @@ -34,7 +36,7 @@ struct function_type signature s; function_impl impl; function_interface interface; - size_t ref_count; + struct threading_atomic_ref_count_type ref; enum async_id async; void *data; }; @@ -77,7 +79,6 @@ function function_create(const char *name, size_t args_count, function_impl impl } func->impl = impl; - func->ref_count = 0; func->async = SYNCHRONOUS; func->data = NULL; @@ -87,12 +88,11 @@ function function_create(const char *name, size_t args_count, function_impl impl { log_write("metacall", LOG_LEVEL_ERROR, "Invalid function signature allocation"); - free(func->name); - free(func); - - return NULL; + goto function_create_error; } + threading_atomic_ref_count_store(&func->ref, 0); + func->interface = singleton ? singleton() : NULL; if (func->interface != NULL && func->interface->create != NULL) @@ -101,16 +101,19 @@ function function_create(const char *name, size_t args_count, function_impl impl { log_write("metacall", LOG_LEVEL_ERROR, "Invalid function (%s) create callback <%p>", func->name, func->interface->create); - free(func->name); - free(func); - - return NULL; + goto function_create_error; } } reflect_memory_tracker_allocation(function_stats); return func; + +function_create_error: + free(func->name); + free(func); + + return NULL; } int function_increment_reference(function func) @@ -120,12 +123,11 @@ int function_increment_reference(function func) return 1; } - if (func->ref_count == SIZE_MAX) + if (threading_atomic_ref_count_increment(&func->ref) == 1) { return 1; } - ++func->ref_count; reflect_memory_tracker_increment(function_stats); return 0; @@ -138,12 +140,11 @@ int function_decrement_reference(function func) return 1; } - if (func->ref_count == 0) + if (threading_atomic_ref_count_decrement(&func->ref) == 1) { return 1; } - --func->ref_count; reflect_memory_tracker_decrement(function_stats); return 0; @@ -639,7 +640,7 @@ void function_destroy(function func) log_write("metacall", LOG_LEVEL_ERROR, "Invalid reference counter in function: %s", func->name ? func->name : ""); } - if (func->ref_count == 0) + if (threading_atomic_ref_count_load(&func->ref) == 0) { if (func->name == NULL) { diff --git a/source/reflect/source/reflect_object.c b/source/reflect/source/reflect_object.c index 42ee31a90..d2b905ce4 100644 --- a/source/reflect/source/reflect_object.c +++ b/source/reflect/source/reflect_object.c @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -38,7 +40,7 @@ struct object_type enum accessor_type_id accessor; object_impl impl; object_interface interface; - size_t ref_count; + struct threading_atomic_ref_count_type ref; klass cls; }; @@ -79,7 +81,8 @@ object object_create(const char *name, enum accessor_type_id accessor, object_im obj->impl = impl; obj->accessor = accessor; - obj->ref_count = 0; + threading_atomic_ref_count_store(&obj->ref, 0); + obj->interface = singleton ? singleton() : NULL; obj->cls = cls; @@ -109,12 +112,11 @@ int object_increment_reference(object obj) return 1; } - if (obj->ref_count == SIZE_MAX) + if (threading_atomic_ref_count_increment(&obj->ref) == 1) { return 1; } - ++obj->ref_count; reflect_memory_tracker_increment(object_stats); return 0; @@ -127,12 +129,11 @@ int object_decrement_reference(object obj) return 1; } - if (obj->ref_count == 0) + if (threading_atomic_ref_count_decrement(&obj->ref) == 1) { return 1; } - --obj->ref_count; reflect_memory_tracker_decrement(object_stats); return 0; @@ -393,7 +394,7 @@ void object_destroy(object obj) log_write("metacall", LOG_LEVEL_ERROR, "Invalid reference counter in object: %s", obj->name ? obj->name : ""); } - if (obj->ref_count == 0) + if (threading_atomic_ref_count_load(&obj->ref) == 0) { if (obj->name == NULL) { diff --git a/source/threading/CMakeLists.txt b/source/threading/CMakeLists.txt index 5c2fd2016..e3c9a9fb0 100644 --- a/source/threading/CMakeLists.txt +++ b/source/threading/CMakeLists.txt @@ -37,6 +37,7 @@ set(headers ${include_path}/threading.h ${include_path}/threading_atomic.h ${include_path}/threading_thread_id.h + ${include_path}/threading_atomic_ref_count.h ) set(sources diff --git a/source/threading/include/threading/threading_atomic_ref_count.h b/source/threading/include/threading/threading_atomic_ref_count.h new file mode 100644 index 000000000..fb9dcb341 --- /dev/null +++ b/source/threading/include/threading/threading_atomic_ref_count.h @@ -0,0 +1,99 @@ +/* + * Thrading Library by Parra Studios + * A threading library providing utilities for lock-free data structures and more. + * + * Copyright (C) 2016 - 2022 Vicente Eduardo Ferrer Garcia + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef THREADING_ATOMIC_REF_COUNT_H +#define THREADING_ATOMIC_REF_COUNT_H 1 + +/* -- Headers -- */ + +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* -- Headers -- */ + +#include + +/* -- Definitions -- */ + +#define THREADING_ATOMIC_REF_COUNT_MAX UINTMAX_MAX +#define THREADING_ATOMIC_REF_COUNT_MIN 0 + +/* -- Member Data -- */ + +struct threading_atomic_ref_count_type +{ + atomic_uintmax_t count; +}; + +/* -- Type Definitions -- */ + +typedef struct threading_atomic_ref_count_type *threading_atomic_ref_count; + +/* -- Methods -- */ + +inline void threading_atomic_ref_count_store(threading_atomic_ref_count ref, uintmax_t v) +{ + atomic_store(&ref->count, v); +} + +inline uintmax_t threading_atomic_ref_count_load(threading_atomic_ref_count ref) +{ + return atomic_load_explicit(&ref->count, memory_order_relaxed); +} + +inline int threading_atomic_ref_count_increment(threading_atomic_ref_count ref) +{ + if (atomic_load_explicit(&ref->count, memory_order_relaxed) == THREADING_ATOMIC_REF_COUNT_MAX) + { + return 1; + } + + atomic_fetch_add_explicit(&ref->count, 1U, memory_order_relaxed); + + return 0; +} + +inline int threading_atomic_ref_count_decrement(threading_atomic_ref_count ref) +{ + if (atomic_load_explicit(&ref->count, memory_order_relaxed) == 0) + { + return 1; + } + + uintmax_t old_ref_count = atomic_fetch_add_explicit(&ref->count, 1U, memory_order_release); + + if (old_ref_count == 1) + { + atomic_thread_fence(memory_order_acquire); + } + + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* THREADING_ATOMIC_REF_COUNT_H */ diff --git a/source/threading/include/threading/threading_thread_id.h b/source/threading/include/threading/threading_thread_id.h index f9833e403..b56bc8405 100644 --- a/source/threading/include/threading/threading_thread_id.h +++ b/source/threading/include/threading/threading_thread_id.h @@ -37,7 +37,7 @@ extern "C" { #define THREAD_ID_INVALID UINT64_MAX -/* -- Macros -- */ +/* -- Methods -- */ /** * @brief