Browse Source

fix haiku

avanspector 7 months ago
parent
commit
5376d2a20b

+ 1 - 1
build_odin.sh

@@ -115,7 +115,7 @@ OpenBSD)
 	LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
 	;;
 Haiku)
-	CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags) -I/system/develop/headers/private/shared -I/system/develop/headers/private/kernel"
+	CXXFLAGS="$CXXFLAGS -D_GNU_SOURCE $($LLVM_CONFIG --cxxflags --ldflags) -I/system/develop/headers/private/shared -I/system/develop/headers/private/kernel"
 	LDFLAGS="$LDFLAGS -liconv"
 	LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
 	;;

+ 8 - 7
core/c/libc/errno.odin

@@ -88,14 +88,15 @@ when ODIN_OS == .Haiku {
 		_get_errno :: proc() -> ^int ---
 	}
 
-	@(private="file")
-	B_GENERAL_ERROR_BASE :: min(i32)
-	@(private="file")
-	B_POSIX_ERROR_BASE   :: B_GENERAL_ERROR_BASE + 0x7000
+	_HAIKU_USE_POSITIVE_POSIX_ERRORS :: #config(HAIKU_USE_POSITIVE_POSIX_ERRORS, false)
+	_POSIX_ERROR_FACTOR              :: -1 when _HAIKU_USE_POSITIVE_POSIX_ERRORS else 1
+
+	@(private="file") _GENERAL_ERROR_BASE :: min(int)
+	@(private="file") _POSIX_ERROR_BASE   :: _GENERAL_ERROR_BASE + 0x7000
 
-	EDOM   :: B_POSIX_ERROR_BASE + 16
-	EILSEQ :: B_POSIX_ERROR_BASE + 38
-	ERANGE :: B_POSIX_ERROR_BASE + 17
+	EDOM   :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE + 16)
+	EILSEQ :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE + 38)
+	ERANGE :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE + 17)
 }
 
 when ODIN_OS == .JS {

+ 1 - 1
core/c/libc/locale.odin

@@ -110,7 +110,7 @@ when ODIN_OS == .Windows {
 	}
 }
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD  || ODIN_OS == .OpenBSD || ODIN_OS == .Windows {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD  || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku || ODIN_OS == .Windows {
 
 	LC_ALL      :: 0
 	LC_COLLATE  :: 1

+ 7 - 6
core/os/os_haiku.odin

@@ -1,11 +1,13 @@
 package os
 
-foreign import libc "system:c"
+foreign import lib "system:c"
 
 import "base:runtime"
 import "core:c"
+import "core:c/libc"
 import "core:strings"
 import "core:sys/haiku"
+import "core:sys/posix"
 
 Handle    :: i32
 Pid       :: i32
@@ -117,14 +119,13 @@ S_ISBLK  :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK
 S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO  }
 S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
 
+__error :: libc.errno
+_unix_open :: posix.open
 
-foreign libc {
-	@(link_name="_errorp")        __error              :: proc() -> ^c.int ---
-
+foreign lib {
 	@(link_name="fork")           _unix_fork           :: proc() -> pid_t ---
 	@(link_name="getthrid")       _unix_getthrid       :: proc() -> int ---
 
-	@(link_name="open")           _unix_open           :: proc(path: cstring, flags: c.int, #c_vararg mode: ..u16) -> Handle ---
 	@(link_name="close")          _unix_close          :: proc(fd: Handle) -> c.int ---
 	@(link_name="read")           _unix_read           :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
 	@(link_name="pread")          _unix_pread          :: proc(fd: Handle, buf: rawptr, size: c.size_t, offset: i64) -> c.ssize_t ---
@@ -203,7 +204,7 @@ fork :: proc() -> (Pid, Error) {
 open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Error) {
 	runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
 	cstr := strings.clone_to_cstring(path, context.temp_allocator)
-	handle := _unix_open(cstr, c.int(flags), u16(mode))
+	handle := cast(Handle)_unix_open(cstr, transmute(posix.O_Flags)i32(flags), transmute(posix.mode_t)i32(mode))
 	if handle == -1 {
 		return INVALID_HANDLE, get_last_error()
 	}

+ 1 - 1
core/os/stat_unix.odin

@@ -53,7 +53,7 @@ File_Info :: struct {
 @(private, require_results)
 _make_time_from_unix_file_time :: proc(uft: Unix_File_Time) -> time.Time {
 	return time.Time{
-		_nsec = uft.nanoseconds + uft.seconds * 1_000_000_000,
+		_nsec = i64(uft.nanoseconds) + i64(uft.seconds) * 1_000_000_000,
 	}
 }
 

+ 26 - 28
core/sync/futex_haiku.odin

@@ -1,14 +1,12 @@
 #+private
 package sync
 
-import "core:c"
-import "core:sys/haiku"
-import "core:sys/unix"
+import "core:sys/posix"
 import "core:time"
 
 @(private="file")
 Wait_Node :: struct {
-	thread:     unix.pthread_t,
+	thread:     posix.pthread_t,
 	futex:      ^Futex,
 	prev, next: ^Wait_Node,
 }
@@ -58,7 +56,7 @@ _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> (ok: bool) {
 
 	head   := &waitq.list
 	waiter := Wait_Node{
-		thread = unix.pthread_self(),
+		thread = posix.pthread_self(),
 		futex  = f,
 		prev   = head,
 		next   = head.next,
@@ -67,25 +65,25 @@ _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> (ok: bool) {
 	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)
+	old_mask, mask: posix.sigset_t
+	posix.sigemptyset(&mask)
+	posix.sigaddset(&mask, .SIGCONT)
+	posix.pthread_sigmask(.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)
-		errno := haiku.errno() 
-		ok = errno == .OK
+		sig: posix.Signal
+		posix.sigwait(&mask, &sig)
+		errno := posix.errno() 
+		ok = errno == nil
 	}
 
 	waiter.prev.next = waiter.next
 	waiter.next.prev = waiter.prev
 
-	_ = unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil)
+	_ = posix.pthread_sigmask(.SETMASK, &old_mask, nil)
 
  	// FIXME: Add error handling!
 	return
@@ -101,7 +99,7 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration
 
 	head   := &waitq.list
 	waiter := Wait_Node{
-		thread = unix.pthread_self(),
+		thread = posix.pthread_self(),
 		futex  = f,
 		prev   = head,
 		next   = head.next,
@@ -110,29 +108,29 @@ _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration
 	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)
+	old_mask, mask: posix.sigset_t
+	posix.sigemptyset(&mask)
+	posix.sigaddset(&mask, .SIGCONT)
+	posix.pthread_sigmask(.BLOCK, &mask, &old_mask)
 
 	if u32(atomic_load_explicit(f, .Acquire)) == expect {
 		waitq_unlock(waitq)
 		defer waitq_lock(waitq)
 		
-		info: haiku.siginfo_t
-		ts := unix.timespec{
-			tv_sec  = i64(duration / 1e9),
+		info: posix.siginfo_t
+		ts := posix.timespec{
+			tv_sec  = posix.time_t(i64(duration / 1e9)),
 			tv_nsec = i64(duration % 1e9),
 		}
-		haiku.sigtimedwait(&mask, &info, &ts)
-		errno := haiku.errno() 
-		ok = errno == .EAGAIN || errno == .OK
+		posix.sigtimedwait(&mask, &info, &ts)
+		errno := posix.errno() 
+		ok = errno == .EAGAIN || errno == nil
 	}
 
 	waiter.prev.next = waiter.next
 	waiter.next.prev = waiter.prev
 
-	unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil)
+	posix.pthread_sigmask(.SETMASK, &old_mask, nil)
 
 	// FIXME: Add error handling!
 	return
@@ -146,7 +144,7 @@ _futex_signal :: proc "contextless" (f: ^Futex) {
 	head := &waitq.list
 	for waiter := head.next; waiter != head; waiter = waiter.next {
 		if waiter.futex == f {
-			unix.pthread_kill(waiter.thread, haiku.SIGCONT)
+			posix.pthread_kill(waiter.thread, .SIGCONT)
 			break
 		}
 	}
@@ -160,7 +158,7 @@ _futex_broadcast :: proc "contextless" (f: ^Futex) {
 	head := &waitq.list
 	for waiter := head.next; waiter != head; waiter = waiter.next {
 		if waiter.futex == f {
-			unix.pthread_kill(waiter.thread, haiku.SIGCONT)
+			posix.pthread_kill(waiter.thread, .SIGCONT)
 		}
 	}
 }

+ 217 - 0
core/sys/haiku/errno.odin

@@ -0,0 +1,217 @@
+#+build haiku
+package sys_haiku
+
+import "core:sys/posix"
+
+foreign import libroot "system:c"
+
+Errno :: enum i32 {
+	// Error baselines
+	GENERAL_ERROR_BASE     = min(i32),
+	OS_ERROR_BASE          = GENERAL_ERROR_BASE + 0x1000,
+	APP_ERROR_BASE         = GENERAL_ERROR_BASE + 0x2000,
+	INTERFACE_ERROR_BASE   = GENERAL_ERROR_BASE + 0x3000,
+	MEDIA_ERROR_BASE       = GENERAL_ERROR_BASE + 0x4000,
+	TRANSLATION_ERROR_BASE = GENERAL_ERROR_BASE + 0x4800,
+	MIDI_ERROR_BASE        = GENERAL_ERROR_BASE + 0x5000,
+	STORAGE_ERROR_BASE     = GENERAL_ERROR_BASE + 0x6000,
+	POSIX_ERROR_BASE       = GENERAL_ERROR_BASE + 0x7000,
+	MAIL_ERROR_BASE        = GENERAL_ERROR_BASE + 0x8000,
+	PRINT_ERROR_BASE       = GENERAL_ERROR_BASE + 0x9000,
+	DEVICE_ERROR_BASE      = GENERAL_ERROR_BASE + 0xA000,
+
+	// Developer-defined errors start at (ERRORS_END+1)
+	ERRORS_END             = GENERAL_ERROR_BASE + 0xFFFF,
+
+	// General Errors
+	NO_MEMORY              = GENERAL_ERROR_BASE + 0,
+	IO_ERROR               = GENERAL_ERROR_BASE + 1,
+	PERMISSION_DENIED      = GENERAL_ERROR_BASE + 2,
+	BAD_INDEX              = GENERAL_ERROR_BASE + 3,
+	BAD_TYPE               = GENERAL_ERROR_BASE + 4,
+	BAD_VALUE              = GENERAL_ERROR_BASE + 5,
+	MISMATCHED_VALUES      = GENERAL_ERROR_BASE + 6,
+	NAME_NOT_FOUND         = GENERAL_ERROR_BASE + 7,
+	NAME_IN_USE            = GENERAL_ERROR_BASE + 8,
+	TIMED_OUT              = GENERAL_ERROR_BASE + 9,
+	INTERRUPTED            = GENERAL_ERROR_BASE + 10,
+	WOULD_BLOCK            = GENERAL_ERROR_BASE + 11,
+	CANCELED               = GENERAL_ERROR_BASE + 12,
+	NO_INIT                = GENERAL_ERROR_BASE + 13,
+	NOT_INITIALIZED        = GENERAL_ERROR_BASE + 13,
+	BUSY                   = GENERAL_ERROR_BASE + 14,
+	NOT_ALLOWED            = GENERAL_ERROR_BASE + 15,
+	BAD_DATA               = GENERAL_ERROR_BASE + 16,
+	DONT_DO_THAT           = GENERAL_ERROR_BASE + 17,
+
+	ERROR                  = -1,
+	OK                     = 0,
+	NO_ERROR               = 0,
+
+	// Kernel Kit Errors
+	BAD_SEM_ID                        = OS_ERROR_BASE + 0,
+	NO_MORE_SEMS                      = OS_ERROR_BASE + 1,
+	BAD_THREAD_ID                     = OS_ERROR_BASE + 0x100,
+	NO_MORE_THREADS                   = OS_ERROR_BASE + 0x101,
+	BAD_THREAD_STATE                  = OS_ERROR_BASE + 0x102,
+	BAD_TEAM_ID                       = OS_ERROR_BASE + 0x103,
+	NO_MORE_TEAMS                     = OS_ERROR_BASE + 0x104,
+	BAD_PORT_ID                       = OS_ERROR_BASE + 0x200,
+	NO_MORE_PORTS                     = OS_ERROR_BASE + 0x201,
+	BAD_IMAGE_ID                      = OS_ERROR_BASE + 0x300,
+	BAD_ADDRESS                       = OS_ERROR_BASE + 0x301,
+	NOT_AN_EXECUTABLE                 = OS_ERROR_BASE + 0x302,
+	MISSING_LIBRARY                   = OS_ERROR_BASE + 0x303,
+	MISSING_SYMBOL                    = OS_ERROR_BASE + 0x304,
+	UNKNOWN_EXECUTABLE                = OS_ERROR_BASE + 0x305,
+	LEGACY_EXECUTABLE                 = OS_ERROR_BASE + 0x306,
+
+	DEBUGGER_ALREADY_INSTALLED        = OS_ERROR_BASE + 0x400,
+
+	// Application Kit Errors
+	BAD_REPLY                         = APP_ERROR_BASE + 0,
+	DUPLICATE_REPLY                   = APP_ERROR_BASE + 1,
+	MESSAGE_TO_SELF                   = APP_ERROR_BASE + 2,
+	BAD_HANDLER                       = APP_ERROR_BASE + 3,
+	ALREADY_RUNNING                   = APP_ERROR_BASE + 4,
+	LAUNCH_FAILED                     = APP_ERROR_BASE + 5,
+	AMBIGUOUS_APP_LAUNCH              = APP_ERROR_BASE + 6,
+	UNKNOWN_MIME_TYPE                 = APP_ERROR_BASE + 7,
+	BAD_SCRIPT_SYNTAX                 = APP_ERROR_BASE + 8,
+	LAUNCH_FAILED_NO_RESOLVE_LINK     = APP_ERROR_BASE + 9,
+	LAUNCH_FAILED_EXECUTABLE          = APP_ERROR_BASE + 10,
+	LAUNCH_FAILED_APP_NOT_FOUND       = APP_ERROR_BASE + 11,
+	LAUNCH_FAILED_APP_IN_TRASH        = APP_ERROR_BASE + 12,
+	LAUNCH_FAILED_NO_PREFERRED_APP    = APP_ERROR_BASE + 13,
+	LAUNCH_FAILED_FILES_APP_NOT_FOUND = APP_ERROR_BASE + 14,
+	BAD_MIME_SNIFFER_RULE             = APP_ERROR_BASE + 15,
+	NOT_A_MESSAGE                     = APP_ERROR_BASE + 16,
+	SHUTDOWN_CANCELLED                = APP_ERROR_BASE + 17,
+	SHUTTING_DOWN                     = APP_ERROR_BASE + 18,
+
+	// Storage Kit/File System Errors
+	FILE_ERROR                        = STORAGE_ERROR_BASE + 0,
+	// 1 was B_FILE_NOT_FOUND (deprecated)
+	FILE_EXISTS                       = STORAGE_ERROR_BASE + 2,
+	ENTRY_NOT_FOUND                   = STORAGE_ERROR_BASE + 3,
+	NAME_TOO_LONG                     = STORAGE_ERROR_BASE + 4,
+	NOT_A_DIRECTORY                   = STORAGE_ERROR_BASE + 5,
+	DIRECTORY_NOT_EMPTY               = STORAGE_ERROR_BASE + 6,
+	DEVICE_FULL                       = STORAGE_ERROR_BASE + 7,
+	READ_ONLY_DEVICE                  = STORAGE_ERROR_BASE + 8,
+	IS_A_DIRECTORY                    = STORAGE_ERROR_BASE + 9,
+	NO_MORE_FDS                       = STORAGE_ERROR_BASE + 10,
+	CROSS_DEVICE_LINK                 = STORAGE_ERROR_BASE + 11,
+	LINK_LIMIT                        = STORAGE_ERROR_BASE + 12,
+	BUSTED_PIPE                       = STORAGE_ERROR_BASE + 13,
+	UNSUPPORTED                       = STORAGE_ERROR_BASE + 14,
+	PARTITION_TOO_SMALL               = STORAGE_ERROR_BASE + 15,
+	PARTIAL_READ                      = STORAGE_ERROR_BASE + 16,
+	PARTIAL_WRITE                     = STORAGE_ERROR_BASE + 17,
+
+	// New error codes that can be mapped to POSIX errors
+	TOO_MANY_ARGS                = posix.E2BIG,
+	FILE_TOO_LARGE               = posix.EFBIG,
+	DEVICE_NOT_FOUND             = posix.ENODEV,
+	RESULT_NOT_REPRESENTABLE     = posix.ERANGE,
+	BUFFER_OVERFLOW              = posix.EOVERFLOW,
+	NOT_SUPPORTED                = posix.EOPNOTSUPP,
+
+	// Media Kit Errors
+	STREAM_NOT_FOUND             = MEDIA_ERROR_BASE + 0,
+	SERVER_NOT_FOUND             = MEDIA_ERROR_BASE + 1,
+	RESOURCE_NOT_FOUND           = MEDIA_ERROR_BASE + 2,
+	RESOURCE_UNAVAILABLE         = MEDIA_ERROR_BASE + 3,
+	BAD_SUBSCRIBER               = MEDIA_ERROR_BASE + 4,
+	SUBSCRIBER_NOT_ENTERED       = MEDIA_ERROR_BASE + 5,
+	BUFFER_NOT_AVAILABLE         = MEDIA_ERROR_BASE + 6,
+	LAST_BUFFER_ERROR            = MEDIA_ERROR_BASE + 7,
+	MEDIA_SYSTEM_FAILURE         = MEDIA_ERROR_BASE + 100,
+	MEDIA_BAD_NODE               = MEDIA_ERROR_BASE + 101,
+	MEDIA_NODE_BUSY              = MEDIA_ERROR_BASE + 102,
+	MEDIA_BAD_FORMAT             = MEDIA_ERROR_BASE + 103,
+	MEDIA_BAD_BUFFER             = MEDIA_ERROR_BASE + 104,
+	MEDIA_TOO_MANY_NODES         = MEDIA_ERROR_BASE + 105,
+	MEDIA_TOO_MANY_BUFFERS       = MEDIA_ERROR_BASE + 106,
+	MEDIA_NODE_ALREADY_EXISTS    = MEDIA_ERROR_BASE + 107,
+	MEDIA_BUFFER_ALREADY_EXISTS  = MEDIA_ERROR_BASE + 108,
+	MEDIA_CANNOT_SEEK            = MEDIA_ERROR_BASE + 109,
+	MEDIA_CANNOT_CHANGE_RUN_MODE = MEDIA_ERROR_BASE + 110,
+	MEDIA_APP_ALREADY_REGISTERED = MEDIA_ERROR_BASE + 111,
+	MEDIA_APP_NOT_REGISTERED     = MEDIA_ERROR_BASE + 112,
+	MEDIA_CANNOT_RECLAIM_BUFFERS = MEDIA_ERROR_BASE + 113,
+	MEDIA_BUFFERS_NOT_RECLAIMED  = MEDIA_ERROR_BASE + 114,
+	MEDIA_TIME_SOURCE_STOPPED    = MEDIA_ERROR_BASE + 115,
+	MEDIA_TIME_SOURCE_BUSY       = MEDIA_ERROR_BASE + 116,
+	MEDIA_BAD_SOURCE             = MEDIA_ERROR_BASE + 117,
+	MEDIA_BAD_DESTINATION        = MEDIA_ERROR_BASE + 118,
+	MEDIA_ALREADY_CONNECTED      = MEDIA_ERROR_BASE + 119,
+	MEDIA_NOT_CONNECTED          = MEDIA_ERROR_BASE + 120,
+	MEDIA_BAD_CLIP_FORMAT        = MEDIA_ERROR_BASE + 121,
+	MEDIA_ADDON_FAILED           = MEDIA_ERROR_BASE + 122,
+	MEDIA_ADDON_DISABLED         = MEDIA_ERROR_BASE + 123,
+	MEDIA_CHANGE_IN_PROGRESS     = MEDIA_ERROR_BASE + 124,
+	MEDIA_STALE_CHANGE_COUNT     = MEDIA_ERROR_BASE + 125,
+	MEDIA_ADDON_RESTRICTED       = MEDIA_ERROR_BASE + 126,
+	MEDIA_NO_HANDLER             = MEDIA_ERROR_BASE + 127,
+	MEDIA_DUPLICATE_FORMAT       = MEDIA_ERROR_BASE + 128,
+	MEDIA_REALTIME_DISABLED      = MEDIA_ERROR_BASE + 129,
+	MEDIA_REALTIME_UNAVAILABLE   = MEDIA_ERROR_BASE + 130,
+
+	// Mail Kit Errors
+	MAIL_NO_DAEMON               = MAIL_ERROR_BASE + 0,
+	MAIL_UNKNOWN_USER            = MAIL_ERROR_BASE + 1,
+	MAIL_WRONG_PASSWORD          = MAIL_ERROR_BASE + 2,
+	MAIL_UNKNOWN_HOST            = MAIL_ERROR_BASE + 3,
+	MAIL_ACCESS_ERROR            = MAIL_ERROR_BASE + 4,
+	MAIL_UNKNOWN_FIELD           = MAIL_ERROR_BASE + 5,
+	MAIL_NO_RECIPIENT            = MAIL_ERROR_BASE + 6,
+	MAIL_INVALID_MAIL            = MAIL_ERROR_BASE + 7,
+
+	// Printing Errors
+	NO_PRINT_SERVER              = PRINT_ERROR_BASE + 0,
+
+	// Device Kit Errors
+	DEV_INVALID_IOCTL            = DEVICE_ERROR_BASE + 0,
+	DEV_NO_MEMORY                = DEVICE_ERROR_BASE + 1,
+	DEV_BAD_DRIVE_NUM            = DEVICE_ERROR_BASE + 2,
+	DEV_NO_MEDIA                 = DEVICE_ERROR_BASE + 3,
+	DEV_UNREADABLE               = DEVICE_ERROR_BASE + 4,
+	DEV_FORMAT_ERROR             = DEVICE_ERROR_BASE + 5,
+	DEV_TIMEOUT                  = DEVICE_ERROR_BASE + 6,
+	DEV_RECALIBRATE_ERROR        = DEVICE_ERROR_BASE + 7,
+	DEV_SEEK_ERROR               = DEVICE_ERROR_BASE + 8,
+	DEV_ID_ERROR                 = DEVICE_ERROR_BASE + 9,
+	DEV_READ_ERROR               = DEVICE_ERROR_BASE + 10,
+	DEV_WRITE_ERROR              = DEVICE_ERROR_BASE + 11,
+	DEV_NOT_READY                = DEVICE_ERROR_BASE + 12,
+	DEV_MEDIA_CHANGED            = DEVICE_ERROR_BASE + 13,
+	DEV_MEDIA_CHANGE_REQUESTED   = DEVICE_ERROR_BASE + 14,
+	DEV_RESOURCE_CONFLICT        = DEVICE_ERROR_BASE + 15,
+	DEV_CONFIGURATION_ERROR      = DEVICE_ERROR_BASE + 16,
+	DEV_DISABLED_BY_USER         = DEVICE_ERROR_BASE + 17,
+	DEV_DOOR_OPEN                = DEVICE_ERROR_BASE + 18,
+	DEV_INVALID_PIPE             = DEVICE_ERROR_BASE + 19,
+	DEV_CRC_ERROR                = DEVICE_ERROR_BASE + 20,
+	DEV_STALLED                  = DEVICE_ERROR_BASE + 21,
+	DEV_BAD_PID                  = DEVICE_ERROR_BASE + 22,
+	DEV_UNEXPECTED_PID           = DEVICE_ERROR_BASE + 23,
+	DEV_DATA_OVERRUN             = DEVICE_ERROR_BASE + 24,
+	DEV_DATA_UNDERRUN            = DEVICE_ERROR_BASE + 25,
+	DEV_FIFO_OVERRUN             = DEVICE_ERROR_BASE + 26,
+	DEV_FIFO_UNDERRUN            = DEVICE_ERROR_BASE + 27,
+	DEV_PENDING                  = DEVICE_ERROR_BASE + 28,
+	DEV_MULTIPLE_ERRORS          = DEVICE_ERROR_BASE + 29,
+	DEV_TOO_LATE                 = DEVICE_ERROR_BASE + 30,
+
+	// Translation Kit Errors
+	TRANSLATION_BASE_ERROR       = TRANSLATION_ERROR_BASE + 0,
+	NO_TRANSLATOR                = TRANSLATION_ERROR_BASE + 1,
+	ILLEGAL_DATA                 = TRANSLATION_ERROR_BASE + 2,
+}
+
+@(default_calling_convention="c")
+foreign libroot {
+	_to_positive_error :: proc(error: i32) -> i32 ---
+	_to_negative_error :: proc(error: i32) -> i32 ---
+}

+ 23 - 20
core/sys/haiku/find_directory.odin

@@ -1,9 +1,11 @@
 #+build haiku
 package sys_haiku
 
-import "core:c"
+import "base:intrinsics"
 
-directory_which :: enum c.int {
+foreign import libroot "system:c"
+
+directory_which :: enum i32 {
 	// Per volume directories
 	DESKTOP_DIRECTORY = 0,
 	TRASH_DIRECTORY,
@@ -110,17 +112,18 @@ directory_which :: enum c.int {
 	BEOS_SOUNDS_DIRECTORY,
 }
 
-find_path_flags :: enum c.int {
-	CREATE_DIRECTORY        = 0x0001,
-	CREATE_PARENT_DIRECTORY = 0x0002,
-	EXISTING_ONLY           = 0x0004,
+find_path_flag :: enum u32 {
+	CREATE_DIRECTORY        = intrinsics.constant_log2(0x0001),
+	CREATE_PARENT_DIRECTORY = intrinsics.constant_log2(0x0002),
+	EXISTING_ONLY           = intrinsics.constant_log2(0x0004),
 	
-	// find_paths() only!
-	SYSTEM_ONLY             = 0x0010,
-	USER_ONLY               = 0x0020,
+	// find_paths() only
+	SYSTEM_ONLY             = intrinsics.constant_log2(0x0010),
+	USER_ONLY               = intrinsics.constant_log2(0x0020),
 }
+find_path_flags :: distinct bit_set[find_path_flag; u32]
 
-path_base_directory :: enum c.int {
+path_base_directory :: enum i32 {
 	INSTALLATION_LOCATION_DIRECTORY,
 	ADD_ONS_DIRECTORY,
 	APPS_DIRECTORY,
@@ -146,7 +149,7 @@ path_base_directory :: enum c.int {
 	TRANSLATORS_DIRECTORY,
 	VAR_DIRECTORY,
 
-	// find_path() only!
+	// find_path() only
 	IMAGE_PATH = 1000,
 	PACKAGE_PATH,
 }
@@ -154,15 +157,15 @@ path_base_directory :: enum c.int {
 // value that can be used instead of a pointer to a symbol in the program image
 APP_IMAGE_SYMBOL :: rawptr(addr_t(0))
 // pointer to a symbol in the callers image (same as B_CURRENT_IMAGE_SYMBOL)
-current_image_symbol :: proc() -> rawptr { return rawptr(current_image_symbol) }
+current_image_symbol :: proc "contextless" () -> rawptr { return rawptr(current_image_symbol) }
 
-foreign import libroot "system:c"
+@(default_calling_convention="c")
 foreign libroot {
-	find_directory         :: proc(which: directory_which, volume: dev_t, createIt: bool, pathString: [^]c.char, length: i32) -> status_t ---
-	find_path              :: proc(codePointer: rawptr, baseDirectory: path_base_directory, subPath: cstring, pathBuffer: [^]c.char, bufferSize: c.size_t) -> status_t ---
-	find_path_etc          :: proc(codePointer: rawptr, dependency: cstring, architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, pathBuffer: [^]c.char, bufferSize: c.size_t) -> status_t ---
-	find_path_for_path     :: proc(path: cstring, baseDirectory: path_base_directory, subPath: cstring, pathBuffer: [^]c.char, bufferSize: c.size_t) -> status_t ---
-	find_path_for_path_etc :: proc(path: cstring, dependency: cstring, architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, pathBuffer: [^]c.char, bufferSize: c.size_t) -> status_t ---
-	find_paths             :: proc(baseDirectory: path_base_directory, subPath: cstring, _paths: ^[^][^]c.char, _pathCount: ^c.size_t) -> status_t ---
-	find_paths_etc         :: proc(architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, _paths: ^[^][^]c.char, _pathCount: ^c.size_t) -> status_t ---
+	find_directory         :: proc(which: directory_which, volume: dev_t, createIt: bool, pathString: [^]byte, length: i32) -> status_t ---
+	find_path              :: proc(codePointer: rawptr, baseDirectory: path_base_directory, subPath: cstring, pathBuffer: [^]byte, bufferSize: uintptr) -> status_t ---
+	find_path_etc          :: proc(codePointer: rawptr, dependency: cstring, architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, pathBuffer: [^]byte, bufferSize: uintptr) -> status_t ---
+	find_path_for_path     :: proc(path: cstring, baseDirectory: path_base_directory, subPath: cstring, pathBuffer: [^]byte, bufferSize: uintptr) -> status_t ---
+	find_path_for_path_etc :: proc(path: cstring, dependency: cstring, architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, pathBuffer: [^]byte, bufferSize: uintptr) -> status_t ---
+	find_paths             :: proc(baseDirectory: path_base_directory, subPath: cstring, _paths: ^[^][^]byte, _pathCount: ^uintptr) -> status_t ---
+	find_paths_etc         :: proc(architecture: cstring, baseDirectory: path_base_directory, subPath: cstring, flags: find_path_flags, _paths: ^[^][^]byte, _pathCount: ^uintptr) -> status_t ---
 }

+ 128 - 144
core/sys/haiku/os.odin

@@ -1,8 +1,8 @@
 #+build haiku
 package sys_haiku
 
+import "base:intrinsics"
 import "core:c"
-import "core:sys/unix"
 
 foreign import libroot "system:c"
 
@@ -18,8 +18,8 @@ OS_NAME_LENGTH   :: 32
 
 area_info :: struct {
 	area:       area_id,
-	name:       [OS_NAME_LENGTH]c.char,
-	size:       c.size_t,
+	name:       [OS_NAME_LENGTH]byte,
+	size:       uintptr,
 	lock:       u32,
 	protection: u32,
 	team:       team_id,
@@ -31,11 +31,11 @@ area_info :: struct {
 }
 
 area_locking :: enum u32 {
-	NO_LOCK           = 0,
-	LAZY_LOCK         = 1,
-	FULL_LOCK         = 2,
-	CONTIGUOUS        = 3,
-	LOMEM             = 4, // CONTIGUOUS, < 16 MB physical address
+	NO_LOCK            = 0,
+	LAZY_LOCK          = 1,
+	FULL_LOCK          = 2,
+	CONTIGUOUS         = 3,
+	LOMEM              = 4, // CONTIGUOUS, < 16 MB physical address
 	_32_BIT_FULL_LOCK  = 5, // FULL_LOCK, < 4 GB physical addresses
 	_32_BIT_CONTIGUOUS = 6, // CONTIGUOUS, < 4 GB physical address
 }
@@ -52,27 +52,29 @@ address_spec :: enum u32 {
 	RANDOMIZED_BASE_ADDRESS = 7,
 }
 
-area_protection_flags :: enum u32 {
-	READ_AREA      = 1 << 0,
-	WRITE_AREA     = 1 << 1,
-	EXECUTE_AREA   = 1 << 2,
+area_protection_flag :: enum u32 {
+	READ_AREA      = 0,
+	WRITE_AREA     = 1,
+	EXECUTE_AREA   = 2,
 	// "stack" protection is not available on most platforms - it's used
 	// to only commit memory as needed, and have guard pages at the
 	// bottom of the stack.
-	STACK_AREA     = 1 << 3,
-	CLONEABLE_AREA = 1 << 8,
+	STACK_AREA     = 3,
+	CLONEABLE_AREA = 8,
 }
+area_protection_flags :: distinct bit_set[area_protection_flag; u32]
 
+@(default_calling_convention="c")
 foreign libroot {
-	create_area         :: proc(name: cstring, startAddress: ^rawptr, addressSpec: address_spec, size: c.size_t, lock: area_locking, protection: area_protection_flags) -> area_id ---
+	create_area         :: proc(name: cstring, startAddress: ^rawptr, addressSpec: address_spec, size: uintptr, lock: area_locking, protection: area_protection_flags) -> area_id ---
 	clone_area          :: proc(name: cstring, destAddress: ^rawptr, addressSpec: address_spec, protection: area_protection_flags, source: area_id) -> area_id ---
 	find_area           :: proc(name: cstring) -> area_id ---
 	area_for            :: proc(address: rawptr) -> area_id ---
 	delete_area         :: proc(id: area_id) -> status_t ---
-	resize_area         :: proc(id: area_id, newSize: c.size_t) -> status_t ---
+	resize_area         :: proc(id: area_id, newSize: uintptr) -> status_t ---
 	set_area_protection :: proc(id: area_id, newProtection: area_protection_flags) -> status_t ---
-	_get_area_info      :: proc(id: area_id, areaInfo: ^area_info, size: c.size_t) -> status_t ---
-	_get_next_area_info :: proc(team: team_id, cookie: ^c.ssize_t, areaInfo: ^area_info, size: c.size_t) -> status_t ---
+	_get_area_info      :: proc(id: area_id, areaInfo: ^area_info, size: uintptr) -> status_t ---
+	_get_next_area_info :: proc(team: team_id, cookie: ^c.ssize_t, areaInfo: ^area_info, size: uintptr) -> status_t ---
 }
 
 // Ports
@@ -80,33 +82,35 @@ foreign libroot {
 port_info :: struct {
 	port:        port_id,
 	team:        team_id,
-	name:        [OS_NAME_LENGTH]c.char,
+	name:        [OS_NAME_LENGTH]byte,
 	capacity:    i32, // queue depth
 	queue_count: i32, // # msgs waiting to be read
 	total_count: i32, // total # msgs read so far
 }
 
-port_flags :: enum u32 {
-	USE_USER_MEMCPY   = 0x80000000,
+port_flag :: enum u32 {
+	USE_USER_MEMCPY   = intrinsics.constant_log2(0x80000000),
 	// read the message, but don't remove it; kernel-only; memory must be locked
-	PEEK_PORT_MESSAGE = 0x100,
+	PEEK_PORT_MESSAGE = intrinsics.constant_log2(0x100),
 }
+port_flags :: distinct bit_set[port_flag; u32]
 
+@(default_calling_convention="c")
 foreign libroot {
 	create_port          :: proc(capacity: i32, name: cstring) -> port_id ---
 	find_port            :: proc(name: cstring) -> port_id ---
-	read_port            :: proc(port: port_id, code: ^i32, buffer: rawptr, bufferSize: c.size_t) -> c.ssize_t ---
-	read_port_etc        :: proc(port: port_id, code: ^i32, buffer: rawptr, bufferSize: c.size_t, flags: port_flags, timeout: bigtime_t) -> c.ssize_t ---
-	write_port           :: proc(port: port_id, code: i32, buffer: rawptr, bufferSize: c.size_t) -> status_t ---
-	write_port_etc       :: proc(port: port_id, code: i32, buffer: rawptr, bufferSize: c.size_t, flags: port_flags, timeout: bigtime_t) -> status_t ---
+	read_port            :: proc(port: port_id, code: ^i32, buffer: rawptr, bufferSize: uintptr) -> c.ssize_t ---
+	read_port_etc        :: proc(port: port_id, code: ^i32, buffer: rawptr, bufferSize: uintptr, flags: port_flags, timeout: bigtime_t) -> c.ssize_t ---
+	write_port           :: proc(port: port_id, code: i32, buffer: rawptr, bufferSize: uintptr) -> status_t ---
+	write_port_etc       :: proc(port: port_id, code: i32, buffer: rawptr, bufferSize: uintptr, flags: port_flags, timeout: bigtime_t) -> status_t ---
 	close_port           :: proc(port: port_id) -> status_t ---
 	delete_port          :: proc(port: port_id) -> status_t ---
 	port_buffer_size     :: proc(port: port_id) -> c.ssize_t ---
 	port_buffer_size_etc :: proc(port: port_id, flags: port_flags, timeout: bigtime_t) -> c.ssize_t ---
 	port_count           :: proc(port: port_id) -> c.ssize_t ---
 	set_port_owner       :: proc(port: port_id, team: team_id) -> status_t ---
-	_get_port_info       :: proc(port: port_id, portInfo: ^port_info, portInfoSize: c.size_t) -> status_t ---
-	_get_next_port_info  :: proc(team: team_id, cookie: ^i32, portInfo: ^port_info, portInfoSize: c.size_t) -> status_t ---
+	_get_port_info       :: proc(port: port_id, portInfo: ^port_info, portInfoSize: uintptr) -> status_t ---
+	_get_next_port_info  :: proc(team: team_id, cookie: ^i32, portInfo: ^port_info, portInfoSize: uintptr) -> status_t ---
 }
 
 // Semaphores
@@ -114,22 +118,24 @@ foreign libroot {
 sem_info :: struct {
 	sem:           sem_id,
 	team:          team_id,
-	name:          [OS_NAME_LENGTH]c.char,
+	name:          [OS_NAME_LENGTH]byte,
 	count:         i32,
 	latest_holder: thread_id,
 }
 
-semaphore_flags :: enum u32 {
-	CAN_INTERRUPT      = 0x01, // acquisition of the semaphore can be interrupted (system use only)
-	CHECK_PERMISSION   = 0x04, // ownership will be checked (system use only)
-	KILL_CAN_INTERRUPT = 0x20, // acquisition of the semaphore can be interrupted by SIGKILL[THR], even if not CAN_INTERRUPT (system use only)
+semaphore_flag :: enum u32 {
+	CAN_INTERRUPT      = intrinsics.constant_log2(0x01), // acquisition of the semaphore can be interrupted (system use only)
+	CHECK_PERMISSION   = intrinsics.constant_log2(0x04), // ownership will be checked (system use only)
+	KILL_CAN_INTERRUPT = intrinsics.constant_log2(0x20), // acquisition of the semaphore can be interrupted by SIGKILL[THR], even if not CAN_INTERRUPT (system use only)
 	
 	// release_sem_etc() only flags
-	DO_NOT_RESCHEDULE       = 0x02, // thread is not rescheduled
-	RELEASE_ALL             = 0x08, // all waiting threads will be woken up, count will be zeroed
-	RELEASE_IF_WAITING_ONLY	= 0x10, // release count only if there are any threads waiting
+	DO_NOT_RESCHEDULE       = intrinsics.constant_log2(0x02), // thread is not rescheduled
+	RELEASE_ALL             = intrinsics.constant_log2(0x08), // all waiting threads will be woken up, count will be zeroed
+	RELEASE_IF_WAITING_ONLY	= intrinsics.constant_log2(0x10), // release count only if there are any threads waiting
 }
+semaphore_flags :: distinct bit_set[semaphore_flag; u32]
 
+@(default_calling_convention="c")
 foreign libroot {
 	create_sem         :: proc(count: i32, name: cstring) -> sem_id ---
 	delete_sem         :: proc(id: sem_id) -> status_t ---
@@ -141,8 +147,8 @@ foreign libroot {
 	switch_sem_etc     :: proc(semToBeReleased: sem_id, id: sem_id, count: i32, flags: semaphore_flags, timeout: bigtime_t) -> status_t ---
 	get_sem_count      :: proc(id: sem_id, threadCount: ^i32) -> status_t ---
 	set_sem_owner      :: proc(id: sem_id, team: team_id) -> status_t ---
-	_get_sem_info      :: proc(id: sem_id, info: ^sem_info, infoSize: c.size_t) -> status_t ---
-	_get_next_sem_info :: proc(team: team_id, cookie: ^i32, info: ^sem_info, infoSize: c.size_t) -> status_t ---
+	_get_sem_info      :: proc(id: sem_id, info: ^sem_info, infoSize: uintptr) -> status_t ---
+	_get_next_sem_info :: proc(team: team_id, cookie: ^i32, info: ^sem_info, infoSize: uintptr) -> status_t ---
 }
 
 // Teams
@@ -155,7 +161,7 @@ team_info :: struct {
 	debugger_nub_thread: thread_id,
 	debugger_nub_port:   port_id,
 	argc:                i32,
-	args:                [64]c.char,
+	args:                [64]byte,
 	uid:                 uid_t,
 	gid:                 gid_t,
 
@@ -165,7 +171,7 @@ team_info :: struct {
 	group_id:            pid_t,
 	session_id:          pid_t,
 	parent:              team_id,
-	name:                [OS_NAME_LENGTH]c.char,
+	name:                [OS_NAME_LENGTH]byte,
 	start_time:          bigtime_t,
 }
 
@@ -183,17 +189,18 @@ team_usage_who :: enum i32 {
 	CHILDREN = -1,
 }
 
+@(default_calling_convention="c")
 foreign libroot {
 	// see also: send_signal()
 	kill_team            :: proc(team: team_id) -> status_t ---
-	_get_team_info       :: proc(id: team_id, info: ^team_info, size: c.size_t) -> status_t ---
-	_get_next_team_info  :: proc(cookie: ^i32, info: ^team_info, size: c.size_t) -> status_t ---
-	_get_team_usage_info :: proc(id: team_id, who: team_usage_who, info: ^team_usage_info, size: c.size_t) -> status_t ---
+	_get_team_info       :: proc(id: team_id, info: ^team_info, size: uintptr) -> status_t ---
+	_get_next_team_info  :: proc(cookie: ^i32, info: ^team_info, size: uintptr) -> status_t ---
+	_get_team_usage_info :: proc(id: team_id, who: team_usage_who, info: ^team_usage_info, size: uintptr) -> status_t ---
 }
 
 // Threads
 
-thread_state :: enum c.int {
+thread_state :: enum i32 {
 	RUNNING = 1,
 	READY,
 	RECEIVING,
@@ -205,7 +212,7 @@ thread_state :: enum c.int {
 thread_info :: struct {
 	thread:      thread_id,
 	team:        team_id,
-	name:        [OS_NAME_LENGTH]c.char,
+	name:        [OS_NAME_LENGTH]byte,
 	state:       thread_state,
 	priority:    thread_priority,
 	sem:         sem_id,
@@ -234,6 +241,7 @@ SYSTEM_TIMEBASE :: 0
 
 thread_func :: #type proc "c" (rawptr) -> status_t
 
+@(default_calling_convention="c")
 foreign libroot {
 	spawn_thread          :: proc(thread_func, name: cstring, priority: thread_priority, data: rawptr) -> thread_id ---
 	kill_thread           :: proc(thread: thread_id) -> status_t ---
@@ -247,24 +255,25 @@ foreign libroot {
 	wait_for_thread_etc   :: proc(id: thread_id, flags: u32, timeout: bigtime_t, _returnCode: ^status_t) -> status_t ---
 	on_exit_thread        :: proc(callback: proc "c" (rawptr), data: rawptr) -> status_t ---
 	find_thread           :: proc(name: cstring) -> thread_id ---
-	send_data             :: proc(thread: thread_id, code: i32, buffer: rawptr, bufferSize: c.size_t) -> status_t ---
-	receive_data          :: proc(sender: ^thread_id, buffer: rawptr, bufferSize: c.size_t) -> i32 ---
+	send_data             :: proc(thread: thread_id, code: i32, buffer: rawptr, bufferSize: uintptr) -> status_t ---
+	receive_data          :: proc(sender: ^thread_id, buffer: rawptr, bufferSize: uintptr) -> i32 ---
 	has_data              :: proc(thread: thread_id) -> bool ---
 	snooze                :: proc(amount: bigtime_t) -> status_t ---
 	// FIXME: Find and define those flags.
-	snooze_etc            :: proc(amount: bigtime_t, timeBase: c.int, flags: u32) -> status_t ---
-	snooze_until          :: proc(time: bigtime_t, timeBase: c.int) -> status_t ---
-	_get_thread_info      :: proc(id: thread_id, info: ^thread_info, size: c.size_t) -> status_t ---
-	_get_next_thread_info :: proc(team: team_id, cookie: ^i32, info: ^thread_info, size: c.size_t) -> status_t ---
+	snooze_etc            :: proc(amount: bigtime_t, timeBase: i32, flags: u32) -> status_t ---
+	snooze_until          :: proc(time: bigtime_t, timeBase: i32) -> status_t ---
+	_get_thread_info      :: proc(id: thread_id, info: ^thread_info, size: uintptr) -> status_t ---
+	_get_next_thread_info :: proc(team: team_id, cookie: ^i32, info: ^thread_info, size: uintptr) -> status_t ---
 	// bridge to the pthread API
 	get_pthread_thread_id :: proc(thread: pthread_t) -> thread_id ---
 }
 
 // Time
 
+@(default_calling_convention="c")
 foreign libroot {
-	real_time_clock       :: proc() -> c.ulong ---
-	set_real_time_clock   :: proc(secsSinceJan1st1970: c.ulong) ---
+	real_time_clock       :: proc() -> uint ---
+	set_real_time_clock   :: proc(secsSinceJan1st1970: uint) ---
 	real_time_clock_usecs :: proc() -> bigtime_t ---
 	// time since booting in microseconds
 	system_time           :: proc() -> bigtime_t ---
@@ -280,12 +289,14 @@ alarm_mode :: enum u32 {
 	PERIODIC_ALARM, // "when" specifies the period
 }
 
+@(default_calling_convention="c")
 foreign libroot {
 	set_alarm :: proc(_when: bigtime_t, mode: alarm_mode) -> bigtime_t ---
 }
 
 // Debugger
 
+@(default_calling_convention="c")
 foreign libroot {
 	debugger :: proc(message: cstring) ---
 	/*
@@ -296,7 +307,7 @@ foreign libroot {
 
 		to re-enable the default debugger pass a zero.
 	*/
-	disable_debugger :: proc(state: c.int) -> c.int ---
+	disable_debugger :: proc(state: i32) -> i32 ---
 }
 
 // System information
@@ -338,15 +349,15 @@ system_info :: struct {
 	max_teams:         u32,
 	used_teams:        u32,
 
-	kernel_name:       [FILE_NAME_LENGTH]c.char,
-	kernel_build_date: [OS_NAME_LENGTH]c.char,
-	kernel_build_time: [OS_NAME_LENGTH]c.char,
+	kernel_name:       [FILE_NAME_LENGTH]byte,
+	kernel_build_date: [OS_NAME_LENGTH]byte,
+	kernel_build_time: [OS_NAME_LENGTH]byte,
 
 	kernel_version:    i64,
 	abi:               u32,       // the system API
 }
 
-topology_level_type :: enum c.int {
+topology_level_type :: enum i32 {
 	UNKNOWN,
 	ROOT,
 	SMT,
@@ -354,7 +365,7 @@ topology_level_type :: enum c.int {
 	PACKAGE,
 }
 
-cpu_platform :: enum c.int {
+cpu_platform :: enum i32 {
 	UNKNOWN,
 	x86,
 	x86_64,
@@ -370,7 +381,7 @@ cpu_platform :: enum c.int {
 	RISC_V,
 }
 
-cpu_vendor :: enum c.int {
+cpu_vendor :: enum i32 {
 	UNKNOWN,
 	AMD,
 	CYRIX,
@@ -408,95 +419,68 @@ cpu_topology_node_info :: struct {
 	},
 }
 
-// FIXME: Add cpuid_info when bit fields are ready.
+when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
+	cpuid_info :: struct #raw_union {
+		eax_0: struct {
+			max_eax:   u32,
+			vendor_id: [12]byte,
+		},
 
-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 ---
-	get_cpu_topology_info :: proc(topologyInfos: [^]cpu_topology_node_info, topologyInfoCount: ^u32) -> status_t ---
+		eax_1: struct {
+			using _: bit_field u32 {
+				stepping:        u32 | 4,
+				model:           u32 | 4,
+				family:          u32 | 4,
+				type:            u32 | 2,
+				reserved_0:      u32 | 2,
+				extended_model:  u32 | 4,
+				extended_family: u32 | 8,
+				reserved_1:      u32 | 4,
+			},
+
+			using _: bit_field u32 {
+				brand_index:  u32 | 8,
+				clflush:      u32 | 8,
+				logical_cpus: u32 | 8,
+				apic_id:      u32 | 8,
+			},
+
+			features:          u32,
+			extended_features: u32,
+		},
 
-	is_computer_on        :: proc() -> i32 ---
-	is_computer_on_fire   :: proc() -> f64 ---
-}
+		eax_2: struct {
+			call_num:          u8,
+			cache_descriptors: [15]u8,
+		},
 
-// 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,
-}
+		eax_3: struct {
+			reserved:           [2]u32,
+			serial_number_high: u32,
+			serial_number_low:  u32,
+		},
+
+		as_chars: [16]byte,
 
-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
+		regs: struct {
+			eax: u32,
+			ebx: u32,
+			edx: u32,
+			ecx: u32,
+		},
+	}
 }
 
+@(default_calling_convention="c")
 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 ---
-
-	send_signal      :: proc(threadID: thread_id, signal: c.uint) -> c.int ---
-	set_signal_stack :: proc(base: rawptr, size: c.size_t) ---
+	get_system_info       :: proc(info: ^system_info) -> status_t ---
+	_get_cpu_info_etc     :: proc(firstCPU: u32, cpuCount: u32, info: ^cpu_info, size: uintptr) -> status_t ---
+	get_cpu_topology_info :: proc(topologyInfos: [^]cpu_topology_node_info, topologyInfoCount: ^u32) -> status_t ---
+
+	when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
+		get_cpuid :: proc(info: ^cpuid_info, eaxRegister: u32, cpuNum: u32) -> status_t ---
+	}
+
+	is_computer_on      :: proc() -> i32 ---
+	is_computer_on_fire :: proc() -> f64 ---
 }

+ 8 - 6
core/sys/haiku/types.odin

@@ -1,9 +1,7 @@
 #+build haiku
 package sys_haiku
 
-import "core:c"
-
-status_t       :: i32
+status_t       :: Errno
 bigtime_t      :: i64
 nanotime_t     :: i64
 type_code      :: u32
@@ -37,16 +35,20 @@ mode_t         :: u32
 umode_t        :: u32
 nlink_t        :: i32
 
-caddr_t        :: ^c.char
+caddr_t        :: [^]byte
 
 addr_t         :: phys_addr_t
 key_t          :: i32
 
 clockid_t      :: i32
 
-time_t         :: i64 when ODIN_ARCH == .amd64 || ODIN_ARCH == .arm64 else i32
+time_t   :: int
+timespec :: struct {
+	tv_sec:  time_t,
+	tv_nsec: int,
+}
 
-sig_atomic_t   :: c.int
+sig_atomic_t   :: i32
 sigset_t       :: u64
 
 image_id       :: i32

+ 88 - 1
core/sys/posix/errno.odin

@@ -1,4 +1,4 @@
-#+build windows, darwin, linux, freebsd, openbsd, netbsd
+#+build windows, darwin, linux, freebsd, openbsd, netbsd, haiku
 package posix
 
 import "core:c"
@@ -536,5 +536,92 @@ when ODIN_OS == .Darwin {
 	ETXTBSY         :: 139
 	EWOULDBLOCK     :: 140
 	EXDEV           :: 18
+} else when ODIN_OS == .Haiku {
+	_HAIKU_USE_POSITIVE_POSIX_ERRORS :: libc._HAIKU_USE_POSITIVE_POSIX_ERRORS
+	_POSIX_ERROR_FACTOR              :: libc._POSIX_ERROR_FACTOR
+	
+	_GENERAL_ERROR_BASE :: min(c.int)
+	_OS_ERROR_BASE      :: _GENERAL_ERROR_BASE + 0x1000
+	_STORAGE_ERROR_BASE :: _GENERAL_ERROR_BASE + 0x6000
+	_POSIX_ERROR_BASE   :: _GENERAL_ERROR_BASE + 0x7000
+
+	EIO             :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 1)     // B_IO_ERROR
+	EACCES          :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 2)     // B_PERMISSION_DENIED
+	EINVAL          :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 5)     // B_BAD_VALUE
+	ETIMEDOUT       :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 9)     // B_TIMED_OUT
+	EINTR           :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 10)    // B_INTERRUPTED
+	EAGAIN          :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 11)    // B_WOULD_BLOCK /* SysV compatibility */
+	EWOULDBLOCK     :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 11)    // B_WOULD_BLOCK /* BSD compatibility */
+	EBUSY           :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 14)    // B_BUSY
+	EPERM           :: _POSIX_ERROR_FACTOR * (_GENERAL_ERROR_BASE + 15)    // B_NOT_ALLOWED
+	EFAULT          :: _POSIX_ERROR_FACTOR * (_OS_ERROR_BASE      + 0x301) // B_BAD_ADDRESS
+	ENOEXEC         :: _POSIX_ERROR_FACTOR * (_OS_ERROR_BASE      + 0x302) // B_NOT_AN_EXECUTABLE
+	EBADF           :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 0)     // B_FILE_ERROR
+	EEXIST          :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 2)     // B_FILE_EXISTS
+	ENOENT          :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 3)     // B_ENTRY_NOT_FOUND
+	ENAMETOOLONG    :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 4)     // B_NAME_TOO_LONG
+	ENOTDIR         :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 5)     // B_NOT_A_DIRECTORY
+	ENOTEMPTY       :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 6)     // B_DIRECTORY_NOT_EMPTY
+	ENOSPC          :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 7)     // B_DEVICE_FULL
+	EROFS           :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 8)     // B_READ_ONLY_DEVICE
+	EISDIR          :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 9)     // B_IS_A_DIRECTORY
+	EMFILE          :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 10)    // B_NO_MORE_FDS
+	EXDEV           :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 11)    // B_CROSS_DEVICE_LINK
+	ELOOP           :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 12)    // B_LINK_LIMIT
+	EPIPE           :: _POSIX_ERROR_FACTOR * (_STORAGE_ERROR_BASE + 13)    // B_BUSTED_PIPE
+	ENOMEM          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 0) when _HAIKU_USE_POSITIVE_POSIX_ERRORS else (_GENERAL_ERROR_BASE + 0) // B_NO_MEMORY
+	E2BIG           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 1)
+	ECHILD          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 2)
+	EDEADLK         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 3)
+	EFBIG           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 4)
+	EMLINK          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 5)
+	ENFILE          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 6)
+	ENODEV          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 7)
+	ENOLCK          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 8)
+	ENOSYS          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 9)
+	ENOTTY          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 10)
+	ENXIO           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 11)
+	ESPIPE          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 12)
+	ESRCH           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 13)
+	EPROTOTYPE      :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 18)
+	EPROTONOSUPPORT :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 19)
+	EAFNOSUPPORT    :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 21)
+	EADDRINUSE      :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 22)
+	EADDRNOTAVAIL   :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 23)
+	ENETDOWN        :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 24)
+	ENETUNREACH     :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 25)
+	ENETRESET       :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 26)
+	ECONNABORTED    :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 27)
+	ECONNRESET      :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 28)
+	EISCONN         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 29)
+	ENOTCONN        :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 30)
+	ECONNREFUSED    :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 32)
+	EHOSTUNREACH    :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 33)
+	ENOPROTOOPT     :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 34)
+	ENOBUFS         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 35)
+	EINPROGRESS     :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 36)
+	EALREADY        :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 37)
+	ENOMSG          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 39)
+	ESTALE          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 40)
+	EOVERFLOW       :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 41)
+	EMSGSIZE        :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 42)
+	EOPNOTSUPP      :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 43)
+	ENOTSOCK        :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 44)
+	EBADMSG         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 46)
+	ECANCELED       :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 47)
+	EDESTADDRREQ    :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 48)
+	EDQUOT          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 49)
+	EIDRM           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 50)
+	EMULTIHOP       :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 51)
+	ENODATA         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 52)
+	ENOLINK         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 53)
+	ENOSR           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 54)
+	ENOSTR          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 55)
+	ENOTSUP         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 56)
+	EPROTO          :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 57)
+	ETIME           :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 58)
+	ETXTBSY         :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 59)
+	ENOTRECOVERABLE :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 61)
+	EOWNERDEAD      :: _POSIX_ERROR_FACTOR * (_POSIX_ERROR_BASE   + 62)
 }
 

+ 68 - 1
core/sys/posix/fcntl.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, openbsd, freebsd, netbsd
+#+build linux, darwin, openbsd, freebsd, netbsd, haiku
 package posix
 
 import "core:c"
@@ -343,6 +343,7 @@ when ODIN_OS == .Darwin {
 		l_type:   Lock_Type, /* [PSX] type of lock */
 		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset */
 	}
+
 } else when ODIN_OS == .OpenBSD {
 
 	off_t :: distinct c.int64_t
@@ -408,6 +409,72 @@ when ODIN_OS == .Darwin {
 		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset */
 	}
 
+} else when ODIN_OS == .Haiku {
+
+	off_t :: distinct c.int64_t
+	pid_t :: distinct c.int32_t
+
+	/* commands that can be passed to fcntl() */
+	F_DUPFD         :: 0x0001 /* duplicate fd */
+	F_GETFD         :: 0x0002 /* get fd flags */
+	F_SETFD         :: 0x0004 /* set fd flags */
+	F_GETFL         :: 0x0008 /* get file status flags and access mode */
+	F_SETFL         :: 0x0010 /* set file status flags */
+	F_GETLK         :: 0x0020 /* get locking information */
+	F_SETLK         :: 0x0080 /* set locking information */
+	F_SETLKW        :: 0x0100 /* as above, but waits if blocked */
+	F_DUPFD_CLOEXEC :: 0x0200 /* duplicate fd with close on exec set */
+	F_GETOWN        :: -1 // NOTE: Not supported.
+	F_SETOWN        :: -1 // NOTE: Not supported.
+
+	/* advisory locking types */
+	F_RDLCK :: 0x0040 /* read or shared lock */
+	F_UNLCK :: 0x0200 /* unlock */
+	F_WRLCK :: 0x0400 /* write or exclusive lock */
+
+	/* file descriptor flags for fcntl() */
+	FD_CLOEXEC :: 1
+
+	O_CLOEXEC   :: 0x00000040
+	O_CREAT     :: 0x0200
+	O_DIRECTORY :: 0x00200000
+	O_EXCL      :: 0x0100
+	O_NOCTTY    :: 0x1000
+	O_NOFOLLOW  :: 0x00080000
+	O_TRUNC     :: 0x0400
+
+	_O_TTY_INIT :: 0
+	O_TTY_INIT  :: O_Flags{} // NOTE: not defined in the headers
+
+	O_APPEND   :: 0x0800
+	O_DSYNC    :: 0x040000
+	O_NONBLOCK :: 0x0080
+	O_SYNC     :: 0x010000
+	O_RSYNC    :: 0x020000
+
+	O_EXEC   :: 0x04000000 // NOTE: not defined in the headers
+	O_RDONLY :: 0
+	O_RDWR   :: 0x0002
+	O_WRONLY :: 0x0001
+
+	_O_SEARCH :: 0
+	O_SEARCH  :: O_Flags{} // NOTE: not defined in the headers
+
+	AT_FDCWD: FD: -100
+
+	AT_EACCESS          :: 0x08
+	AT_SYMLINK_NOFOLLOW :: 0x01
+	AT_SYMLINK_FOLLOW   :: 0x02
+	AT_REMOVEDIR        :: 0x04
+
+	flock :: struct {
+		l_type:   Lock_Type, /* [PSX] type of lock */
+		l_whence: c.short,   /* [PSX] flag (Whence) of starting offset */
+		l_start:  off_t,     /* [PSX] relative offset in bytes */
+		l_len:    off_t,     /* [PSX] size; if 0 then until EOF */
+		l_pid:    pid_t,     /* [PSX] process ID of the process holding the lock */
+	}
+
 } else when ODIN_OS == .Linux {
 
 	off_t :: distinct c.int64_t

+ 2 - 2
core/sys/posix/grp.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "core:c"
@@ -115,7 +115,7 @@ foreign lib {
 	getgrnam_r :: proc(name: cstring, grp: ^group, buffer: [^]byte, bufsize: c.size_t, result: ^^group) -> Errno ---
 }
 
-when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux {
+when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku || ODIN_OS == .Linux {
 
 	gid_t :: distinct c.uint32_t
 

+ 51 - 1
core/sys/posix/pthread.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "core:c"
@@ -554,6 +554,56 @@ when ODIN_OS == .Darwin {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 	}
 
+} else when ODIN_OS == .Haiku {
+
+	PTHREAD_CANCEL_ASYNCHRONOUS :: 2
+	PTHREAD_CANCEL_DEFERRED     :: 0
+
+	PTHREAD_CANCEL_DISABLE      :: 1
+	PTHREAD_CANCEL_ENABLE       :: 0
+
+	PTHREAD_CANCELED :: rawptr(uintptr(1))
+
+	PTHREAD_CREATE_DETACHED :: 0x1
+	PTHREAD_CREATE_JOINABLE :: 0
+
+	PTHREAD_EXPLICIT_SCHED :: 0
+	PTHREAD_INHERIT_SCHED  :: 0x4
+
+	PTHREAD_PRIO_INHERIT :: 1
+	PTHREAD_PRIO_NONE    :: 0
+	PTHREAD_PRIO_PROTECT :: 2
+
+	PTHREAD_PROCESS_SHARED  :: 1
+	PTHREAD_PROCESS_PRIVATE :: 0
+
+	PTHREAD_SCOPE_PROCESS   :: 0
+	PTHREAD_SCOPE_SYSTEM    :: 0x2
+
+	pthread_t       :: distinct rawptr
+	pthread_attr_t  :: distinct rawptr
+	pthread_key_t   :: distinct c.int
+	
+	pthread_mutex_t :: struct {
+		flags:       u32,
+		lock:        i32,
+		unused:      i32,
+		owner:       i32,
+		owner_count: i32,
+	}
+	
+	pthread_cond_t :: struct {
+		flags:        u32,
+		unused:       i32,
+		mutex:        ^pthread_mutex_t,
+		waiter_count: i32,
+		lock:         i32,
+	}
+
+	sched_param :: struct {
+		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
+	}
+
 } else when ODIN_OS == .Linux {
 
 	PTHREAD_CANCEL_DEFERRED     :: 0

+ 8 - 1
core/sys/posix/sched.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "core:c"
@@ -101,4 +101,11 @@ when ODIN_OS == .Darwin {
 	SCHED_FIFO     :: 1
 	SCHED_RR       :: 2
 
+} else when ODIN_OS == .Haiku {
+
+	SCHED_FIFO     :: 1
+	SCHED_RR       :: 2
+	// SCHED_SPORADIC :: 3 NOTE: not a thing on freebsd, netbsd and probably others, leaving it out
+	SCHED_OTHER    :: 4
+
 }

+ 158 - 1
core/sys/posix/signal.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "base:intrinsics"
@@ -185,6 +185,16 @@ foreign lib {
 	*/
 	sigwait :: proc(set: ^sigset_t, sig: ^Signal) -> Errno ---
 
+	when ODIN_OS != .Darwin {
+		/*
+		Wait for queued signals.
+
+		[[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/sigtimedwait.html ]]
+		*/
+		sigtimedwait :: proc(set: ^sigset_t, info: ^siginfo_t, timeout: ^timespec) -> result ---
+	}
+
+
 	/* NOTE: unimplemented on darwin.
 
 	void   psiginfo(const siginfo_t *, const char *);
@@ -1180,4 +1190,151 @@ when ODIN_OS == .Darwin {
 	SI_TIMER   :: -2
 	SI_MESGQ   :: -3
 	SI_ASYNCIO :: -4
+
+} else when ODIN_OS == .Haiku {
+
+	// Request that signal be held
+	SIG_HOLD :: rawptr(uintptr(3))
+
+	uid_t :: distinct c.uint32_t
+	sigset_t :: distinct u64
+
+	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
+
+	// NOTE: this is actually defined as `sigaction`, but due to the function with the same name
+	// `_t` has been added.
+
+	sigaction_t :: struct {
+		using _: struct #raw_union {
+			sa_handler:   proc "c" (Signal),                     /* [PSX] signal-catching function or one of the SIG_IGN or SIG_DFL */
+			sa_sigaction: proc "c" (Signal, ^siginfo_t, rawptr), /* [PSX] signal-catching function */
+		},
+		sa_mask:     sigset_t, /* [PSX] set of signals to be blocked during execution of the signal handling function */
+		sa_flags:    SA_Flags, /* [PSX] special flags */
+		sa_userdata: rawptr,   /* will be passed to the signal handler, BeOS extension */
+	}
+
+	SIG_BLOCK   :: 1
+	SIG_UNBLOCK :: 2
+	SIG_SETMASK :: 3
+
+	SA_NOCLDSTOP :: 0x01
+	SA_NOCLDWAIT :: 0x02
+	SA_RESETHAND :: 0x04
+	SA_NODEFER   :: 0x08
+	SA_RESTART   :: 0x10
+	SA_ONSTACK   :: 0x20
+	SA_SIGINFO   :: 0x40
+
+	SS_ONSTACK :: 1
+	SS_DISABLE :: 2
+
+	MINSIGSTKSZ :: 8192
+	SIGSTKSZ    :: 16384
+
+	stack_t :: struct {
+		ss_sp:    rawptr,   /* [PSX] stack base or pointer */
+		ss_size:  c.size_t, /* [PSX] stack size */
+		ss_flags: SS_Flags, /* [PSX] flags */
+	}
+
+	siginfo_t :: struct {
+		si_signo: Signal,             /* [PSX] signal number */
+		si_code:  struct #raw_union { /* [PSX] specific more detailed codes per signal */
+			ill:  ILL_Code,
+			fpe:  FPE_Code,
+			segv: SEGV_Code,
+			bus:  BUS_Code,
+			trap: TRAP_Code,
+			chld: CLD_Code,
+			poll: POLL_Code,
+			any:  Any_Code,
+		},
+		si_errno:  Errno,  /* [PSX] errno value 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 */
+	}
+
+	/* any signal */
+	SI_USER       :: 0 /* signal sent by user */
+	SI_QUEUE      :: 1 /* signal sent by sigqueue() */
+	SI_TIMER      :: 2 /* signal sent on timer_settime() timeout */
+	SI_ASYNCIO    :: 3 /* signal sent on asynchronous I/O completion */
+	SI_MESGQ      :: 4 /* signal sent on arrival of message on empty message queue */
+	/* SIGILL */
+	ILL_ILLOPC    :: 10 /* illegal opcode */
+	ILL_ILLOPN    :: 11 /* illegal operand */
+	ILL_ILLADR    :: 12 /* illegal addressing mode */
+	ILL_ILLTRP    :: 13 /* illegal trap */
+	ILL_PRVOPC    :: 14 /* privileged opcode */
+	ILL_PRVREG    :: 15 /* privileged register */
+	ILL_COPROC    :: 16 /* coprocessor error */
+	ILL_BADSTK    :: 17 /* internal stack error */
+	/* SIGFPE */
+	FPE_INTDIV    :: 20 /* integer division by zero */
+	FPE_INTOVF    :: 21 /* integer overflow */
+	FPE_FLTDIV    :: 22 /* floating-point division by zero */
+	FPE_FLTOVF    :: 23 /* floating-point overflow */
+	FPE_FLTUND    :: 24 /* floating-point underflow */
+	FPE_FLTRES    :: 25 /* floating-point inexact result */
+	FPE_FLTINV    :: 26 /* invalid floating-point operation */
+	FPE_FLTSUB    :: 27 /* subscript out of range */
+	/* SIGSEGV */
+	SEGV_MAPERR   :: 30 /* address not mapped to object */
+	SEGV_ACCERR   :: 31 /* invalid permissions for mapped object */
+	/* SIGBUS */
+	BUS_ADRALN    :: 40 /* invalid address alignment */
+	BUS_ADRERR    :: 41 /* nonexistent physical address */
+	BUS_OBJERR    :: 42 /* object-specific hardware error */
+	/* SIGTRAP */
+	TRAP_BRKPT    :: 50 /* process breakpoint */
+	TRAP_TRACE    :: 51 /* process trace trap. */
+	/* SIGCHLD */
+	CLD_EXITED    :: 60 /* child exited */
+	CLD_KILLED    :: 61 /* child terminated abnormally without core dump */
+	CLD_DUMPED    :: 62 /* child terminated abnormally with core dump */
+	CLD_TRAPPED   :: 63 /* traced child trapped */
+	CLD_STOPPED   :: 64 /* child stopped */
+	CLD_CONTINUED :: 65 /* stopped child continued */
+	/* SIGPOLL */
+	POLL_IN       :: 70 /* input available */
+	POLL_OUT      :: 71 /* output available */
+	POLL_MSG      :: 72 /* input message available */
+	POLL_ERR      :: 73 /* I/O error */
+	POLL_PRI      :: 74 /* high priority input available */
+	POLL_HUP      :: 75 /* device disconnected */
+
 }

+ 1 - 1
core/sys/posix/signal_libc.odin

@@ -1,4 +1,4 @@
-#+build linux, windows, darwin, netbsd, openbsd, freebsd
+#+build linux, windows, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "base:intrinsics"

+ 31 - 1
core/sys/posix/sys_stat.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "core:c"
@@ -428,6 +428,36 @@ when ODIN_OS == .Darwin {
 	UTIME_NOW  :: -2
 	UTIME_OMIT :: -1
 
+} else when ODIN_OS == .Haiku {
+
+	dev_t      :: distinct c.int32_t
+	nlink_t    :: distinct c.int32_t
+	_mode_t    :: distinct c.uint32_t
+	blkcnt_t   :: distinct c.int64_t
+	blksize_t  :: distinct c.int32_t
+	ino_t      :: distinct c.int64_t
+
+	stat_t :: struct {
+		st_dev:           dev_t,        /* [PSX] ID of device containing file */
+		st_ino:           ino_t,        /* [PSX] file serial number */
+		st_mode:          mode_t,       /* [PSX] mode of file */
+		st_nlink:         nlink_t,      /* [PSX] number of hard links */
+		st_uid:           uid_t,        /* [PSX] user ID of the file */
+		st_gid:           gid_t,        /* [PSX] group ID of the file */
+		st_size:          off_t,        /* [PSX] file size, in bytes */
+		st_rdev:          dev_t,        /* [PSX] device ID */
+		st_blksize:       blksize_t,    /* [PSX] optimal blocksize for I/O */
+		st_atim:          timespec,     /* [PSX] time of last access */
+		st_mtim:          timespec,     /* [PSX] time of last data modification */
+		st_ctim:          timespec,     /* [PSX] time of last status change */
+		st_crtim:         timespec,     /* [PSX] time of last status change */
+		st_type:          c.uint32_t,
+		st_blocks:        blkcnt_t,     /* [PSX] blocks allocated for file */
+	}
+
+	UTIME_NOW  :: 1000000000
+	UTIME_OMIT :: 1000000001
+
 } else when ODIN_OS == .Linux {
 
 	dev_t     :: distinct u64

+ 12 - 1
core/sys/posix/time.odin

@@ -1,4 +1,4 @@
-#+build linux, darwin, netbsd, openbsd, freebsd
+#+build linux, darwin, netbsd, openbsd, freebsd, haiku
 package posix
 
 import "core:c"
@@ -230,6 +230,17 @@ when ODIN_OS == .Darwin {
 
 	getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD.
 
+} else when ODIN_OS == .Haiku {
+
+	clockid_t :: distinct c.int32_t
+
+	CLOCK_MONOTONIC          :: 0
+	CLOCK_PROCESS_CPUTIME_ID :: -2
+	CLOCK_REALTIME           :: -1
+	CLOCK_THREAD_CPUTIME_ID  :: -3
+
+	getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on Haiku.
+
 } else when ODIN_OS == .Linux {
 
 	clockid_t :: distinct c.int