diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2019-12-01 11:33:23 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-12-01 11:33:23 +0000 |
| commit | 3fd5c3cd851d8f4dfd441141ca7e96889f069933 (patch) | |
| tree | 67f47e79f5c5bb80a3ed1b1e9d79a61c08c0a29d /core/sys/unix | |
| parent | 0c0c83ee295fe8787a4bdc8b826a5432abba2ca9 (diff) | |
| parent | 99121d6ff2b02f3d16b791eb103bb9f9e8b96475 (diff) | |
Merge pull request #458 from Tetralux/linux-threads
Implement core:thread and core:sync on Unix using pthreads
Diffstat (limited to 'core/sys/unix')
| -rw-r--r-- | core/sys/unix/pthread_darwin.odin | 80 | ||||
| -rw-r--r-- | core/sys/unix/pthread_linux.odin | 106 | ||||
| -rw-r--r-- | core/sys/unix/pthread_unix.odin | 107 |
3 files changed, 293 insertions, 0 deletions
diff --git a/core/sys/unix/pthread_darwin.odin b/core/sys/unix/pthread_darwin.odin new file mode 100644 index 000000000..97a750b9b --- /dev/null +++ b/core/sys/unix/pthread_darwin.odin @@ -0,0 +1,80 @@ +package unix; + +import "core:c" + +// NOTE(tetra): No 32-bit Macs. +// Source: _pthread_types.h on my Mac. +PTHREAD_SIZE :: 8176; +PTHREAD_ATTR_SIZE :: 56; +PTHREAD_MUTEXATTR_SIZE :: 8; +PTHREAD_MUTEX_SIZE :: 56; +PTHREAD_CONDATTR_SIZE :: 8; +PTHREAD_COND_SIZE :: 40; +PTHREAD_ONCE_SIZE :: 8; +PTHREAD_RWLOCK_SIZE :: 192; +PTHREAD_RWLOCKATTR_SIZE :: 16; + +pthread_t :: opaque struct #align 16 { + sig: c.long, + cleanup_stack: rawptr, + _: [PTHREAD_SIZE] c.char, +}; + +pthread_attr_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_ATTR_SIZE] c.char, +}; + +pthread_cond_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_COND_SIZE] c.char, +}; + +pthread_condattr_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_CONDATTR_SIZE] c.char, +}; + +pthread_mutex_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_MUTEX_SIZE] c.char, +}; + +pthread_mutexattr_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_MUTEXATTR_SIZE] c.char, +}; + +pthread_once_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_ONCE_SIZE] c.char, +}; + +pthread_rwlock_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_RWLOCK_SIZE] c.char, +}; + +pthread_rwlockattr_t :: opaque struct #align 16 { + sig: c.long, + _: [PTHREAD_RWLOCKATTR_SIZE] c.char, +}; + +SCHED_OTHER :: 1; // Avoid if you are writing portable software. +SCHED_FIFO :: 4; +SCHED_RR :: 2; // Round robin. + +SCHED_PARAM_SIZE :: 4; + +sched_param :: struct { + sched_priority: c.int, + _: [SCHED_PARAM_SIZE] c.char, +}; + +// Source: https://github.com/apple/darwin-libpthread/blob/03c4628c8940cca6fd6a82957f683af804f62e7f/pthread/pthread.h#L138 +PTHREAD_CREATE_JOINABLE :: 1; +PTHREAD_CREATE_DETACHED :: 2; +PTHREAD_INHERIT_SCHED :: 1; +PTHREAD_EXPLICIT_SCHED :: 2; +PTHREAD_PROCESS_SHARED :: 1; +PTHREAD_PROCESS_PRIVATE :: 2; diff --git a/core/sys/unix/pthread_linux.odin b/core/sys/unix/pthread_linux.odin new file mode 100644 index 000000000..18ef09a69 --- /dev/null +++ b/core/sys/unix/pthread_linux.odin @@ -0,0 +1,106 @@ +package unix; + +import "core:c" + +// TODO(tetra): For robustness, I'd like to mark this with align 16. +// I cannot currently do this. +// And at the time of writing there is a bug with putting it +// as the only field in a struct. +pthread_t :: distinct u64; +// pthread_t :: struct #align 16 { x: u64 }; + +// NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my +// Linux machine. + +PTHREAD_COND_T_SIZE :: 48; + +PTHREAD_MUTEXATTR_T_SIZE :: 4; +PTHREAD_CONDATTR_T_SIZE :: 4; +PTHREAD_RWLOCKATTR_T_SIZE :: 8; +PTHREAD_BARRIERATTR_T_SIZE :: 4; + +// WARNING: The sizes of these things are different yet again +// on non-X86! +when size_of(int) == 8 { + PTHREAD_ATTR_T_SIZE :: 56; + PTHREAD_MUTEX_T_SIZE :: 40; + PTHREAD_RWLOCK_T_SIZE :: 56; + PTHREAD_BARRIER_T_SIZE :: 32; +} else when size_of(int) == 4 { + PTHREAD_ATTR_T_SIZE :: 32; + PTHREAD_MUTEX_T_SIZE :: 32; + PTHREAD_RWLOCK_T_SIZE :: 44; + PTHREAD_BARRIER_T_SIZE :: 20; +} + +pthread_cond_t :: opaque struct #align 16 { + _: [PTHREAD_COND_T_SIZE] c.char, +}; +pthread_mutex_t :: opaque struct #align 16 { + _: [PTHREAD_MUTEX_T_SIZE] c.char, +}; +pthread_rwlock_t :: opaque struct #align 16 { + _: [PTHREAD_RWLOCK_T_SIZE] c.char, +}; +pthread_barrier_t :: opaque struct #align 16 { + _: [PTHREAD_BARRIER_T_SIZE] c.char, +}; + +pthread_attr_t :: opaque struct #align 16 { + _: [PTHREAD_ATTR_T_SIZE] c.char, +}; +pthread_condattr_t :: opaque struct #align 16 { + _: [PTHREAD_CONDATTR_T_SIZE] c.char, +}; +pthread_mutexattr_t :: opaque struct #align 16 { + _: [PTHREAD_MUTEXATTR_T_SIZE] c.char, +}; +pthread_rwlockattr_t :: opaque struct #align 16 { + _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, +}; +pthread_barrierattr_t :: opaque struct #align 16 { + _: [PTHREAD_BARRIERATTR_T_SIZE] c.char, +}; + + +// TODO(tetra, 2019-11-01): Maybe make `enum c.int`s for these? +PTHREAD_CREATE_JOINABLE :: 0; +PTHREAD_CREATE_DETACHED :: 1; +PTHREAD_INHERIT_SCHED :: 0; +PTHREAD_EXPLICIT_SCHED :: 1; +PTHREAD_PROCESS_PRIVATE :: 0; +PTHREAD_PROCESS_SHARED :: 1; + +SCHED_OTHER :: 0; +SCHED_FIFO :: 1; +SCHED_RR :: 2; // Round robin. + +sched_param :: struct { + sched_priority: c.int, +} + +sem_t :: struct #align 16 { + _: [SEM_T_SIZE] c.char, +} + +when size_of(int) == 8 { + SEM_T_SIZE :: 32; +} else when size_of(int) == 4 { + SEM_T_SIZE :: 16; +} + +foreign import "system:pthread" + +@(default_calling_convention="c") +foreign pthread { + // create named semaphore. + // used in process-shared semaphores. + sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---; + + sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---; + sem_destroy :: proc(sem: ^sem_t) -> c.int ---; + sem_post :: proc(sem: ^sem_t) -> c.int ---; + sem_wait :: proc(sem: ^sem_t) -> c.int ---; + sem_trywait :: proc(sem: ^sem_t) -> c.int ---; + // sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---; +} diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin new file mode 100644 index 000000000..885048a59 --- /dev/null +++ b/core/sys/unix/pthread_unix.odin @@ -0,0 +1,107 @@ +package unix; + +foreign import "system:pthread" + +import "core:c" +import "core:time" + +// +// On success, these functions return 0. +// + +@(default_calling_convention="c") +foreign pthread { + pthread_create :: proc(t: ^pthread_t, attrs: ^pthread_attr_t, routine: proc(data: rawptr) -> rawptr, arg: rawptr) -> c.int ---; + + // retval is a pointer to a location to put the return value of the thread proc. + pthread_join :: proc(t: pthread_t, retval: rawptr) -> c.int ---; + + pthread_self :: proc() -> pthread_t ---; + + pthread_equal :: proc(a, b: pthread_t) -> b32 ---; + + sched_get_priority_min :: proc(policy: c.int) -> c.int ---; + sched_get_priority_max :: proc(policy: c.int) -> c.int ---; + + // NOTE: POSIX says this can fail with OOM. + pthread_attr_init :: proc(attrs: ^pthread_attr_t) -> c.int ---; + + pthread_attr_destroy :: proc(attrs: ^pthread_attr_t) -> c.int ---; + + pthread_attr_getschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int ---; + pthread_attr_setschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int ---; + + pthread_attr_getschedpolicy :: proc(t: ^pthread_attr_t, policy: ^c.int) -> c.int ---; + pthread_attr_setschedpolicy :: proc(t: ^pthread_attr_t, policy: c.int) -> c.int ---; + + // states: PTHREAD_CREATE_DETACHED, PTHREAD_CREATE_JOINABLE + pthread_attr_setdetachstate :: proc(attrs: ^pthread_attr_t, detach_state: c.int) -> c.int ---; + + // scheds: PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED + pthread_attr_setinheritsched :: proc(attrs: ^pthread_attr_t, sched: c.int) -> c.int ---; + + // NOTE(tetra, 2019-11-06): WARNING: Different systems have different alignment requirements. + // For maximum usefulness, use the OS's page size. + // ALSO VERY MAJOR WARNING: `stack_ptr` must be the LAST byte of the stack on systems + // where the stack grows downwards, which is the common case, so far as I know. + // On systems where it grows upwards, give the FIRST byte instead. + // ALSO SLIGHTLY LESS MAJOR WARNING: Using this procedure DISABLES automatically-provided + // guard pages. If you are using this procedure, YOU must set them up manually. + // If you forget to do this, you WILL get stack corruption bugs if you do not EXTREMELY + // know what you are doing! + pthread_attr_setstack :: proc(attrs: ^pthread_attr_t, stack_ptr: rawptr, stack_size: u64) -> c.int ---; + pthread_attr_getstack :: proc(attrs: ^pthread_attr_t, stack_ptr: ^rawptr, stack_size: ^u64) -> c.int ---; +} + +@(default_calling_convention="c") +foreign pthread { + // NOTE: POSIX says this can fail with OOM. + pthread_cond_init :: proc(cond: ^pthread_cond_t, attrs: ^pthread_condattr_t) -> c.int ---; + + pthread_cond_destroy :: proc(cond: ^pthread_cond_t) -> c.int ---; + + pthread_cond_signal :: proc(cond: ^pthread_cond_t) -> c.int ---; + + // same as signal, but wakes up _all_ threads that are waiting + pthread_cond_broadcast :: proc(cond: ^pthread_cond_t) -> c.int ---; + + + // assumes the mutex is pre-locked + pthread_cond_wait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t) -> c.int ---; + pthread_cond_timedwait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t, timeout: ^time.TimeSpec) -> c.int ---; + + pthread_condattr_init :: proc(attrs: ^pthread_condattr_t) -> c.int ---; + pthread_condattr_destroy :: proc(attrs: ^pthread_condattr_t) -> c.int ---; + + // p-shared = "process-shared" - i.e: is this condition shared among multiple processes? + // values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED + pthread_condattr_setpshared :: proc(attrs: ^pthread_condattr_t, value: c.int) -> c.int ---; + pthread_condattr_getpshared :: proc(attrs: ^pthread_condattr_t, result: ^c.int) -> c.int ---; + +} + +@(default_calling_convention="c") +foreign pthread { + // NOTE: POSIX says this can fail with OOM. + pthread_mutex_init :: proc(mutex: ^pthread_mutex_t, attrs: ^pthread_mutexattr_t) -> c.int ---; + + pthread_mutex_destroy :: proc(mutex: ^pthread_mutex_t) -> c.int ---; + + pthread_mutex_trylock :: proc(mutex: ^pthread_mutex_t) -> c.int ---; + + pthread_mutex_lock :: proc(mutex: ^pthread_mutex_t) -> c.int ---; + + pthread_mutex_timedlock :: proc(mutex: ^pthread_mutex_t, timeout: ^time.TimeSpec) -> c.int ---; + + pthread_mutex_unlock :: proc(mutex: ^pthread_mutex_t) -> c.int ---; + + + pthread_mutexattr_init :: proc(attrs: ^pthread_mutexattr_t) -> c.int ---; + pthread_mutexattr_destroy :: proc(attrs: ^pthread_mutexattr_t) -> c.int ---; + + // p-shared = "process-shared" - i.e: is this mutex shared among multiple processes? + // values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED + pthread_mutexattr_setpshared :: proc(attrs: ^pthread_mutexattr_t, value: c.int) -> c.int ---; + pthread_mutexattr_getpshared :: proc(attrs: ^pthread_mutexattr_t, result: ^c.int) -> c.int ---; + +}
\ No newline at end of file |