#include "../../include/std/thread.h" #include "../../include/std/log.h" #include #include #include #include #include #include #include static int thread_type_to_system_thread_type(amal_thread_type thread_type) { switch(thread_type) { case AMAL_THREAD_JOINABLE: return PTHREAD_CREATE_JOINABLE; case AMAL_THREAD_DETACHED: return PTHREAD_CREATE_DETACHED; } assert(bool_false); return PTHREAD_CREATE_JOINABLE; } int amal_thread_create(amal_thread *self, amal_thread_type thread_type, const char *name, AmalThreadCallbackFunc callback_func, void *userdata) { int result; self->name = name; self->thread_id = 0; self->cancellable = bool_false; self->destroyable = bool_false; if((result = pthread_attr_init(&self->thread_attr)) != 0) { perror("amal_thread_create"); return result; } self->destroyable = bool_true; if((result = pthread_attr_setdetachstate(&self->thread_attr, thread_type_to_system_thread_type(thread_type))) != 0) { perror("amal_thread_create"); return result; } if((result = pthread_create(&self->thread_id, NULL, callback_func, userdata)) != 0) { perror("amal_thread_create"); return result; } self->cancellable = bool_true; return 0; } int amal_thread_deinit(amal_thread *self) { int r1; int r2; r1 = 0; r2 = 0; if(self->cancellable) { r1 = pthread_cancel(self->thread_id); self->cancellable = bool_false; } if(self->destroyable) { r2 = pthread_attr_destroy(&self->thread_attr); self->destroyable = bool_false; } return r1 != 0 ? r1 : r2; } int amal_thread_detach(amal_thread *self) { int result_err; int thread_type; if((result_err = pthread_attr_getdetachstate(&self->thread_attr, &thread_type)) != 0) return result_err; if(thread_type != PTHREAD_CREATE_DETACHED) return AMAL_THREAD_ERR; if((result_err = pthread_detach(self->thread_id)) != 0) return result_err; self->cancellable = bool_false; return 0; } int amal_thread_join(amal_thread *self, void **result) { int result_err; int thread_type; if((result_err = pthread_attr_getdetachstate(&self->thread_attr, &thread_type)) != 0) return result_err; if(thread_type != PTHREAD_CREATE_JOINABLE) return AMAL_THREAD_NOT_JOINABLE; if((result_err = pthread_join(self->thread_id, result)) != 0) return result_err == EINVAL ? AMAL_THREAD_NOT_JOINABLE : result_err; self->cancellable = bool_false; return 0; } void amal_mutex_init(amal_mutex *self) { pthread_mutex_init(&self->mutex, NULL); /* TODO: pthread_mutex_destroy in amal_mutex_deinit */ self->lock_identifier = NULL; } void amal_mutex_deinit(amal_mutex *self) { pthread_mutex_destroy(&self->mutex); } static long amal_process_get_id() { return getpid(); } static long amal_thread_get_id() { return syscall(SYS_gettid); } int amal_mutex_lock(amal_mutex *self, const char *lock_identifier) { int result; result = pthread_mutex_lock(&self->mutex); self->lock_identifier = lock_identifier; #ifdef AMAL_MUTEX_DEBUG if(result == 0 && self->lock_identifier) { amal_log_debug("amal_mutex_lock: mutex locked by thread %lu (%s), identification: %s", amal_thread_get_id(), amal_thread_is_main() ? "main" : "not main", self->lock_identifier ? self->lock_identifier : "none"); } #endif return result; } int amal_mutex_unlock(amal_mutex *self) { int result; #ifdef AMAL_MUTEX_DEBUG const char *identifier; identifier = self->lock_identifier; #endif result = pthread_mutex_unlock(&self->mutex); #ifdef AMAL_MUTEX_DEBUG if(result == 0 && identifier) { amal_log_debug("amal_mutex_unlock: mutex unlocked by thread %lu (%s), identification: %s", amal_thread_get_id(), amal_thread_is_main() ? "main" : "not main", identifier ? identifier : "none"); } #endif return result; } void amal_mutex_tryunlock(amal_mutex *self) { ignore_result_int(amal_mutex_unlock(self)); } bool amal_thread_is_main() { /* TODO: This only works for linux, use equivalent functions on other platforms */ return amal_thread_get_id() == amal_process_get_id(); } int amal_get_usable_thread_count() { return get_nprocs(); }