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);
 }