avanspector hace 1 año
padre
commit
9d4c2ba0d8

+ 1 - 1
core/os/os_haiku.odin

@@ -14,7 +14,7 @@ Errno     :: i32
 
 MAX_PATH :: haiku.PATH_MAX
 
-ENOSYS :: haiku.Errno.POSIX_ERROR_BASE + 9
+ENOSYS :: int(haiku.Errno.POSIX_ERROR_BASE) + 9
 
 INVALID_HANDLE :: ~Handle(0)
 

+ 115 - 0
core/sync/futex_haiku.odin

@@ -0,0 +1,115 @@
+//+private
+package sync
+
+import "core:c"
+import "core:c/libc"
+import "core:sys/haiku"
+import "core:sys/unix"
+
+@(private="file")
+Wait_Node :: struct {
+	thread:     unix.pthread_t,
+	futex:      ^Futex,
+	prev, next: Wait_Node,
+}
+@(private="file")
+Wait_Queue :: struct {
+	lock: libc.atomic_flag,
+	list: Wait_Node,
+}
+@(private="file")
+waitq_lock :: proc(waitq: ^Wait_Queue) {
+	for libc.atomic_flag_test_and_set_explicit(&waitq.lock, .Acquire) {
+		; // spin...
+	}
+}
+@(private="file")
+waitq_unlock :: proc(waitq: ^Wait_Queue) {
+	libc.atomic_flag_clear(&waitq.lock, .Release)
+}
+
+// FIXME: This approach may scale badly in the future,
+// possible solution - hash map (leads to deadlocks now).
+@(private="file")
+g_waitq := Wait_Queue{
+	list = {
+		prev = &g_waitq.list,
+		next = &g_waitq.list,
+	},
+}
+@(private="file")
+get_waitq :: #force_inline proc "contextless" (f: ^Futex) -> ^Wait_Queue {
+	_ = f
+	return &g_waitq
+}
+
+_futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
+	waitq := get_waitq(f)
+	waitq_lock(&waitq)
+	defer waitq_unlock(&waitq)
+
+	head   := &waitq.list
+	waiter := Wait_Node{
+		thread = unix.pthread_self(),
+		futex  = f,
+		prev   = head,
+		next   = head.next,
+	}
+
+	waiter.prev.next = &waiter
+	waiter.next.prev = &waiter
+
+	old_mask, mask: haiku.sigset_t
+	haiku.sigemptyset(&mask)
+	haiku.sigaddset(&mask, haiku.SIGCONT)
+	unix.pthread_sigmask(haiku.SIG_BLOCK, &mask, &old_mask)
+
+	if u32(atomic_load_explicit(f, .Acquire)) == expect {
+		waitq_unlock(&waitq)
+		defer waitq_lock(&waitq)
+		
+		sig: c.int
+		haiku.sigwait(&mask, &sig)
+	}
+
+	waiter.prev.next = waiter.next
+	waiter.next.prev = waiter.prev
+
+ 	unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil)
+
+ 	// FIXME: Add error handling!
+ 	return true
+}
+
+_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
+	// FIXME: Add timeout!
+	_ = duration
+	return _futex_wait(f, expect)
+}
+
+_futex_signal :: proc "contextless" (f: ^Futex) {
+	waitq := get_waitq(f)
+	waitq_lock(&waitq)
+	defer waitq_unlock(&waitq)
+
+	head := &waitq.list
+	for waiter := head.next; waiter != head; waiter = waiter.next {
+		if waiter.futex == f {
+			unix.pthread_kill(waiter.thread, haiku.SIGCONT)
+			break
+		}
+	}
+}
+
+_futex_broadcast :: proc "contextless" (f: ^Futex) {
+	waitq := get_waitq(f)
+	waitq_lock(&waitq)
+	defer waitq_unlock(&waitq)
+
+	head := &waitq.list
+	for waiter := head.next; waiter != head; waiter = waiter.next {
+		if waiter.futex == f {
+			unix.pthread_kill(waiter.thread, haiku.SIGCONT)
+		}
+	}
+}

+ 84 - 1
core/sys/haiku/os.odin

@@ -2,6 +2,9 @@
 package sys_haiku
 
 import "core:c"
+import "core:sys/unix"
+
+foreign import libroot "system:c"
 
 PATH_MAX   :: 1024
 NAME_MAX   :: 256
@@ -120,7 +123,6 @@ cpu_topology_node_info :: struct {
 	},
 }
 
-foreign import libroot "system:c"
 foreign libroot {
 	get_system_info       :: proc(info: ^system_info) -> status_t ---
 	_get_cpu_info_etc     :: proc(firstCPU: u32, cpuCount: u32, info: ^cpu_info, size: c.size_t) -> status_t ---
@@ -136,4 +138,85 @@ foreign libroot {
 		to re-enable the default debugger pass a zero.
 	*/
 	disable_debugger :: proc(state: c.int) -> c.int ---
+
+	find_thread(name: cstring) -> thread_id ---
+}
+
+// Signal.h
+
+SIG_BLOCK   :: 1
+SIG_UNBLOCK :: 2
+SIG_SETMASK :: 3
+
+/*
+ * The list of all defined signals:
+ *
+ * The numbering of signals for Haiku attempts to maintain
+ * some consistency with UN*X conventions so that things
+ * like "kill -9" do what you expect.
+ */
+
+SIGHUP     :: 1  // hangup -- tty is gone!
+SIGINT     :: 2  // interrupt
+SIGQUIT    :: 3  // `quit' special character typed in tty
+SIGILL     :: 4  // illegal instruction
+SIGCHLD    :: 5  // child process exited
+SIGABRT    :: 6  // abort() called, dont' catch
+SIGPIPE    :: 7  // write to a pipe w/no readers
+SIGFPE     :: 8  // floating point exception
+SIGKILL    :: 9  // kill a team (not catchable)
+SIGSTOP    :: 10 // suspend a thread (not catchable)
+SIGSEGV    :: 11 // segmentation violation (read: invalid pointer)
+SIGCONT    :: 12 // continue execution if suspended
+SIGTSTP    :: 13 // `stop' special character typed in tty
+SIGALRM    :: 14 // an alarm has gone off (see alarm())
+SIGTERM    :: 15 // termination requested
+SIGTTIN    :: 16 // read of tty from bg process
+SIGTTOU    :: 17 // write to tty from bg process
+SIGUSR1    :: 18 // app defined signal 1
+SIGUSR2    :: 19 // app defined signal 2
+SIGWINCH   :: 20 // tty window size changed
+SIGKILLTHR :: 21 // be specific: kill just the thread, not team
+SIGTRAP    :: 22 // Trace/breakpoint trap
+SIGPOLL    :: 23 // Pollable event
+SIGPROF    :: 24 // Profiling timer expired
+SIGSYS     :: 25 // Bad system call
+SIGURG     :: 26 // High bandwidth data is available at socket
+SIGVTALRM  :: 27 // Virtual timer expired
+SIGXCPU    :: 28 // CPU time limit exceeded
+SIGXFSZ    :: 29 // File size limit exceeded
+SIGBUS     :: 30 // access to undefined portion of a memory object
+
+sigval :: struct #raw_union {
+	sival_int: c.int,
+	sival_ptr: rawptr,
+}
+
+siginfo_t :: struct {
+	si_signo: c.int,   // signal number
+	si_code:  c.int,   // signal code
+	si_errno: c.int,   // if non zero, an error number associated with this signal
+
+	si_pid:    pid_t,  // sending process ID
+	si_uid:    uid_t,  // real user ID of sending process
+	si_addr:   rawptr, // address of faulting instruction
+	si_status: c.int,  // exit value or signal
+	si_band:   c.long, // band event for SIGPOLL
+	si_value:  sigval, // signal value
+}
+
+foreign libroot {
+	// signal set (sigset_t) manipulation
+	sigemptyset :: proc(set: ^sigset_t) -> c.int ---
+	sigfillset  :: proc(set: ^sigset_t) -> c.int ---
+	sigaddset   :: proc(set: ^sigset_t, _signal: c.int) -> c.int ---
+	sigdelset   :: proc(set: ^sigset_t, _signal: c.int) -> c.int ---
+	sigismember :: proc(set: ^sigset_t, _signal: c.int) -> c.int ---
+	// querying and waiting for signals
+	sigpending   :: proc(set: ^sigset_t) -> c.int ---
+	sigsuspend   :: proc(mask: ^sigset_t) -> c.int ---
+	sigpause     :: proc(_signal: c.int) -> c.int ---
+	sigwait      :: proc(set: ^sigset_t, _signal: ^c.int) -> c.int ---
+	sigwaitinfo  :: proc(set: ^sigset_t, info: ^siginfo_t) -> c.int ---
+	sigtimedwait :: proc(set: ^sigset_t, info: ^siginfo_t, timeout: ^unix.timespec) -> c.int ---
 }

+ 3 - 0
core/sys/haiku/types.odin

@@ -45,3 +45,6 @@ key_t          :: i32
 clockid_t      :: i32
 
 time_t         :: i64 when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 else i32
+
+sig_atomic_t   :: c.int
+sigset_t       :: u64

+ 2 - 0
core/sys/unix/pthread_unix.odin

@@ -52,6 +52,8 @@ foreign pthread {
 	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 ---
 
+	pthread_sigmask :: proc(how: c.int, set: rawptr, oldset: rawptr) -> c.int ---
+
 	sched_yield :: proc() -> c.int ---
 
 }