aboutsummaryrefslogtreecommitdiff
path: root/core/sys
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2019-12-01 11:33:23 +0000
committerGitHub <noreply@github.com>2019-12-01 11:33:23 +0000
commit3fd5c3cd851d8f4dfd441141ca7e96889f069933 (patch)
tree67f47e79f5c5bb80a3ed1b1e9d79a61c08c0a29d /core/sys
parent0c0c83ee295fe8787a4bdc8b826a5432abba2ca9 (diff)
parent99121d6ff2b02f3d16b791eb103bb9f9e8b96475 (diff)
Merge pull request #458 from Tetralux/linux-threads
Implement core:thread and core:sync on Unix using pthreads
Diffstat (limited to 'core/sys')
-rw-r--r--core/sys/darwin/mach_darwin.odin29
-rw-r--r--core/sys/unix/pthread_darwin.odin80
-rw-r--r--core/sys/unix/pthread_linux.odin106
-rw-r--r--core/sys/unix/pthread_unix.odin107
-rw-r--r--core/sys/win32/general.odin19
-rw-r--r--core/sys/win32/kernel32.odin1
6 files changed, 342 insertions, 0 deletions
diff --git a/core/sys/darwin/mach_darwin.odin b/core/sys/darwin/mach_darwin.odin
new file mode 100644
index 000000000..52a145507
--- /dev/null
+++ b/core/sys/darwin/mach_darwin.odin
@@ -0,0 +1,29 @@
+package darwin;
+
+foreign import "system:pthread"
+
+import "core:c"
+
+// NOTE(tetra): Unclear whether these should be aligned 16 or not.
+// However all other sync primitives are aligned for robustness.
+// I cannot currently align these though.
+// See core/sys/unix/pthread_linux.odin/pthread_t.
+task_t :: distinct u64;
+semaphore_t :: distinct u64;
+
+kern_return_t :: distinct u64;
+thread_act_t :: distinct u64;
+
+@(default_calling_convention="c")
+foreign pthread {
+ mach_task_self :: proc() -> task_t ---;
+
+ semaphore_create :: proc(task: task_t, semaphore: ^semaphore_t, policy, value: c.int) -> kern_return_t ---;
+ semaphore_destroy :: proc(task: task_t, semaphore: semaphore_t) -> kern_return_t ---;
+
+ semaphore_signal :: proc(semaphore: semaphore_t) -> kern_return_t ---;
+ semaphore_signal_all :: proc(semaphore: semaphore_t) -> kern_return_t ---;
+ semaphore_signal_thread :: proc(semaphore: semaphore_t, thread: thread_act_t) -> kern_return_t ---;
+
+ semaphore_wait :: proc(semaphore: semaphore_t) -> kern_return_t ---;
+}
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
diff --git a/core/sys/win32/general.odin b/core/sys/win32/general.odin
index 16241de05..16853c5cd 100644
--- a/core/sys/win32/general.odin
+++ b/core/sys/win32/general.odin
@@ -300,6 +300,25 @@ File_Notify_Information :: struct {
file_name: [1]u16,
}
+// https://docs.microsoft.com/en-gb/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
+System_Info :: struct {
+ using _: struct #raw_union {
+ oem_id: u32,
+ using _: struct #raw_union {
+ processor_architecture: u16,
+ _: u16, // reserved
+ },
+ },
+ page_size: u32,
+ minimum_application_address: rawptr,
+ maximum_application_address: rawptr,
+ active_processor_mask: u32,
+ number_of_processors: u32,
+ processor_type: u32,
+ allocation_granularity: u32,
+ processor_level: u16,
+ processor_revision: u16,
+}
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_osversioninfoexa
OS_Version_Info_Ex_A :: struct {
diff --git a/core/sys/win32/kernel32.odin b/core/sys/win32/kernel32.odin
index f647ab7e0..3caeb4963 100644
--- a/core/sys/win32/kernel32.odin
+++ b/core/sys/win32/kernel32.odin
@@ -31,6 +31,7 @@ foreign kernel32 {
@(link_name="GetCommandLineA") get_command_line_a :: proc() -> cstring ---;
@(link_name="GetCommandLineW") get_command_line_w :: proc() -> Wstring ---;
@(link_name="GetSystemMetrics") get_system_metrics :: proc(index: i32) -> i32 ---;
+ @(link_name="GetSystemInfo") get_system_info :: proc(info: ^System_Info) ---;
@(link_name="GetVersionExA") get_version :: proc(osvi: ^OS_Version_Info_Ex_A) ---;
@(link_name="GetCurrentThreadId") get_current_thread_id :: proc() -> u32 ---;