aboutsummaryrefslogtreecommitdiff
path: root/src/std/thread.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/std/thread.c')
-rw-r--r--src/std/thread.c140
1 files changed, 140 insertions, 0 deletions
diff --git a/src/std/thread.c b/src/std/thread.c
new file mode 100644
index 0000000..f717865
--- /dev/null
+++ b/src/std/thread.c
@@ -0,0 +1,140 @@
+#include "../../include/std/thread.h"
+#include "../../include/std/log.h"
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/sysinfo.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+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;
+}
+
+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;
+ 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");
+ }
+ return result;
+}
+
+int amal_mutex_unlock(amal_mutex *self) {
+ int result;
+ const char *identifier;
+ identifier = self->lock_identifier;
+ result = pthread_mutex_unlock(&self->mutex);
+ 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");
+ }
+ return result;
+}
+
+void amal_mutex_tryunlock(amal_mutex *self) {
+ int _;
+ (void)_;
+ _ = 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();
+} \ No newline at end of file