Add initialized field to thread abstraction and add missing doxygen
diff --git a/bundles/logging/log_helper/src/log_helper.c b/bundles/logging/log_helper/src/log_helper.c
index 677564e..17d7531 100644
--- a/bundles/logging/log_helper/src/log_helper.c
+++ b/bundles/logging/log_helper/src/log_helper.c
@@ -107,7 +107,7 @@
(*loghelper)->stdOutFallback = celix_bundleContext_getPropertyAsBool(context, LOGHELPER_ENABLE_STDOUT_FALLBACK_NAME, LOGHELPER_ENABLE_STDOUT_FALLBACK_DEFAULT);
(*loghelper)->stdOutFallbackIncludeDebug = celix_bundleContext_getPropertyAsBool(context, LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG_NAME, LOGHELPER_STDOUT_FALLBACK_INCLUDE_DEBUG_DEFAULT);
- pthread_mutex_init(&(*loghelper)->logListLock, NULL);
+ celixThreadMutex_create(&(*loghelper)->logListLock, NULL);
arrayList_create(&(*loghelper)->logServices);
}
@@ -139,9 +139,9 @@
{
log_helper_t *loghelper = handle;
- pthread_mutex_lock(&loghelper->logListLock);
+ celixThreadMutex_lock(&loghelper->logListLock);
arrayList_add(loghelper->logServices, service);
- pthread_mutex_unlock(&loghelper->logListLock);
+ celixThreadMutex_unlock(&loghelper->logListLock);
return CELIX_SUCCESS;
}
@@ -150,9 +150,9 @@
{
log_helper_t *loghelper = handle;
- pthread_mutex_lock(&loghelper->logListLock);
+ celixThreadMutex_lock(&loghelper->logListLock);
arrayList_removeElement(loghelper->logServices, service);
- pthread_mutex_unlock(&loghelper->logListLock);
+ celixThreadMutex_unlock(&loghelper->logListLock);
return CELIX_SUCCESS;
}
@@ -173,11 +173,11 @@
serviceTracker_destroy((*loghelper)->logServiceTracker);
}
- pthread_mutex_lock(&(*loghelper)->logListLock);
+ celixThreadMutex_lock(&(*loghelper)->logListLock);
arrayList_destroy((*loghelper)->logServices);
- pthread_mutex_unlock(&(*loghelper)->logListLock);
+ celixThreadMutex_unlock(&(*loghelper)->logListLock);
- pthread_mutex_destroy(&(*loghelper)->logListLock);
+ celixThreadMutex_destroy(&(*loghelper)->logListLock);
free(*loghelper);
*loghelper = NULL;
@@ -202,7 +202,7 @@
va_start(listPointer, message);
vsnprintf(msg, 1024, message, listPointer);
- pthread_mutex_lock(&loghelper->logListLock);
+ celixThreadMutex_lock(&loghelper->logListLock);
int i = 0;
for (; i < arrayList_size(loghelper->logServices); i++) {
@@ -218,7 +218,7 @@
}
}
- pthread_mutex_unlock(&loghelper->logListLock);
+ celixThreadMutex_unlock(&loghelper->logListLock);
if (!logged && loghelper->stdOutFallback) {
char *levelStr = NULL;
diff --git a/libs/framework/src/dm_dependency_manager_impl.c b/libs/framework/src/dm_dependency_manager_impl.c
index 1de53a8..0a94a52 100644
--- a/libs/framework/src/dm_dependency_manager_impl.c
+++ b/libs/framework/src/dm_dependency_manager_impl.c
@@ -35,7 +35,7 @@
if (manager != NULL) {
manager->ctx = context;
manager->components = celix_arrayList_create();
- pthread_mutex_init(&manager->mutex, NULL);
+ celixThreadMutex_create(&manager->mutex, NULL);
}
return manager;
}
@@ -46,7 +46,7 @@
celix_arrayList_destroy(manager->components);
celixThreadMutex_unlock(&manager->mutex);
- pthread_mutex_destroy(&manager->mutex);
+ celixThreadMutex_destroy(&manager->mutex);
free(manager);
}
}
diff --git a/libs/framework/src/dm_dependency_manager_impl.h b/libs/framework/src/dm_dependency_manager_impl.h
index aa43b02..ff5558c 100644
--- a/libs/framework/src/dm_dependency_manager_impl.h
+++ b/libs/framework/src/dm_dependency_manager_impl.h
@@ -31,7 +31,7 @@
struct celix_dependency_manager {
celix_bundle_context_t *ctx;
celix_array_list_t *components;
- pthread_mutex_t mutex;
+ celix_thread_mutex_t mutex;
};
celix_dependency_manager_t* celix_private_dependencyManager_create(celix_bundle_context_t *context);
diff --git a/libs/utils/gtest/src/ThreadsTestSuite.cc b/libs/utils/gtest/src/ThreadsTestSuite.cc
index 999415a..a8efe0d 100644
--- a/libs/utils/gtest/src/ThreadsTestSuite.cc
+++ b/libs/utils/gtest/src/ThreadsTestSuite.cc
@@ -339,16 +339,48 @@
int* value = (int*)malloc(sizeof(int));
*value = 123;
- status = celix_tss_set(key, value);
+ status = celix_tss_set(&key, value);
EXPECT_EQ(CELIX_SUCCESS, status);
- value = (int*)celix_tss_get(key);
+ value = (int*)celix_tss_get(&key);
EXPECT_EQ(123, *value);
- status = celix_tss_delete(key);
+ status = celix_tss_delete(&key);
EXPECT_EQ(CELIX_SUCCESS, status);
}
+TEST_F(ThreadsTestSuite, UninitializedTssTest) {
+ celix_tss_key_t key;
+ key.initialized = false;
+
+ EXPECT_EQ(CELIX_ILLEGAL_STATE, celix_tss_set(&key, (void*)0x42));
+ EXPECT_EQ(nullptr, celix_tss_get(&key));
+
+ //nothing happens when deleting an uninitialized key
+ EXPECT_EQ(CELIX_SUCCESS, celix_tss_delete(&key));
+}
+
+TEST_F(ThreadsTestSuite, UninitializedThreadTest) {
+ celix_thread_t thread;
+ thread.threadInitialized = false;
+ EXPECT_EQ(CELIX_SUCCESS, celixThread_join(thread, nullptr)); //ignore join on uninitialized thread
+ EXPECT_EQ(CELIX_SUCCESS, celixThread_detach(thread)); //ignore join on uninitialized thread
+ EXPECT_EQ(CELIX_SUCCESS, celixThread_kill(thread, SIGINT)); //ignore join on uninitialized thread
+
+ celix_thread_mutex_t mutex;
+ mutex.initialized = false;
+ EXPECT_EQ(CELIX_SUCCESS, celixThreadMutex_destroy(&mutex)); //ignore destroy on uninitialized mutex
+
+ celix_thread_cond_t cond;
+ cond.initialized = false;
+ EXPECT_EQ(CELIX_SUCCESS, celixThreadCondition_destroy(&cond)); //ignore destroy on uninitialized cond
+
+ celix_thread_rwlock_t rwlock;
+ rwlock.initialized = false;
+ EXPECT_EQ(CELIX_SUCCESS, celixThreadRwlock_destroy(&rwlock)); //ignore destroy on uninitialized rwlock
+}
+
+
static void * thread_test_func_create(void * arg) {
char ** test_str = (char**) arg;
*test_str = strdup("SUCCESS");
diff --git a/libs/utils/include/celix_threads.h b/libs/utils/include/celix_threads.h
index fba1e24..8d55721 100644
--- a/libs/utils/include/celix_threads.h
+++ b/libs/utils/include/celix_threads.h
@@ -30,13 +30,18 @@
extern "C" {
#endif
-struct celix_thread {
- bool threadInitialized;
- pthread_t thread;
-};
+/**
+ * @file celix_threads.h
+ * @brief Abstraction of thread utilities.
+ *
+ * This file contains the abstraction of thread utilities. Currently only pthread is supported.
+ */
-typedef pthread_once_t celix_thread_once_t;
-#define CELIX_THREAD_ONCE_INIT PTHREAD_ONCE_INIT
+
+struct celix_thread {
+ bool threadInitialized; /**< Indicates if the thread is initialized. */
+ pthread_t thread; /**< The actual thread.*/
+};
typedef struct celix_thread celix_thread_t;
typedef pthread_attr_t celix_thread_attr_t;
@@ -45,38 +50,135 @@
static const celix_thread_t celix_thread_default = {0, 0};
+/**
+ * @brief Create a new thread.
+ *
+ * Note will not check the initialized field when creating.
+ *
+ * @section errors Errors
+ * If an error occurs, the thread is not created and the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN Insufficient resources to create another thread.
+ * - EAGAIN A system-imposed limit on the number of threads was encountered.
+ * - EINVAL Invalid settings in attr.
+ * - EPERM No permission to set the scheduling policy and parameters specified in attr.
+ * @endsection
+ *
+ * @param[in,out] new_thread The created thread.
+ * @param[in] attr The thread attributes. Can be NULL for default attributes.
+ * @param[in] func The function to execute in the thread.
+ * @param[in] data The data passed to the function.
+ * @return CELIX_SUCCESS if the thread is created.
+ */
CELIX_UTILS_EXPORT celix_status_t
celixThread_create(celix_thread_t *new_thread, const celix_thread_attr_t *attr, celix_thread_start_t func, void *data);
+
/**
- * If supported by the platform sets the name of the thread.
+ * @brief If supported by the platform sets the name of the thread.
*/
CELIX_UTILS_EXPORT void celixThread_setName(celix_thread_t *thread, const char *threadName);
+/**
+ * @brief Exit the current thread.
+ *
+ * @param[in] exitStatus The exit status of the thread. This is output status for the celixThread_join function.
+ */
CELIX_UTILS_EXPORT void celixThread_exit(void *exitStatus);
+/**
+ * @brief Detach the thread.
+ *
+ * Will silently ignore if the thread is not initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EINVAL thread is not a joinable thread.
+ * - ESRCH No thread with the ID thread could be found.
+ *
+ * @param[in] thread The thread to detach.
+ * @return CELIX_SUCCESS if the thread is detached.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThread_detach(celix_thread_t thread);
-CELIX_UTILS_EXPORT celix_status_t celixThread_join(celix_thread_t thread, void **status);
+/**
+ * @brief Join the thread.
+ *
+ * Will silently ignore if the thread is not initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EDEADLK A deadlock was detected (e.g., two threads tried to join with each other); or thread specifies the calling thread.
+ * - EINVAL thread is not a joinable thread.
+ * - EINVAL Another thread is already waiting to join with this thread.
+ * - ESRCH No thread with the ID thread could be found.
+ * @endsection
+ *
+ * @param[in] thread The thread to join.
+ * @param[out] status The exit status of the thread.
+ * @return CELIX_SUCCESS if the thread is joined.
+ */
+CELIX_UTILS_EXPORT celix_status_t celixThread_join(celix_thread_t thread, void** status);
+/**
+ * @brief Kill the thread.
+ *
+ * Will silently ignore if the thread is not initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EINVAL An invalid signal was specified.
+ * @endsection
+ *
+ * @param[in] thread The thread to kill.
+ * @param[in] sig The signal to send to the thread.
+ * @return CELIX_SUCCESS if the thread is killed.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThread_kill(celix_thread_t thread, int sig);
+/**
+ * Return the current thread.
+ */
CELIX_UTILS_EXPORT celix_thread_t celixThread_self(void);
/**
- * Return true - as int - if the threads are equals
+ * @brief Return true - as int - if the threads are equals
* @param[in] thread1
* @param[in] thread2
* @return non-zero if the thread IDs t1 and t2 correspond to the same thread, otherwise it will return zero.
*/
CELIX_UTILS_EXPORT int celixThread_equals(celix_thread_t thread1, celix_thread_t thread2);
+/**
+ * @brief Check if the thread is initialized.
+ *
+ * @param[in] thread
+ * @return true if the thread is initialized.
+ */
CELIX_UTILS_EXPORT bool celixThread_initialized(celix_thread_t thread);
-typedef pthread_mutex_t celix_thread_mutex_t;
+typedef pthread_once_t celix_thread_once_t;
+#define CELIX_THREAD_ONCE_INIT PTHREAD_ONCE_INIT
+
+CELIX_UTILS_EXPORT celix_status_t celixThread_once(celix_thread_once_t *once_control, void (*init_routine)(void));
+
typedef pthread_mutexattr_t celix_thread_mutexattr_t;
+typedef struct celix_thread_mutex {
+ bool initialized; /**< Indicates if the thread is initialized. */
+ pthread_mutex_t pthreadMutex; /**< The actual mutex. */
+} celix_thread_mutex_t;
+
+#define CELIX_THREAD_MUTEX_INITIALIZER {true, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEXATTR_INITIALIZER}
+
//MUTEX TYPES
enum {
CELIX_THREAD_MUTEX_NORMAL,
@@ -85,13 +187,103 @@
CELIX_THREAD_MUTEX_DEFAULT
};
-
+/**
+ * @brief Create a mutex.
+ *
+ * Note will not check the initialized field when creating.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The system lacked the necessary resources (other than memory) to initialize another mutex.
+ * - ENOMEM Insufficient memory exists to initialize the mutex.
+ * - EPERM The caller does not have the privilege to perform the operation.
+ * - EINVAL The attributes object referenced by attr has the robust mutex attribute set without the process-shared
+ * attribute being set.
+ * @endsection
+ *
+ * @param[out] mutex The created mutex.
+ * @param[in] attr The mutex attributes. Can be NULL.
+ * @return CELIX_SUCCESS if the mutex is created.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_create(celix_thread_mutex_t *mutex, celix_thread_mutexattr_t *attr);
+/**
+ * @brief Destroy a mutex.
+ *
+ * Will silently ignore if the mutex is not initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The system lacked the necessary resources (other than memory) to initialize another mutex.
+ * - ENOMEM Insufficient memory exists to initialize the mutex.
+ * - EPERM The caller does not have the privilege to perform the operation.
+ * @endsection
+ *
+ * @param[in,out] mutex The mutex to destroy.
+ * @return CELIX_SUCCESS if the mutex is destroyed.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_destroy(celix_thread_mutex_t *mutex);
+/**
+ * @brief Check if the mutex is initialized.
+ */
+CELIX_UTILS_EXPORT bool celixThreadMutex_isInitialized(const celix_thread_mutex_t *mutex);
+
+/**
+ * @brief Lock a mutex.
+ *
+ * Will not check if the mutex is initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
+ * - EINVAL The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling
+ * thread's priority is higher than the mutex's current priority ceiling.
+ * - ENOTRECOVERABLE The state protected by the mutex is not recoverable.
+ * - EOWNERDEAD The mutex is a robust mutex and the process containing the previous owning thread terminated while
+ * holding the mutex lock. The mutex lock shall be acquired by the calling thread and it is up to the new owner to
+ * make the state consistent.
+ * - EDEADLK The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already owns the mutex.
+ * - EOWNERDEAD The mutex is a robust mutex and the previous owning thread terminated while holding the mutex lock.
+ * The mutex lock shall be acquired by the calling thread and it is up to the new owner to make the state consistent.
+ * - EDEADLK A deadlock condition was detected.
+ * @endsection
+ *
+ * @param[in] mutex The mutex to lock.
+ * @return CELIX_SUCCESS if the mutex is locked.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_lock(celix_thread_mutex_t *mutex);
+/**
+ * @brief Unlock a mutex.
+ *
+ * Will not check if the mutex is initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The mutex could not be acquired because the maximum number of recursive locks for mutex has been exceeded.
+ * - EINVAL The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling
+ * thread's priority is higher than the mutex's current priority ceiling.
+ * - ENOTRECOVERABLE The state protected by the mutex is not recoverable.
+ * - EOWNERDEAD The mutex is a robust mutex and the process containing the previous owning thread terminated while
+ * holding the mutex lock. The mutex lock shall be acquired by the calling thread and it is up to the new owner to
+ * make the state consistent.
+ * - EPERM The mutex type is PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, or the mutex is a robust mutex,
+ * and the current thread does not own the mutex.
+ * @endsection
+ *
+ * @param[in] mutex The mutex to unlock.
+ * @return CELIX_SUCCESS if the mutex is unlocked.
+ *
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadMutex_unlock(celix_thread_mutex_t *mutex);
CELIX_UTILS_EXPORT celix_status_t celixThreadMutexAttr_create(celix_thread_mutexattr_t *attr);
@@ -100,44 +292,186 @@
CELIX_UTILS_EXPORT celix_status_t celixThreadMutexAttr_settype(celix_thread_mutexattr_t *attr, int type);
-typedef pthread_rwlock_t celix_thread_rwlock_t;
typedef pthread_rwlockattr_t celix_thread_rwlockattr_t;
+typedef struct celix_thread_rwlock {
+ bool initialized;
+ pthread_rwlock_t pthreadRwLock;
+} celix_thread_rwlock_t;
+
+/**
+ * @brief Create a read-write lock.
+ *
+ * Note will not check the initialized field when creating.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The system lacked the necessary resources (other than memory) to initialize another read-write lock.
+ * - ENOMEM Insufficient memory exists to initialize the read-write lock.
+ * - EPERM The caller does not have the privilege to perform the operation.
+ * @endsection
+ *
+ * @param[out] lock The created read-write lock.
+ * @param[in] attr The read-write lock attributes. Can be NULL.
+ * @return CELIX_SUCCESS if the read-write lock is created.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_create(celix_thread_rwlock_t *lock, celix_thread_rwlockattr_t *attr);
+/**
+ * @brief Destroy a read-write lock.
+ *
+ * Will silently ignore if the lock is not initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ * - EAGAIN The system lacked the necessary resources (other than memory) to initialize another read-write lock.
+ * - ENOMEM Insufficient memory exists to initialize the read-write lock.
+ * - EPERM The caller does not have the privilege to perform the operation
+ * @endsection
+ *
+ * @param[in] lock The read-write lock to destroy.
+ * @return CELIX_SUCCESS if the read-write lock is destroyed.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_destroy(celix_thread_rwlock_t *lock);
+/**
+ * @brief Check if a read-write lock is initialized.
+ */
+CELIX_UTILS_EXPORT bool celixThreadRwlock_isInitialized(const celix_thread_rwlock_t *lock);
+
+/**
+ * @brief Lock a read-write lock for reading.
+ *
+ * Will not check if the lock is initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ * - EAGAIN The read lock could not be acquired because the maximum number of read locks for rwlock has been exceeded.
+ * - EDEADLK A deadlock condition was detected or the current thread already owns the read-write lock for writing.
+ * @endsection
+ *
+ * @param[in] lock The read-write lock to lock.
+ * @return CELIX_SUCCESS if the read-write lock is locked.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_readLock(celix_thread_rwlock_t *lock);
+/**
+ * @brief Lock a read-write lock for writing.
+ *
+ * Will not check if the lock is initialized.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ * - EDEADLK A deadlock condition was detected or the current thread already owns the read-write lock for writing
+ * or reading.
+ *
+ * @param[in] lock The read-write lock to lock.
+ * @return CELIX_SUCCESS if the read-write lock is locked.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_writeLock(celix_thread_rwlock_t *lock);
+/**
+ * @brief Unlock a read-write lock.
+ *
+ * Will not check if the lock is initialized.
+ *
+ * @param[in] lock The read-write lock to unlock.
+ * @return CELIX_SUCCESS if the read-write lock is unlocked.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlock_unlock(celix_thread_rwlock_t *lock);
+
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlockAttr_create(celix_thread_rwlockattr_t *attr);
CELIX_UTILS_EXPORT celix_status_t celixThreadRwlockAttr_destroy(celix_thread_rwlockattr_t *attr);
-//NOTE: No support yet for setting specific rw lock attributes
-
-typedef pthread_cond_t celix_thread_cond_t;
typedef pthread_condattr_t celix_thread_condattr_t;
+typedef struct celix_thread_cond {
+ bool initialized; /**< Indicates if the condition is initialized. */
+ pthread_cond_t pthreadCond; /**< The actual condition variable. */
+} celix_thread_cond_t;
+/**
+ * @brief Initialize a condition variable.
+ *
+ * Note will not check the initialized field when initializing.
+ *
+ * @section errors Errors
+ * If an error occurs, the function returns an error code.
+ *
+ * And if pthread is the underlying implementation:
+ * - EAGAIN The system lacked the necessary resources (other than memory) to initialize another condition variable.
+ * - ENOMEM Insufficient memory exists to initialize the condition variable.
+ * @endsection
+ *
+ * @param[in,out] condition The condition variable to initialize.
+ * @param[in] attr The condition variable attributes to use. Can be NULL.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_init(celix_thread_cond_t *condition, celix_thread_condattr_t *attr);
+/**
+ * @brief Destroy a condition variable.
+ *
+ * Will silently ignore if the condition variable is not initialized.
+ *
+ * @oarnam[in] condition The condition variable to destroy.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_destroy(celix_thread_cond_t *condition);
+/**
+ * @brief Check if a condition variable is initialized.
+ */
+CELIX_UTILS_EXPORT bool celixThreadCondition_isInitialized(const celix_thread_cond_t *condition);
+
+/**
+ * @brief Wait for a condition variable to be signaled.
+ *
+ * Will not check if the condition variable is initialized.
+ *
+ * @param[in] cond The condition to wait for.
+ * @param[in] mutex The mutex to use.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_wait(celix_thread_cond_t *cond, celix_thread_mutex_t *mutex);
+/**
+ * @brief Wait for a condition variable to be signaled or a timeout to occur.
+ *
+ * Will not check if the condition variable is initialized.
+ *
+ * @param[in] cond The condition to wait for.
+ * @param[in] mutex The mutex to use.
+ * @param[in] seconds The seconds to wait.
+ * @param[in] nanoseconds The nanoseconds to wait.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_timedwaitRelative(celix_thread_cond_t *cond, celix_thread_mutex_t *mutex, long seconds, long nanoseconds);
+/**
+ * @brief Broadcast a condition.
+ *
+ * @param[in] cond The condition to broadcast.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_broadcast(celix_thread_cond_t *cond);
+/**
+ * @brief Signal a condition.
+ *
+ * @param[in] cond The condition to signal.
+ * @return CELIX_SUCCESS if no errors are encountered.
+ */
CELIX_UTILS_EXPORT celix_status_t celixThreadCondition_signal(celix_thread_cond_t *cond);
-CELIX_UTILS_EXPORT celix_status_t celixThread_once(celix_thread_once_t *once_control, void (*init_routine)(void));
-
//Thread Specific Storage (TSS) Abstraction
-typedef pthread_key_t celix_tss_key_t;
+typedef struct celix_tss_key {
+ bool initialized;
+ pthread_key_t pthreadKey;
+} celix_tss_key_t;
/**
* @brief Create a thread specific storage key visible for all threads.
@@ -151,39 +485,39 @@
* non-NULL destructor pointer, and the thread has a non-NULL value associated with that key, the value of the key is
* set to NULL, and then the function pointed to is called with the previously associated value as its sole argument.
* The order of destructor calls is unspecified if more than one destructor exists for a thread when it exits.
+ *
+ * Note will not check the initialized field when creating.
*
* @param key The key to create.
* @param destroyFunction The function to call when the key is destroyed.
- * @return CELIX_SUCCESS if the key is created successfully.
- *
- * @retval CELIX_ENOMEM if there was insufficient memory for the key creation.
- * @retval CELIX_EAGAIN if the system lacked the necessary resources to create another thread specific data key.
+ * @return CELIX_SUCCESS if the key is created successfully; otherwise, an error code is returned.
*/
CELIX_UTILS_EXPORT celix_status_t celix_tss_create(celix_tss_key_t* key, void (*destroyFunction)(void*));
/**
+ * @brief Check if a thread specific storage key is initialized.
+ */
+CELIX_UTILS_EXPORT bool celix_tss_isInitialized(const celix_tss_key_t* key);
+
+/**
* @brief Delete a thread specific storage key previously created by celix_tss_create.
+ *
+ * Will silently ignore if the key is NULL or key is not initialized.
*
* @param key The key to delete.
- * @return CELIX_SUCCESS if the key is deleted successfully.
- *
- * @retval CELIX_ILLEGAL_ARGUMENT if the key is invalid.
- * @retval CELIX_ILLEGAL_STATE if the key is otherwise not deleted successfully.
+ * @return CELIX_SUCCESS if the key is deleted successfully; otherwise, an error code is returned.
*/
-CELIX_UTILS_EXPORT celix_status_t celix_tss_delete(celix_tss_key_t key);
+CELIX_UTILS_EXPORT celix_status_t celix_tss_delete(celix_tss_key_t* key);
/**
* @brief Set a thread-specific value for the provide thread specific storage key.
*
* @param key The key to set the value for.
* @param value The thread-specific value to set.
- * @return CELIX_SUCCESS if the value is set successfully.
- *
- * @retval CELIX_ILLEGAL_ARGUMENT if the key is invalid.
- * @retval CELIX_ENOMEM if there was insufficient memory to set the value.
- * @retval CELIX_ILLEGAL_STATE if the value is not set successfully.
+ * @return CELIX_SUCCESS if the value is set successfully; otherwise, an error code is returned.
+ * @retval CELIX_ILLEGAL_STATE if the key is not initialized.
*/
-CELIX_UTILS_EXPORT celix_status_t celix_tss_set(celix_tss_key_t key, void* value);
+CELIX_UTILS_EXPORT celix_status_t celix_tss_set(const celix_tss_key_t* key, void* value);
/**
* @brief Get the thread-specific value for the provided thread specific storage key.
@@ -193,7 +527,7 @@
*
* @retval NULL if the key is invalid or there is no thread-specific value set for the key.
*/
-CELIX_UTILS_EXPORT void* celix_tss_get(celix_tss_key_t key);
+CELIX_UTILS_EXPORT void* celix_tss_get(const celix_tss_key_t* key);
#ifdef __cplusplus
}
diff --git a/libs/utils/src/celix_err.c b/libs/utils/src/celix_err.c
index 6f3ad7e..8c4b426 100644
--- a/libs/utils/src/celix_err.c
+++ b/libs/utils/src/celix_err.c
@@ -50,7 +50,7 @@
return NULL;
}
- celix_err_t* err = celix_tss_get(celix_err_tssKey);
+ celix_err_t* err = celix_tss_get(&celix_err_tssKey);
if (err) {
return err;
}
@@ -58,7 +58,7 @@
err = malloc(sizeof(*err));
if (err) {
err->pos = 0; //no entry
- celix_status_t status = celix_tss_set(celix_err_tssKey, err);
+ celix_status_t status = celix_tss_set(&celix_err_tssKey, err);
if (status != CELIX_SUCCESS) {
fprintf(stderr, "Failed to set thread specific storage for celix_err\n");
free(err);
@@ -85,7 +85,7 @@
return;
}
- celix_status_t status = celix_tss_delete(celix_err_tssKey);
+ celix_status_t status = celix_tss_delete(&celix_err_tssKey);
if (status != CELIX_SUCCESS) {
fprintf(stderr,"Failed to delete thread specific storage key for celix_err\n");
}
diff --git a/libs/utils/src/celix_threads.c b/libs/utils/src/celix_threads.c
index 088f216..49bd057 100644
--- a/libs/utils/src/celix_threads.c
+++ b/libs/utils/src/celix_threads.c
@@ -16,13 +16,6 @@
* specific language governing permissions and limitations
* under the License.
*/
-/**
- * celix_threads.c
- *
- * \date 4 Jun 2014
- * \author <a href="mailto:dev@celix.apache.org">Apache Celix Project Team</a>
- * \copyright Apache License, Version 2.0
- */
#include <stdlib.h>
#include <sys/time.h>
@@ -32,16 +25,9 @@
#include "celix_utils.h"
-celix_status_t celixThread_create(celix_thread_t *new_thread, const celix_thread_attr_t *attr, celix_thread_start_t func, void *data) {
- celix_status_t status = CELIX_SUCCESS;
-
- if (pthread_create(&(*new_thread).thread, attr, func, data) != 0) {
- status = CELIX_BUNDLE_EXCEPTION;
- }
- else {
- __atomic_store_n(&(*new_thread).threadInitialized, true, __ATOMIC_RELEASE);
- }
-
+celix_status_t celixThread_create(celix_thread_t *thread, const celix_thread_attr_t *attr, celix_thread_start_t func, void *data) {
+ celix_status_t status = pthread_create(&thread->thread, attr, func, data);
+ thread->threadInitialized = (status == CELIX_SUCCESS);
return status;
}
@@ -61,24 +47,24 @@
}
celix_status_t celixThread_detach(celix_thread_t thread) {
- return pthread_detach(thread.thread);
+ if (celixThread_initialized(thread)) {
+ return pthread_detach(thread.thread);
+ }
+ return CELIX_SUCCESS;
}
-celix_status_t celixThread_join(celix_thread_t thread, void **retVal) {
- celix_status_t status = CELIX_SUCCESS;
-
- if (pthread_join(thread.thread, retVal) != 0) {
- status = CELIX_BUNDLE_EXCEPTION;
+celix_status_t celixThread_join(celix_thread_t thread, void** retVal) {
+ if (celixThread_initialized(thread)) {
+ return pthread_join(thread.thread, retVal);
}
-
- // #TODO make thread a pointer? Now this statement has no effect
- // thread.threadInitialized = false;
-
- return status;
+ return CELIX_SUCCESS;
}
celix_status_t celixThread_kill(celix_thread_t thread, int sig) {
- return pthread_kill(thread.thread, sig);
+ if (celixThread_initialized(thread)) {
+ return pthread_kill(thread.thread, sig);
+ }
+ return CELIX_SUCCESS;
}
celix_thread_t celixThread_self() {
@@ -100,19 +86,30 @@
celix_status_t celixThreadMutex_create(celix_thread_mutex_t *mutex, celix_thread_mutexattr_t *attr) {
- return pthread_mutex_init(mutex, attr);
+ celix_status_t status = pthread_mutex_init(&mutex->pthreadMutex, attr);
+ if (status != CELIX_SUCCESS) {
+ __atomic_store_n(&mutex->initialized, false, __ATOMIC_RELEASE);
+ }
+ return status;
}
celix_status_t celixThreadMutex_destroy(celix_thread_mutex_t *mutex) {
- return pthread_mutex_destroy(mutex);
+ if (celixThreadMutex_isInitialized(mutex)) {
+ return pthread_mutex_destroy(&mutex->pthreadMutex);
+ }
+ return CELIX_SUCCESS;
+}
+
+bool celixThreadMutex_isInitialized(const celix_thread_mutex_t *mutex) {
+ return __atomic_load_n(&mutex->initialized, __ATOMIC_ACQUIRE);
}
celix_status_t celixThreadMutex_lock(celix_thread_mutex_t *mutex) {
- return pthread_mutex_lock(mutex);
+ return pthread_mutex_lock(&mutex->pthreadMutex);
}
celix_status_t celixThreadMutex_unlock(celix_thread_mutex_t *mutex) {
- return pthread_mutex_unlock(mutex);
+ return pthread_mutex_unlock(&mutex->pthreadMutex);
}
celix_status_t celixThreadMutexAttr_create(celix_thread_mutexattr_t *attr) {
@@ -146,31 +143,38 @@
}
celix_status_t celixThreadCondition_init(celix_thread_cond_t *condition, celix_thread_condattr_t *attr) {
-#ifdef __APPLE__
- return pthread_cond_init(condition, attr);
-#else
celix_status_t status = CELIX_SUCCESS;
- if(attr) {
+#ifdef __APPLE__
+ status = pthread_cond_init(condition, attr);
+#else
+ if (attr) {
status = pthread_condattr_setclock(attr, CLOCK_MONOTONIC);
- status = CELIX_DO_IF(status, pthread_cond_init(condition, attr));
- }
- else {
+ status = CELIX_DO_IF(status, pthread_cond_init(&condition->pthreadCond, attr));
+ } else {
celix_thread_condattr_t condattr;
(void)pthread_condattr_init(&condattr); // always return 0
status = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
- status = CELIX_DO_IF(status, pthread_cond_init(condition, &condattr));
+ status = CELIX_DO_IF(status, pthread_cond_init(&condition->pthreadCond, &condattr));
(void)pthread_condattr_destroy(&condattr); // always return 0
}
- return status;
#endif
+ condition->initialized = (status == CELIX_SUCCESS);
+ return status;
}
-celix_status_t celixThreadCondition_destroy(celix_thread_cond_t *condition) {
- return pthread_cond_destroy(condition);
+celix_status_t celixThreadCondition_destroy(celix_thread_cond_t* cond) {
+ if (celixThreadCondition_isInitialized(cond)) {
+ return pthread_cond_destroy(&cond->pthreadCond);
+ }
+ return CELIX_SUCCESS;
+}
+
+bool celixThreadCondition_isInitialized(const celix_thread_cond_t* cond) {
+ return __atomic_load_n(&cond->initialized, __ATOMIC_ACQUIRE);
}
-celix_status_t celixThreadCondition_wait(celix_thread_cond_t *cond, celix_thread_mutex_t *mutex) {
- return pthread_cond_wait(cond, mutex);
+celix_status_t celixThreadCondition_wait(celix_thread_cond_t* cond, celix_thread_mutex_t* mutex) {
+ return pthread_cond_wait(&cond->pthreadCond, &mutex->pthreadMutex);
}
#ifdef __APPLE__
@@ -193,36 +197,45 @@
time.tv_nsec -= CELIX_NS_IN_SEC;
}
}
- return pthread_cond_timedwait(cond, mutex, &time);
+ return pthread_cond_timedwait(&cond->pthreadCond, &mutex->pthreadMutex, &time);
}
#endif
celix_status_t celixThreadCondition_broadcast(celix_thread_cond_t *cond) {
- return pthread_cond_broadcast(cond);
+ return pthread_cond_broadcast(&cond->pthreadCond);
}
celix_status_t celixThreadCondition_signal(celix_thread_cond_t *cond) {
- return pthread_cond_signal(cond);
+ return pthread_cond_signal(&cond->pthreadCond);
}
celix_status_t celixThreadRwlock_create(celix_thread_rwlock_t *lock, celix_thread_rwlockattr_t *attr) {
- return pthread_rwlock_init(lock, attr);
+ celix_status_t status = pthread_rwlock_init(&lock->pthreadRwLock, attr);
+ lock->initialized = (status == CELIX_SUCCESS);
+ return status;
}
celix_status_t celixThreadRwlock_destroy(celix_thread_rwlock_t *lock) {
- return pthread_rwlock_destroy(lock);
+ if (!celixThreadRwlock_isInitialized(lock)) {
+ return pthread_rwlock_destroy(&lock->pthreadRwLock);
+ }
+ return CELIX_SUCCESS;
+}
+
+bool celixThreadRwlock_isInitialized(const celix_thread_rwlock_t *lock) {
+ return __atomic_load_n(&lock->initialized, __ATOMIC_ACQUIRE);
}
celix_status_t celixThreadRwlock_readLock(celix_thread_rwlock_t *lock) {
- return pthread_rwlock_rdlock(lock);
+ return pthread_rwlock_rdlock(&lock->pthreadRwLock);
}
celix_status_t celixThreadRwlock_writeLock(celix_thread_rwlock_t *lock) {
- return pthread_rwlock_wrlock(lock);
+ return pthread_rwlock_wrlock(&lock->pthreadRwLock);
}
celix_status_t celixThreadRwlock_unlock(celix_thread_rwlock_t *lock) {
- return pthread_rwlock_unlock(lock);
+ return pthread_rwlock_unlock(&lock->pthreadRwLock);
}
celix_status_t celixThreadRwlockAttr_create(celix_thread_rwlockattr_t *attr) {
@@ -238,17 +251,32 @@
}
celix_status_t celix_tss_create(celix_tss_key_t* key, void (*destroyFunction)(void*)) {
- return pthread_key_create(key, destroyFunction);
+ celix_status_t status = pthread_key_create(&key->pthreadKey, destroyFunction);
+ key->initialized = (status == CELIX_SUCCESS);
+ return status;
}
-celix_status_t celix_tss_delete(celix_tss_key_t key) {
- return pthread_key_delete(key);
+bool celix_tss_isInitialized(const celix_tss_key_t* key) {
+ return __atomic_load_n(&key->initialized, __ATOMIC_ACQUIRE);
}
-celix_status_t celix_tss_set(celix_tss_key_t key, void* value) {
- return pthread_setspecific(key, value);
+celix_status_t celix_tss_delete(celix_tss_key_t* key) {
+ if (key && celix_tss_isInitialized(key)) {
+ return pthread_key_delete(key->pthreadKey);
+ }
+ return CELIX_SUCCESS;
}
-void* celix_tss_get(celix_tss_key_t key) {
- return pthread_getspecific(key);
+celix_status_t celix_tss_set(const celix_tss_key_t* key, void* value) {
+ if (!celix_tss_isInitialized(key)) {
+ return CELIX_ILLEGAL_STATE;
+ }
+ return pthread_setspecific(key->pthreadKey, value);
+}
+
+void* celix_tss_get(const celix_tss_key_t* key) {
+ if (!celix_tss_isInitialized(key)) {
+ return NULL;
+ }
+ return pthread_getspecific(key->pthreadKey);
}