Merge branch 'master' of github.com:odin-lang/Odin

This commit is contained in:
Jeroen van Rijn
2024-03-08 18:06:13 +01:00
34 changed files with 2551 additions and 552 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
//+private //+private
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
//+no-instrumentation //+no-instrumentation
package runtime package runtime
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
//+private //+private
package runtime package runtime
+21
View File
@@ -0,0 +1,21 @@
//+build haiku
//+private
package runtime
foreign import libc "system:c"
foreign libc {
@(link_name="write")
_unix_write :: proc(fd: i32, buf: rawptr, size: int) -> int ---
_errnop :: proc() -> ^i32 ---
}
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
ret := _unix_write(2, raw_data(data), len(data))
if ret < len(data) {
err := _errnop()
return int(ret), _OS_Errno(err^ if err != nil else 0)
}
return int(ret), 0
}
+5
View File
@@ -82,6 +82,11 @@ OpenBSD)
LDFLAGS="$LDFLAGS -liconv" LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" 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"
LDFLAGS="$LDFLAGS -liconv"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
;;
*) *)
error "Platform \"$OS_NAME\" unsupported" error "Platform \"$OS_NAME\" unsupported"
;; ;;
+18
View File
@@ -80,6 +80,24 @@ when ODIN_OS == .Darwin {
ERANGE :: 34 ERANGE :: 34
} }
when ODIN_OS == .Haiku {
@(private="file")
@(default_calling_convention="c")
foreign libc {
@(link_name="_errnop")
_get_errno :: proc() -> ^int ---
}
@(private="file")
B_GENERAL_ERROR_BASE :: min(i32)
@(private="file")
B_POSIX_ERROR_BASE :: B_GENERAL_ERROR_BASE + 0x7000
EDOM :: B_POSIX_ERROR_BASE + 16
EILSEQ :: B_POSIX_ERROR_BASE + 38
ERANGE :: B_POSIX_ERROR_BASE + 17
}
// Odin has no way to make an identifier "errno" behave as a function call to // Odin has no way to make an identifier "errno" behave as a function call to
// read the value, or to produce an lvalue such that you can assign a different // read the value, or to produce an lvalue such that you can assign a different
// error value to errno. To work around this, just expose it as a function like // error value to errno. To work around this, just expose it as a function like
+30
View File
@@ -163,6 +163,36 @@ when ODIN_OS == .Darwin {
} }
} }
when ODIN_OS == .Haiku {
fpos_t :: distinct i64
_IOFBF :: 0
_IOLBF :: 1
_IONBF :: 2
BUFSIZ :: 8192
EOF :: int(-1)
FOPEN_MAX :: 128
FILENAME_MAX :: 256
L_tmpnam :: 512
SEEK_SET :: 0
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 32768
foreign libc {
stderr: ^FILE
stdin: ^FILE
stdout: ^FILE
}
}
@(default_calling_convention="c") @(default_calling_convention="c")
foreign libc { foreign libc {
// 7.21.4 Operations on files // 7.21.4 Operations on files
+1 -1
View File
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
} }
} }
when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku {
@(default_calling_convention="c") @(default_calling_convention="c")
foreign libc { foreign libc {
// 7.27.2 Time manipulation functions // 7.27.2 Time manipulation functions
+4
View File
@@ -30,6 +30,10 @@ when ODIN_OS == .Windows {
wctrans_t :: distinct int wctrans_t :: distinct int
wctype_t :: distinct ulong wctype_t :: distinct ulong
} else when ODIN_OS == .Haiku {
wctrans_t :: distinct i32
wctype_t :: distinct i32
} }
@(default_calling_convention="c") @(default_calling_convention="c")
+3 -3
View File
@@ -2814,10 +2814,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index) value := runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index)
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb) fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, verb)
if verb == 'v' { if hash {
io.write_string(fi.writer, "=", &fi.n)
} else {
io.write_string(fi.writer, " = ", &fi.n) io.write_string(fi.writer, " = ", &fi.n)
} else {
io.write_string(fi.writer, "=", &fi.n)
} }
fmt_arg(fi, any{rawptr(value), info.value.id}, verb) fmt_arg(fi, any{rawptr(value), info.value.id}, verb)
+435
View File
@@ -0,0 +1,435 @@
package os
foreign import libc "system:c"
import "base:runtime"
import "core:c"
import "core:strings"
import "core:sys/haiku"
Handle :: i32
Pid :: i32
File_Time :: i64
Errno :: i32
MAX_PATH :: haiku.PATH_MAX
ENOSYS :: int(haiku.Errno.POSIX_ERROR_BASE) + 9
INVALID_HANDLE :: ~Handle(0)
ERROR_NONE: Errno: 0
stdin: Handle = 0
stdout: Handle = 1
stderr: Handle = 2
pid_t :: haiku.pid_t
off_t :: haiku.off_t
dev_t :: haiku.dev_t
ino_t :: haiku.ino_t
mode_t :: haiku.mode_t
nlink_t :: haiku.nlink_t
uid_t :: haiku.uid_t
gid_t :: haiku.gid_t
blksize_t :: haiku.blksize_t
blkcnt_t :: haiku.blkcnt_t
time_t :: haiku.time_t
Unix_File_Time :: struct {
seconds: time_t,
nanoseconds: c.long,
}
OS_Stat :: struct {
device_id: dev_t, // device ID that this file resides on
serial: ino_t, // this file's serial inode ID
mode: mode_t, // file mode (rwx for user, group, etc)
nlink: nlink_t, // number of hard links to this file
uid: uid_t, // user ID of the file's owner
gid: gid_t, // group ID of the file's group
size: off_t, // file size, in bytes
rdev: dev_t, // device type (not used)
block_size: blksize_t, // optimal blocksize for I/O
last_access: Unix_File_Time, // time of last access
modified: Unix_File_Time, // time of last data modification
status_change: Unix_File_Time, // time of last file status change
birthtime: Unix_File_Time, // time of file creation
type: u32, // attribute/index type
blocks: blkcnt_t, // blocks allocated for file
}
/* file access modes for open() */
O_RDONLY :: 0x0000 /* read only */
O_WRONLY :: 0x0001 /* write only */
O_RDWR :: 0x0002 /* read and write */
O_ACCMODE :: 0x0003 /* mask to get the access modes above */
O_RWMASK :: O_ACCMODE
/* flags for open() */
O_EXCL :: 0x0100 /* exclusive creat */
O_CREATE :: 0x0200 /* create and open file */
O_TRUNC :: 0x0400 /* open with truncation */
O_NOCTTY :: 0x1000 /* don't make tty the controlling tty */
O_NOTRAVERSE :: 0x2000 /* do not traverse leaf link */
// File type
S_IFMT :: 0o170000 // Type of file mask
S_IFIFO :: 0o010000 // Named pipe (fifo)
S_IFCHR :: 0o020000 // Character special
S_IFDIR :: 0o040000 // Directory
S_IFBLK :: 0o060000 // Block special
S_IFREG :: 0o100000 // Regular
S_IFLNK :: 0o120000 // Symbolic link
S_IFSOCK :: 0o140000 // Socket
S_ISVTX :: 0o001000 // Save swapped text even after use
// File mode
// Read, write, execute/search by owner
S_IRWXU :: 0o0700 // RWX mask for owner
S_IRUSR :: 0o0400 // R for owner
S_IWUSR :: 0o0200 // W for owner
S_IXUSR :: 0o0100 // X for owner
// Read, write, execute/search by group
S_IRWXG :: 0o0070 // RWX mask for group
S_IRGRP :: 0o0040 // R for group
S_IWGRP :: 0o0020 // W for group
S_IXGRP :: 0o0010 // X for group
// Read, write, execute/search by others
S_IRWXO :: 0o0007 // RWX mask for other
S_IROTH :: 0o0004 // R for other
S_IWOTH :: 0o0002 // W for other
S_IXOTH :: 0o0001 // X for other
S_ISUID :: 0o4000 // Set user id on execution
S_ISGID :: 0o2000 // Set group id on execution
S_ISTXT :: 0o1000 // Sticky bit
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
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 }
foreign libc {
@(link_name="_errnop") __error :: proc() -> ^c.int ---
@(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, mode: c.int) -> 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="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
@(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
@(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
@(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
@(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
@(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
}
MAXNAMLEN :: haiku.NAME_MAX
Dirent :: struct {
dev: dev_t,
pdef: dev_t,
ino: ino_t,
pino: ino_t,
reclen: u16,
name: [MAXNAMLEN + 1]byte, // name
}
Dir :: distinct rawptr // DIR*
is_path_separator :: proc(r: rune) -> bool {
return r == '/'
}
get_last_error :: proc "contextless" () -> int {
return int(__error()^)
}
fork :: proc() -> (Pid, Errno) {
pid := _unix_fork()
if pid == -1 {
return Pid(-1), Errno(get_last_error())
}
return Pid(pid), ERROR_NONE
}
open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
handle := _unix_open(cstr, c.int(flags), c.int(mode))
if handle == -1 {
return INVALID_HANDLE, Errno(get_last_error())
}
return handle, ERROR_NONE
}
close :: proc(fd: Handle) -> Errno {
result := _unix_close(fd)
if result == -1 {
return Errno(get_last_error())
}
return ERROR_NONE
}
// In practice a read/write call would probably never read/write these big buffers all at once,
// which is why the number of bytes is returned and why there are procs that will call this in a
// loop for you.
// We set a max of 1GB to keep alignment and to be safe.
@(private)
MAX_RW :: 1 << 30
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
to_read := min(c.size_t(len(data)), MAX_RW)
bytes_read := _unix_read(fd, &data[0], to_read)
if bytes_read == -1 {
return -1, Errno(get_last_error())
}
return int(bytes_read), ERROR_NONE
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
if len(data) == 0 {
return 0, ERROR_NONE
}
to_write := min(c.size_t(len(data)), MAX_RW)
bytes_written := _unix_write(fd, &data[0], to_write)
if bytes_written == -1 {
return -1, Errno(get_last_error())
}
return int(bytes_written), ERROR_NONE
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
res := _unix_seek(fd, offset, c.int(whence))
if res == -1 {
return -1, Errno(get_last_error())
}
return res, ERROR_NONE
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
s, err := _fstat(fd)
if err != ERROR_NONE {
return -1, err
}
return s.size, ERROR_NONE
}
// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments()
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
for arg, i in runtime.args__ {
res[i] = string(arg)
}
return res
}
@private
_stat :: proc(path: string) -> (OS_Stat, Errno) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_stat(cstr, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_lstat(cstr, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
// deliberately uninitialized
s: OS_Stat = ---
res := _unix_fstat(fd, &s)
if res == -1 {
return s, Errno(get_last_error())
}
return s, ERROR_NONE
}
@private
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
dirp := _unix_fdopendir(fd)
if dirp == cast(Dir)nil {
return nil, Errno(get_last_error())
}
return dirp, ERROR_NONE
}
@private
_closedir :: proc(dirp: Dir) -> Errno {
rc := _unix_closedir(dirp)
if rc != 0 {
return Errno(get_last_error())
}
return ERROR_NONE
}
@private
_rewinddir :: proc(dirp: Dir) {
_unix_rewinddir(dirp)
}
@private
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
result: ^Dirent
rc := _unix_readdir_r(dirp, &entry, &result)
if rc != 0 {
err = Errno(get_last_error())
return
}
err = ERROR_NONE
if result == nil {
end_of_stream = true
return
}
return
}
@private
_readlink :: proc(path: string) -> (string, Errno) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
bufsz : uint = MAX_PATH
buf := make([]byte, MAX_PATH)
for {
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
if rc == -1 {
delete(buf)
return "", Errno(get_last_error())
} else if rc == int(bufsz) {
bufsz += MAX_PATH
delete(buf)
buf = make([]byte, bufsz)
} else {
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
}
}
}
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
return "", Errno(ENOSYS)
}
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
rel := rel
if rel == "" {
rel = "."
}
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == context.allocator)
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
path_ptr := _unix_realpath(rel_cstr, nil)
if path_ptr == nil {
return "", Errno(get_last_error())
}
defer _unix_free(path_ptr)
path_cstr := transmute(cstring)path_ptr
path = strings.clone( string(path_cstr) )
return path, ERROR_NONE
}
access :: proc(path: string, mask: int) -> (bool, Errno) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
cstr := strings.clone_to_cstring(path, context.temp_allocator)
res := _unix_access(cstr, c.int(mask))
if res == -1 {
return false, Errno(get_last_error())
}
return true, ERROR_NONE
}
lookup_env :: proc(key: string, allocator := context.allocator) -> (value: string, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD(ignore = context.temp_allocator == allocator)
path_str := strings.clone_to_cstring(key, context.temp_allocator)
cstr := _unix_getenv(path_str)
if cstr == nil {
return "", false
}
return strings.clone(string(cstr), allocator), true
}
get_env :: proc(key: string, allocator := context.allocator) -> (value: string) {
value, _ = lookup_env(key, allocator)
return
}
@(private)
_processor_core_count :: proc() -> int {
info: haiku.system_info
haiku.get_system_info(&info)
return int(info.cpu_count)
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
_unix_exit(i32(code))
}
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
package os package os
import "core:time" import "core:time"
+3 -3
View File
@@ -32,7 +32,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
} }
case .Read_At: case .Read_At:
when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) { when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku) {
n_int, os_err = read_at(fd, p, offset) n_int, os_err = read_at(fd, p, offset)
n = i64(n_int) n = i64(n_int)
if n == 0 && os_err == 0 { if n == 0 && os_err == 0 {
@@ -46,7 +46,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
err = .EOF err = .EOF
} }
case .Write_At: case .Write_At:
when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD) { when !(ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku) {
n_int, os_err = write_at(fd, p, offset) n_int, os_err = write_at(fd, p, offset)
n = i64(n_int) n = i64(n_int)
if n == 0 && os_err == 0 { if n == 0 && os_err == 0 {
@@ -60,7 +60,7 @@ _file_stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte,
case .Destroy: case .Destroy:
err = .Empty err = .Empty
case .Query: case .Query:
when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD { when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Haiku {
return io.query_utility({.Close, .Flush, .Read, .Write, .Seek, .Size, .Query}) return io.query_utility({.Close, .Flush, .Read, .Write, .Seek, .Size, .Query})
} else { } else {
return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query}) return io.query_utility({.Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query})
+167
View File
@@ -0,0 +1,167 @@
//+private
package sync
import "core:c"
import "core:runtime"
import "core:sys/haiku"
import "core:sys/unix"
import "core:time"
@(private="file")
Wait_Node :: struct {
thread: unix.pthread_t,
futex: ^Futex,
prev, next: ^Wait_Node,
}
@(private="file")
atomic_flag :: distinct bool
@(private="file")
Wait_Queue :: struct {
lock: atomic_flag,
list: Wait_Node,
}
@(private="file")
waitq_lock :: proc "contextless" (waitq: ^Wait_Queue) {
for cast(bool)atomic_exchange_explicit(&waitq.lock, atomic_flag(true), .Acquire) {
cpu_relax() // spin...
}
}
@(private="file")
waitq_unlock :: proc "contextless" (waitq: ^Wait_Queue) {
atomic_store_explicit(&waitq.lock, atomic_flag(false), .Release)
}
// FIXME: This approach may scale badly in the future,
// possible solution - hash map (leads to deadlocks now).
@(private="file")
g_waitq: Wait_Queue
@(init, private="file")
g_waitq_init :: proc() {
g_waitq = {
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) -> (ok: 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)
errno := haiku.errno()
ok = errno == .OK
}
waiter.prev.next = waiter.next
waiter.next.prev = waiter.prev
unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil)
// FIXME: Add error handling!
return
}
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> (ok: bool) {
if duration <= 0 {
return false
}
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)
info: haiku.siginfo_t
ts := unix.timespec{
tv_sec = i64(duration / 1e9),
tv_nsec = i64(duration % 1e9),
}
haiku.sigtimedwait(&mask, &info, &ts)
errno := haiku.errno()
ok = errno == .EAGAIN || errno == .OK
}
waiter.prev.next = waiter.next
waiter.next.prev = waiter.prev
unix.pthread_sigmask(haiku.SIG_SETMASK, &old_mask, nil)
// FIXME: Add error handling!
return
}
_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)
}
}
}
+8
View File
@@ -0,0 +1,8 @@
//+private
package sync
import "core:sys/haiku"
_current_thread_id :: proc "contextless" () -> int {
return int(haiku.find_thread(nil))
}
+239
View File
@@ -0,0 +1,239 @@
//+build haiku
package sys_haiku
import "core:c"
Errno :: enum c.int {
// Error baselines
GENERAL_ERROR_BASE = min(c.int),
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,
// Some POSIX errors
E2BIG = POSIX_ERROR_BASE + 1,
EFBIG = POSIX_ERROR_BASE + 4,
ENODEV = POSIX_ERROR_BASE + 7,
ERANGE = POSIX_ERROR_BASE + 17,
EOVERFLOW = POSIX_ERROR_BASE + 41,
EOPNOTSUPP = POSIX_ERROR_BASE + 43,
ENOSYS = POSIX_ERROR_BASE + 9,
EAGAIN = WOULD_BLOCK,
// New error codes that can be mapped to POSIX errors
TOO_MANY_ARGS_NEG = E2BIG,
FILE_TOO_LARGE_NEG = EFBIG,
DEVICE_NOT_FOUND_NEG = ENODEV,
RESULT_NOT_REPRESENTABLE_NEG = ERANGE,
BUFFER_OVERFLOW_NEG = EOVERFLOW,
NOT_SUPPORTED_NEG = EOPNOTSUPP,
TOO_MANY_ARGS_POS = -E2BIG,
FILE_TOO_LARGE_POS = -EFBIG,
DEVICE_NOT_FOUND_POS = -ENODEV,
RESULT_NOT_REPRESENTABLE_POS = -ERANGE,
BUFFER_OVERFLOW_POS = -EOVERFLOW,
NOT_SUPPORTED_POS = -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,
}
errno :: #force_inline proc "contextless" () -> Errno {
return Errno(_errnop()^)
}
foreign import libroot "system:c"
foreign libroot {
_to_positive_error :: proc(error: c.int) -> c.int ---
_to_negative_error :: proc(error: c.int) -> c.int ---
_errnop :: proc() -> ^c.int ---
}
+168
View File
@@ -0,0 +1,168 @@
//+build haiku
package sys_haiku
import "core:c"
directory_which :: enum c.int {
// Per volume directories
DESKTOP_DIRECTORY = 0,
TRASH_DIRECTORY,
// System directories
SYSTEM_DIRECTORY = 1000,
SYSTEM_ADDONS_DIRECTORY = 1002,
SYSTEM_BOOT_DIRECTORY,
SYSTEM_FONTS_DIRECTORY,
SYSTEM_LIB_DIRECTORY,
SYSTEM_SERVERS_DIRECTORY,
SYSTEM_APPS_DIRECTORY,
SYSTEM_BIN_DIRECTORY,
SYSTEM_DOCUMENTATION_DIRECTORY = 1010,
SYSTEM_PREFERENCES_DIRECTORY,
SYSTEM_TRANSLATORS_DIRECTORY,
SYSTEM_MEDIA_NODES_DIRECTORY,
SYSTEM_SOUNDS_DIRECTORY,
SYSTEM_DATA_DIRECTORY,
SYSTEM_DEVELOP_DIRECTORY,
SYSTEM_PACKAGES_DIRECTORY,
SYSTEM_HEADERS_DIRECTORY,
SYSTEM_ETC_DIRECTORY = 2008,
SYSTEM_SETTINGS_DIRECTORY = 2010,
SYSTEM_LOG_DIRECTORY = 2012,
SYSTEM_SPOOL_DIRECTORY,
SYSTEM_TEMP_DIRECTORY,
SYSTEM_VAR_DIRECTORY,
SYSTEM_CACHE_DIRECTORY = 2020,
SYSTEM_NONPACKAGED_DIRECTORY = 2023,
SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
SYSTEM_NONPACKAGED_TRANSLATORS_DIRECTORY,
SYSTEM_NONPACKAGED_MEDIA_NODES_DIRECTORY,
SYSTEM_NONPACKAGED_BIN_DIRECTORY,
SYSTEM_NONPACKAGED_DATA_DIRECTORY,
SYSTEM_NONPACKAGED_FONTS_DIRECTORY,
SYSTEM_NONPACKAGED_SOUNDS_DIRECTORY,
SYSTEM_NONPACKAGED_DOCUMENTATION_DIRECTORY,
SYSTEM_NONPACKAGED_LIB_DIRECTORY,
SYSTEM_NONPACKAGED_HEADERS_DIRECTORY,
SYSTEM_NONPACKAGED_DEVELOP_DIRECTORY,
// User directories. These are interpreted in the context of the user making the find_directory call.
USER_DIRECTORY = 3000,
USER_CONFIG_DIRECTORY,
USER_ADDONS_DIRECTORY,
USER_BOOT_DIRECTORY,
USER_FONTS_DIRECTORY,
USER_LIB_DIRECTORY,
USER_SETTINGS_DIRECTORY,
USER_DESKBAR_DIRECTORY,
USER_PRINTERS_DIRECTORY,
USER_TRANSLATORS_DIRECTORY,
USER_MEDIA_NODES_DIRECTORY,
USER_SOUNDS_DIRECTORY,
USER_DATA_DIRECTORY,
USER_CACHE_DIRECTORY,
USER_PACKAGES_DIRECTORY,
USER_HEADERS_DIRECTORY,
USER_NONPACKAGED_DIRECTORY,
USER_NONPACKAGED_ADDONS_DIRECTORY,
USER_NONPACKAGED_TRANSLATORS_DIRECTORY,
USER_NONPACKAGED_MEDIA_NODES_DIRECTORY,
USER_NONPACKAGED_BIN_DIRECTORY,
USER_NONPACKAGED_DATA_DIRECTORY,
USER_NONPACKAGED_FONTS_DIRECTORY,
USER_NONPACKAGED_SOUNDS_DIRECTORY,
USER_NONPACKAGED_DOCUMENTATION_DIRECTORY,
USER_NONPACKAGED_LIB_DIRECTORY,
USER_NONPACKAGED_HEADERS_DIRECTORY,
USER_NONPACKAGED_DEVELOP_DIRECTORY,
USER_DEVELOP_DIRECTORY,
USER_DOCUMENTATION_DIRECTORY,
USER_SERVERS_DIRECTORY,
USER_APPS_DIRECTORY,
USER_BIN_DIRECTORY,
USER_PREFERENCES_DIRECTORY,
USER_ETC_DIRECTORY,
USER_LOG_DIRECTORY,
USER_SPOOL_DIRECTORY,
USER_VAR_DIRECTORY,
// Global directories
APPS_DIRECTORY = 4000,
PREFERENCES_DIRECTORY,
UTILITIES_DIRECTORY,
PACKAGE_LINKS_DIRECTORY,
// Obsolete: Legacy BeOS definition to be phased out
BEOS_DIRECTORY = 1000,
BEOS_SYSTEM_DIRECTORY,
BEOS_ADDONS_DIRECTORY,
BEOS_BOOT_DIRECTORY,
BEOS_FONTS_DIRECTORY,
BEOS_LIB_DIRECTORY,
BEOS_SERVERS_DIRECTORY,
BEOS_APPS_DIRECTORY,
BEOS_BIN_DIRECTORY,
BEOS_ETC_DIRECTORY,
BEOS_DOCUMENTATION_DIRECTORY,
BEOS_PREFERENCES_DIRECTORY,
BEOS_TRANSLATORS_DIRECTORY,
BEOS_MEDIA_NODES_DIRECTORY,
BEOS_SOUNDS_DIRECTORY,
}
find_path_flags :: enum c.int {
CREATE_DIRECTORY = 0x0001,
CREATE_PARENT_DIRECTORY = 0x0002,
EXISTING_ONLY = 0x0004,
// find_paths() only!
SYSTEM_ONLY = 0x0010,
USER_ONLY = 0x0020,
}
path_base_directory :: enum c.int {
INSTALLATION_LOCATION_DIRECTORY,
ADD_ONS_DIRECTORY,
APPS_DIRECTORY,
BIN_DIRECTORY,
BOOT_DIRECTORY,
CACHE_DIRECTORY,
DATA_DIRECTORY,
DEVELOP_DIRECTORY,
DEVELOP_LIB_DIRECTORY,
DOCUMENTATION_DIRECTORY,
ETC_DIRECTORY,
FONTS_DIRECTORY,
HEADERS_DIRECTORY,
LIB_DIRECTORY,
LOG_DIRECTORY,
MEDIA_NODES_DIRECTORY,
PACKAGES_DIRECTORY,
PREFERENCES_DIRECTORY,
SERVERS_DIRECTORY,
SETTINGS_DIRECTORY,
SOUNDS_DIRECTORY,
SPOOL_DIRECTORY,
TRANSLATORS_DIRECTORY,
VAR_DIRECTORY,
// find_path() only!
IMAGE_PATH = 1000,
PACKAGE_PATH,
}
// 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) }
foreign import libroot "system: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 ---
}
+502
View File
@@ -0,0 +1,502 @@
//+build haiku
package sys_haiku
import "core:c"
import "core:sys/unix"
foreign import libroot "system:c"
PATH_MAX :: 1024
NAME_MAX :: 256
MAXPATHLEN :: PATH_MAX
FILE_NAME_LENGTH :: NAME_MAX
PATH_NAME_LENGTH :: MAXPATHLEN
OS_NAME_LENGTH :: 32
// Areas
area_info :: struct {
area: area_id,
name: [OS_NAME_LENGTH]c.char,
size: c.size_t,
lock: u32,
protection: u32,
team: team_id,
ram_size: u32,
copy_count: u32,
in_count: u32,
out_count: u32,
address: rawptr,
}
area_locking :: enum u32 {
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
}
// for create_area() and clone_area()
address_spec :: enum u32 {
ANY_ADDRESS = 0,
EXACT_ADDRESS = 1,
BASE_ADDRESS = 2,
CLONE_ADDRESS = 3,
ANY_KERNEL_ADDRESS = 4,
// ANY_KERNEL_BLOCK_ADDRESS = 5,
RANDOMIZED_ANY_ADDRESS = 6,
RANDOMIZED_BASE_ADDRESS = 7,
}
area_protection_flags :: enum u32 {
READ_AREA = 1 << 0,
WRITE_AREA = 1 << 1,
EXECUTE_AREA = 1 << 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,
}
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 ---
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 ---
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 ---
}
// Ports
port_info :: struct {
port: port_id,
team: team_id,
name: [OS_NAME_LENGTH]c.char,
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,
// read the message, but don't remove it; kernel-only; memory must be locked
PEEK_PORT_MESSAGE = 0x100,
}
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 ---
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 ---
}
// Semaphores
sem_info :: struct {
sem: sem_id,
team: team_id,
name: [OS_NAME_LENGTH]c.char,
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)
// 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
}
foreign libroot {
create_sem :: proc(count: i32, name: cstring) -> sem_id ---
delete_sem :: proc(id: sem_id) -> status_t ---
acquire_sem :: proc(id: sem_id) -> status_t ---
acquire_sem_etc :: proc(id: sem_id, count: i32, flags: semaphore_flags, timeout: bigtime_t) -> status_t ---
release_sem :: proc(id: sem_id) -> status_t ---
release_sem_etc :: proc(id: sem_id, count: i32, flags: semaphore_flags) -> status_t ---
switch_sem :: proc(semToBeReleased: sem_id) -> status_t ---
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 ---
}
// Teams
team_info :: struct {
team: team_id,
thread_count: i32,
image_count: i32,
area_count: i32,
debugger_nub_thread: thread_id,
debugger_nub_port: port_id,
argc: i32,
args: [64]c.char,
uid: uid_t,
gid: gid_t,
// Haiku R1 extensions
real_uid: uid_t,
real_gid: gid_t,
group_id: pid_t,
session_id: pid_t,
parent: team_id,
name: [OS_NAME_LENGTH]c.char,
start_time: bigtime_t,
}
CURRENT_TEAM :: 0
SYSTEM_TEAM :: 1
team_usage_info :: struct {
user_time: bigtime_t,
kernel_time: bigtime_t,
}
team_usage_who :: enum i32 {
// compatible to sys/resource.h RUSAGE_SELF and RUSAGE_CHILDREN
SELF = 0,
CHILDREN = -1,
}
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 ---
}
// Threads
thread_state :: enum c.int {
RUNNING = 1,
READY,
RECEIVING,
ASLEEP,
SUSPENDED,
WAITING,
}
thread_info :: struct {
thread: thread_id,
team: team_id,
name: [OS_NAME_LENGTH]c.char,
state: thread_state,
priority: thread_priority,
sem: sem_id,
user_time: bigtime_t,
kernel_time: bigtime_t,
stack_base: rawptr,
stack_end: rawptr,
}
thread_priority :: enum i32 {
IDLE_PRIORITY = 0,
LOWEST_ACTIVE_PRIORITY = 1,
LOW_PRIORITY = 5,
NORMAL_PRIORITY = 10,
DISPLAY_PRIORITY = 15,
URGENT_DISPLAY_PRIORITY = 20,
REAL_TIME_DISPLAY_PRIORITY = 100,
URGENT_PRIORITY = 110,
REAL_TIME_PRIORITY = 120,
}
FIRST_REAL_TIME_PRIORITY :: thread_priority.REAL_TIME_PRIORITY
// time base for snooze_*(), compatible with the clockid_t constants defined in <time.h>
SYSTEM_TIMEBASE :: 0
thread_func :: #type proc "c" (rawptr) -> status_t
foreign libroot {
spawn_thread :: proc(thread_func, name: cstring, priority: thread_priority, data: rawptr) -> thread_id ---
kill_thread :: proc(thread: thread_id) -> status_t ---
resume_thread :: proc(thread: thread_id) -> status_t ---
suspend_thread :: proc(thread: thread_id) -> status_t ---
rename_thread :: proc(thread: thread_id, newName: cstring) -> status_t ---
set_thread_priority :: proc(thread: thread_id, newPriority: thread_priority) -> status_t ---
exit_thread :: proc(status: status_t) ---
wait_for_thread :: proc(thread: thread_id, returnValue: ^status_t) -> status_t ---
// FIXME: Find and define those flags.
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 ---
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 ---
// bridge to the pthread API
get_pthread_thread_id :: proc(thread: pthread_t) -> thread_id ---
}
// Time
foreign libroot {
real_time_clock :: proc() -> c.ulong ---
set_real_time_clock :: proc(secsSinceJan1st1970: c.ulong) ---
real_time_clock_usecs :: proc() -> bigtime_t ---
// time since booting in microseconds
system_time :: proc() -> bigtime_t ---
// time since booting in nanoseconds
system_time_nsecs :: proc() -> nanotime_t ---
}
// Alarm
alarm_mode :: enum u32 {
ONE_SHOT_ABSOLUTE_ALARM = 1,
ONE_SHOT_RELATIVE_ALARM,
PERIODIC_ALARM, // "when" specifies the period
}
foreign libroot {
set_alarm :: proc(_when: bigtime_t, mode: alarm_mode) -> bigtime_t ---
}
// Debugger
foreign libroot {
debugger :: proc(message: cstring) ---
/*
calling this function with a non-zero value will cause your thread
to receive signals for any exceptional conditions that occur (i.e.
you'll get SIGSEGV for data access exceptions, SIGFPE for floating
point errors, SIGILL for illegal instructions, etc).
to re-enable the default debugger pass a zero.
*/
disable_debugger :: proc(state: c.int) -> c.int ---
}
// System information
cpu_info :: struct {
active_time: bigtime_t,
enabled: bool,
current_frequency: u64,
}
system_info :: struct {
boot_time: bigtime_t, // time of boot (usecs since 1/1/1970)
cpu_count: u32, // number of cpus
max_pages: u64, // total # of accessible pages
used_pages: u64, // # of accessible pages in use
cached_pages: u64,
block_cache_pages: u64,
ignored_pages: u64, // # of ignored/inaccessible pages
needed_memory: u64,
free_memory: u64,
max_swap_pages: u64,
free_swap_pages: u64,
page_faults: u32, // # of page faults
max_sems: u32,
used_sems: u32,
max_ports: u32,
used_ports: u32,
max_threads: u32,
used_threads: u32,
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_version: i64,
abi: u32, // the system API
}
topology_level_type :: enum c.int {
UNKNOWN,
ROOT,
SMT,
CORE,
PACKAGE,
}
cpu_platform :: enum c.int {
UNKNOWN,
x86,
x86_64,
PPC,
PPC_64,
M68K,
ARM,
ARM_64,
ALPHA,
MIPS,
SH,
SPARC,
RISC_V,
}
cpu_vendor :: enum c.int {
UNKNOWN,
AMD,
CYRIX,
IDT,
INTEL,
NATIONAL_SEMICONDUCTOR,
RISE,
TRANSMETA,
VIA,
IBM,
MOTOROLA,
NEC,
HYGON,
SUN,
FUJITSU,
}
cpu_topology_node_info :: struct {
id: u32,
type: topology_level_type,
level: u32,
data: struct #raw_union {
_root: struct {
platform: cpu_platform,
},
_package: struct {
vendor: cpu_vendor,
cache_line_size: u32
},
_core: struct {
model: u32,
default_frequency: u64,
},
},
}
// FIXME: Add cpuid_info when bit fields are ready.
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 ---
is_computer_on :: proc() -> i32 ---
is_computer_on_fire :: proc() -> f64 ---
}
// 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 ---
send_signal :: proc(threadID: thread_id, signal: c.uint) -> c.int ---
set_signal_stack :: proc(base: rawptr, size: c.size_t) ---
}
+54
View File
@@ -0,0 +1,54 @@
//+build haiku
package sys_haiku
import "core:c"
status_t :: i32
bigtime_t :: i64
nanotime_t :: i64
type_code :: u32
perform_code :: u32
phys_addr_t :: uintptr
phys_size_t :: phys_addr_t
generic_addr_t :: uintptr
generic_size_t :: generic_addr_t
area_id :: i32
port_id :: i32
sem_id :: i32
team_id :: i32
thread_id :: i32
blkcnt_t :: i64
blksize_t :: i32
fsblkcnt_t :: i64
fsfilcnt_t :: i64
off_t :: i64
ino_t :: i64
cnt_t :: i32
dev_t :: i32
pid_t :: i32
id_t :: i32
uid_t :: u32
gid_t :: u32
mode_t :: u32
umode_t :: u32
nlink_t :: i32
caddr_t :: ^c.char
addr_t :: phys_addr_t
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
image_id :: i32
pthread_t :: rawptr
+71
View File
@@ -0,0 +1,71 @@
package unix
import "core:c"
pthread_t :: distinct rawptr
pthread_attr_t :: distinct rawptr
pthread_mutex_t :: distinct rawptr
pthread_mutexattr_t :: distinct rawptr
pthread_cond_t :: distinct rawptr
pthread_condattr_t :: distinct rawptr
pthread_rwlock_t :: distinct rawptr
pthread_rwlockattr_t :: distinct rawptr
pthread_barrier_t :: distinct rawptr
pthread_barrierattr_t :: distinct rawptr
pthread_spinlock_t :: distinct rawptr
pthread_key_t :: distinct c.int
pthread_once_t :: struct {
state: c.int,
mutex: pthread_mutex_t,
}
PTHREAD_MUTEX_DEFAULT :: 0
PTHREAD_MUTEX_NORMAL :: 1
PTHREAD_MUTEX_ERRORCHECK :: 2
PTHREAD_MUTEX_RECURSIVE :: 3
PTHREAD_DETACHED :: 0x1
PTHREAD_SCOPE_SYSTEM :: 0x2
PTHREAD_INHERIT_SCHED :: 0x4
PTHREAD_NOFLOAT :: 0x8
PTHREAD_CREATE_DETACHED :: PTHREAD_DETACHED
PTHREAD_CREATE_JOINABLE :: 0
PTHREAD_SCOPE_PROCESS :: 0
PTHREAD_EXPLICIT_SCHED :: 0
SCHED_FIFO :: 1
SCHED_RR :: 2
SCHED_SPORADIC :: 3
SCHED_OTHER :: 4
sched_param :: struct {
sched_priority: c.int,
}
sem_t :: distinct rawptr
PTHREAD_CANCEL_ENABLE :: 0
PTHREAD_CANCEL_DISABLE :: 1
PTHREAD_CANCEL_DEFERRED :: 0
PTHREAD_CANCEL_ASYNCHRONOUS :: 2
foreign import libc "system:c"
@(default_calling_convention="c")
foreign libc {
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 ---
pthread_yield :: proc() ---
pthread_setcancelstate :: proc (state: c.int, old_state: ^c.int) -> c.int ---
pthread_setcanceltype :: proc (type: c.int, old_type: ^c.int) -> c.int ---
pthread_cancel :: proc (thread: pthread_t) -> c.int ---
}
+16 -8
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
package unix package unix
foreign import "system:pthread" foreign import "system:pthread"
@@ -16,6 +16,8 @@ foreign pthread {
// retval is a pointer to a location to put the return value of the thread proc. // 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_join :: proc(t: pthread_t, retval: ^rawptr) -> c.int ---
pthread_kill :: proc(t: pthread_t, sig: c.int) -> c.int ---
pthread_self :: proc() -> pthread_t --- pthread_self :: proc() -> pthread_t ---
pthread_equal :: proc(a, b: pthread_t) -> b32 --- pthread_equal :: proc(a, b: pthread_t) -> b32 ---
@@ -31,15 +33,9 @@ foreign pthread {
pthread_attr_getschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> 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_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 // states: PTHREAD_CREATE_DETACHED, PTHREAD_CREATE_JOINABLE
pthread_attr_setdetachstate :: proc(attrs: ^pthread_attr_t, detach_state: c.int) -> c.int --- 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. // NOTE(tetra, 2019-11-06): WARNING: Different systems have different alignment requirements.
// For maximum usefulness, use the OS's page size. // 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 // ALSO VERY MAJOR WARNING: `stack_ptr` must be the LAST byte of the stack on systems
@@ -52,8 +48,20 @@ foreign pthread {
pthread_attr_setstack :: proc(attrs: ^pthread_attr_t, stack_ptr: rawptr, stack_size: u64) -> c.int --- 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_attr_getstack :: proc(attrs: ^pthread_attr_t, stack_ptr: ^rawptr, stack_size: ^u64) -> c.int ---
sched_yield :: proc() -> c.int --- pthread_sigmask :: proc(how: c.int, set: rawptr, oldset: rawptr) -> c.int ---
sched_yield :: proc() -> c.int ---
}
// NOTE: Unimplemented in Haiku.
when ODIN_OS != .Haiku {
foreign pthread {
// scheds: PTHREAD_INHERIT_SCHED, PTHREAD_EXPLICIT_SCHED
pthread_attr_setinheritsched :: proc(attrs: ^pthread_attr_t, sched: c.int) -> 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 ---
}
} }
@(default_calling_convention="c") @(default_calling_convention="c")
+1 -1
View File
@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
package unix package unix
when ODIN_OS == .Darwin { when ODIN_OS == .Darwin {
+9 -4
View File
@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd, openbsd // +build linux, darwin, freebsd, openbsd, haiku
// +private // +private
package thread package thread
@@ -78,7 +78,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// NOTE(tetra, 2019-11-01): These only fail if their argument is invalid. // NOTE(tetra, 2019-11-01): These only fail if their argument is invalid.
assert(unix.pthread_attr_setdetachstate(&attrs, unix.PTHREAD_CREATE_JOINABLE) == 0) assert(unix.pthread_attr_setdetachstate(&attrs, unix.PTHREAD_CREATE_JOINABLE) == 0)
assert(unix.pthread_attr_setinheritsched(&attrs, unix.PTHREAD_EXPLICIT_SCHED) == 0) when ODIN_OS != .Haiku {
assert(unix.pthread_attr_setinheritsched(&attrs, unix.PTHREAD_EXPLICIT_SCHED) == 0)
}
thread := new(Thread) thread := new(Thread)
if thread == nil { if thread == nil {
@@ -88,8 +90,11 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
// Set thread priority. // Set thread priority.
policy: i32 policy: i32
res := unix.pthread_attr_getschedpolicy(&attrs, &policy) res: i32
assert(res == 0) when ODIN_OS != .Haiku {
res = unix.pthread_attr_getschedpolicy(&attrs, &policy)
assert(res == 0)
}
params: unix.sched_param params: unix.sched_param
res = unix.pthread_attr_getschedparam(&attrs, &params) res = unix.pthread_attr_getschedparam(&attrs, &params)
assert(res == 0) assert(res == 0)
+1 -1
View File
@@ -1,5 +1,5 @@
//+private //+private
//+build linux, darwin, freebsd, openbsd //+build linux, darwin, freebsd, openbsd, haiku
package time package time
import "core:sys/unix" import "core:sys/unix"
+68 -3
View File
@@ -18,6 +18,7 @@ enum TargetOsKind : u16 {
TargetOs_essence, TargetOs_essence,
TargetOs_freebsd, TargetOs_freebsd,
TargetOs_openbsd, TargetOs_openbsd,
TargetOs_haiku,
TargetOs_wasi, TargetOs_wasi,
TargetOs_js, TargetOs_js,
@@ -78,6 +79,7 @@ gb_global String target_os_names[TargetOs_COUNT] = {
str_lit("essence"), str_lit("essence"),
str_lit("freebsd"), str_lit("freebsd"),
str_lit("openbsd"), str_lit("openbsd"),
str_lit("haiku"),
str_lit("wasi"), str_lit("wasi"),
str_lit("js"), str_lit("js"),
@@ -542,6 +544,13 @@ gb_global TargetMetrics target_openbsd_amd64 = {
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"), str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
}; };
gb_global TargetMetrics target_haiku_amd64 = {
TargetOs_haiku,
TargetArch_amd64,
8, 8, 8, 16,
str_lit("x86_64-unknown-haiku"),
};
gb_global TargetMetrics target_essence_amd64 = { gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence, TargetOs_essence,
TargetArch_amd64, TargetArch_amd64,
@@ -641,6 +650,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 }, { str_lit("freebsd_amd64"), &target_freebsd_amd64 },
{ str_lit("openbsd_amd64"), &target_openbsd_amd64 }, { str_lit("openbsd_amd64"), &target_openbsd_amd64 },
{ str_lit("haiku_amd64"), &target_haiku_amd64 },
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 }, { str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 }, { str_lit("wasi_wasm32"), &target_wasi_wasm32 },
@@ -872,6 +882,58 @@ gb_internal String internal_odin_root_dir(void) {
return path; return path;
} }
#elif defined(GB_SYSTEM_HAIKU)
#include <FindDirectory.h>
gb_internal String path_to_fullpath(gbAllocator a, String s, bool *ok_);
gb_internal String internal_odin_root_dir(void) {
String path = global_module_path;
isize len, i;
u8 *text;
if (global_module_path_set) {
return global_module_path;
}
auto path_buf = array_make<char>(heap_allocator(), 300);
defer (array_free(&path_buf));
len = 0;
for (;;) {
u32 sz = path_buf.count;
int res = find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, nullptr, &path_buf[0], sz);
if(res == B_OK) {
len = sz;
break;
} else {
array_resize(&path_buf, sz + 1);
}
}
mutex_lock(&string_buffer_mutex);
defer (mutex_unlock(&string_buffer_mutex));
text = gb_alloc_array(permanent_allocator(), u8, len + 1);
gb_memmove(text, &path_buf[0], len);
path = path_to_fullpath(heap_allocator(), make_string(text, len), nullptr);
for (i = path.len-1; i >= 0; i--) {
u8 c = path[i];
if (c == '/' || c == '\\') {
break;
}
path.len--;
}
global_module_path = path;
global_module_path_set = true;
return path;
}
#elif defined(GB_SYSTEM_OSX) #elif defined(GB_SYSTEM_OSX)
#include <mach-o/dyld.h> #include <mach-o/dyld.h>
@@ -888,6 +950,7 @@ gb_internal String internal_odin_root_dir(void) {
} }
auto path_buf = array_make<char>(heap_allocator(), 300); auto path_buf = array_make<char>(heap_allocator(), 300);
defer (array_free(&path_buf));
len = 0; len = 0;
for (;;) { for (;;) {
@@ -920,9 +983,6 @@ gb_internal String internal_odin_root_dir(void) {
global_module_path = path; global_module_path = path;
global_module_path_set = true; global_module_path_set = true;
// array_free(&path_buf);
return path; return path;
} }
#else #else
@@ -1301,6 +1361,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
metrics = &target_freebsd_amd64; metrics = &target_freebsd_amd64;
#elif defined(GB_SYSTEM_OPENBSD) #elif defined(GB_SYSTEM_OPENBSD)
metrics = &target_openbsd_amd64; metrics = &target_openbsd_amd64;
#elif defined(GB_SYSTEM_HAIKU)
metrics = &target_haiku_amd64;
#elif defined(GB_CPU_ARM) #elif defined(GB_CPU_ARM)
metrics = &target_linux_arm64; metrics = &target_linux_arm64;
#else #else
@@ -1405,6 +1467,9 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta
case TargetOs_openbsd: case TargetOs_openbsd:
bc->link_flags = str_lit("-arch x86-64 "); bc->link_flags = str_lit("-arch x86-64 ");
break; break;
case TargetOs_haiku:
bc->link_flags = str_lit("-arch x86-64 ");
break;
} }
} else if (bc->metrics.arch == TargetArch_i386) { } else if (bc->metrics.arch == TargetArch_i386) {
switch (bc->metrics.os) { switch (bc->metrics.os) {
+1
View File
@@ -4928,6 +4928,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case TargetOs_essence: case TargetOs_essence:
case TargetOs_freebsd: case TargetOs_freebsd:
case TargetOs_openbsd: case TargetOs_openbsd:
case TargetOs_haiku:
switch (build_context.metrics.arch) { switch (build_context.metrics.arch) {
case TargetArch_i386: case TargetArch_i386:
case TargetArch_amd64: case TargetArch_amd64:
+1
View File
@@ -1010,6 +1010,7 @@ gb_internal void init_universal(void) {
{"Linux", TargetOs_linux}, {"Linux", TargetOs_linux},
{"Essence", TargetOs_essence}, {"Essence", TargetOs_essence},
{"FreeBSD", TargetOs_freebsd}, {"FreeBSD", TargetOs_freebsd},
{"Haiku", TargetOs_haiku},
{"OpenBSD", TargetOs_openbsd}, {"OpenBSD", TargetOs_openbsd},
{"WASI", TargetOs_wasi}, {"WASI", TargetOs_wasi},
{"JS", TargetOs_js}, {"JS", TargetOs_js},
+47 -2
View File
@@ -83,6 +83,10 @@ extern "C" {
#ifndef GB_SYSTEM_OPENBSD #ifndef GB_SYSTEM_OPENBSD
#define GB_SYSTEM_OPENBSD 1 #define GB_SYSTEM_OPENBSD 1
#endif #endif
#elif defined(__HAIKU__) || defined(__haiku__)
#ifndef GB_SYSTEM_HAIKU
#define GB_SYSTEM_HAIKU 1
#endif
#else #else
#error This UNIX operating system is not supported #error This UNIX operating system is not supported
#endif #endif
@@ -206,7 +210,7 @@ extern "C" {
#endif #endif
#include <stdlib.h> // NOTE(bill): malloc on linux #include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h> #include <sys/mman.h>
#if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__HAIKU__)
#include <sys/sendfile.h> #include <sys/sendfile.h>
#endif #endif
#include <sys/stat.h> #include <sys/stat.h>
@@ -248,6 +252,13 @@ extern "C" {
#define lseek64 lseek #define lseek64 lseek
#endif #endif
#if defined(GB_SYSTEM_HAIKU)
#include <stdio.h>
#include <pthread.h>
#include <kernel/OS.h>
#define lseek64 lseek
#endif
#if defined(GB_SYSTEM_UNIX) #if defined(GB_SYSTEM_UNIX)
#include <semaphore.h> #include <semaphore.h>
#endif #endif
@@ -801,6 +812,13 @@ typedef struct gbAffinity {
isize thread_count; isize thread_count;
isize threads_per_core; isize threads_per_core;
} gbAffinity; } gbAffinity;
#elif defined(GB_SYSTEM_HAIKU)
typedef struct gbAffinity {
b32 is_accurate;
isize core_count;
isize thread_count;
isize threads_per_core;
} gbAffinity;
#else #else
#error TODO(bill): Unknown system #error TODO(bill): Unknown system
#endif #endif
@@ -2984,6 +3002,8 @@ gb_inline u32 gb_thread_current_id(void) {
__asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); __asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
#elif defined(GB_SYSTEM_LINUX) #elif defined(GB_SYSTEM_LINUX)
thread_id = gettid(); thread_id = gettid();
#elif defined(GB_SYSTEM_HAIKU)
thread_id = find_thread(NULL);
#else #else
#error Unsupported architecture for gb_thread_current_id() #error Unsupported architecture for gb_thread_current_id()
#endif #endif
@@ -3184,7 +3204,9 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
//info.affinity_tag = cast(integer_t)index; //info.affinity_tag = cast(integer_t)index;
//result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT); //result = thread_policy_set(thread, THREAD_AFFINITY_POLICY, cast(thread_policy_t)&info, THREAD_AFFINITY_POLICY_COUNT);
#if !defined(GB_SYSTEM_HAIKU)
result = pthread_setaffinity_np(thread, sizeof(cpuset_t), &mn); result = pthread_setaffinity_np(thread, sizeof(cpuset_t), &mn);
#endif
return result == 0; return result == 0;
} }
@@ -3236,6 +3258,29 @@ b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true; return true;
} }
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
#elif defined(GB_SYSTEM_HAIKU)
#include <unistd.h>
void gb_affinity_init(gbAffinity *a) {
a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
a->threads_per_core = 1;
a->is_accurate = a->core_count > 0;
a->core_count = a->is_accurate ? a->core_count : 1;
a->thread_count = a->core_count;
}
void gb_affinity_destroy(gbAffinity *a) {
gb_unused(a);
}
b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
return true;
}
isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) { isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count); GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core; return a->threads_per_core;
@@ -5457,7 +5502,7 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
} }
} }
gb_free(buf); gb_mfree(buf);
close(new_fd); close(new_fd);
close(existing_fd); close(existing_fd);
+2 -2
View File
@@ -474,8 +474,8 @@ gb_internal i32 linker_stage(LinkerData *gen) {
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
} }
} else if (build_context.metrics.os != TargetOs_openbsd) { } else if (build_context.metrics.os != TargetOs_openbsd && build_context.metrics.os != TargetOs_haiku) {
// OpenBSD defaults to PIE executable. do not pass -no-pie for it. // OpenBSD and Haiku default to PIE executable. do not pass -no-pie for it.
link_settings = gb_string_appendc(link_settings, "-no-pie "); link_settings = gb_string_appendc(link_settings, "-no-pie ");
} }
+2 -2
View File
@@ -2564,8 +2564,8 @@ gb_internal bool lb_generate_code(lbGenerator *gen) {
switch (build_context.reloc_mode) { switch (build_context.reloc_mode) {
case RelocMode_Default: case RelocMode_Default:
if (build_context.metrics.os == TargetOs_openbsd) { if (build_context.metrics.os == TargetOs_openbsd || build_context.metrics.os == TargetOs_haiku) {
// Always use PIC for OpenBSD: it defaults to PIE // Always use PIC for OpenBSD and Haiku: they default to PIE
reloc_mode = LLVMRelocPIC; reloc_mode = LLVMRelocPIC;
} }
break; break;
+1 -1
View File
@@ -341,7 +341,7 @@ gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi)
return ReadDirectory_None; return ReadDirectory_None;
} }
#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) #elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD) || defined(GB_SYSTEM_HAIKU)
#include <dirent.h> #include <dirent.h>
+172
View File
@@ -492,6 +492,8 @@ gb_internal u32 thread_current_id(void) {
__asm__("mov %%fs:0x10,%0" : "=r"(thread_id)); __asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
#elif defined(GB_SYSTEM_LINUX) #elif defined(GB_SYSTEM_LINUX)
thread_id = gettid(); thread_id = gettid();
#elif defined(GB_SYSTEM_HAIKU)
thread_id = find_thread(NULL);
#else #else
#error Unsupported architecture for thread_current_id() #error Unsupported architecture for thread_current_id()
#endif #endif
@@ -831,6 +833,176 @@ gb_internal void futex_wait(Futex *f, Footex val) {
WaitOnAddress(f, (void *)&val, sizeof(val), INFINITE); WaitOnAddress(f, (void *)&val, sizeof(val), INFINITE);
} while (f->load() == val); } while (f->load() == val);
} }
#elif defined(GB_SYSTEM_HAIKU)
// Futex implementation taken from https://tavianator.com/2023/futex.html
#include <pthread.h>
#include <atomic>
struct _Spinlock {
std::atomic_flag state;
void init() {
state.clear();
}
void lock() {
while (state.test_and_set(std::memory_order_acquire)) {
#if defined(GB_CPU_X86)
_mm_pause();
#else
(void)0; // spin...
#endif
}
}
void unlock() {
state.clear(std::memory_order_release);
}
};
struct Futex_Waitq;
struct Futex_Waiter {
_Spinlock lock;
pthread_t thread;
Futex *futex;
Futex_Waitq *waitq;
Futex_Waiter *prev, *next;
};
struct Futex_Waitq {
_Spinlock lock;
Futex_Waiter list;
void init() {
auto head = &list;
head->prev = head->next = head;
}
};
// FIXME: This approach may scale badly in the future,
// possible solution - hash map (leads to deadlocks now).
Futex_Waitq g_waitq = {
.lock = ATOMIC_FLAG_INIT,
.list = {
.prev = &g_waitq.list,
.next = &g_waitq.list,
},
};
Futex_Waitq *get_waitq(Futex *f) {
// Future hash map method...
return &g_waitq;
}
void futex_signal(Futex *f) {
auto waitq = get_waitq(f);
waitq->lock.lock();
auto head = &waitq->list;
for (auto waiter = head->next; waiter != head; waiter = waiter->next) {
if (waiter->futex != f) {
continue;
}
waitq->lock.unlock();
pthread_kill(waiter->thread, SIGCONT);
return;
}
waitq->lock.unlock();
}
void futex_broadcast(Futex *f) {
auto waitq = get_waitq(f);
waitq->lock.lock();
auto head = &waitq->list;
for (auto waiter = head->next; waiter != head; waiter = waiter->next) {
if (waiter->futex != f) {
continue;
}
if (waiter->next == head) {
waitq->lock.unlock();
pthread_kill(waiter->thread, SIGCONT);
return;
} else {
pthread_kill(waiter->thread, SIGCONT);
}
}
waitq->lock.unlock();
}
void futex_wait(Futex *f, Footex val) {
Futex_Waiter waiter;
waiter.thread = pthread_self();
waiter.futex = f;
auto waitq = get_waitq(f);
while (waitq->lock.state.test_and_set(std::memory_order_acquire)) {
if (f->load(std::memory_order_relaxed) != val) {
return;
}
#if defined(GB_CPU_X86)
_mm_pause();
#else
(void)0; // spin...
#endif
}
waiter.waitq = waitq;
waiter.lock.init();
waiter.lock.lock();
auto head = &waitq->list;
waiter.prev = head->prev;
waiter.next = head;
waiter.prev->next = &waiter;
waiter.next->prev = &waiter;
waiter.prev->next = &waiter;
waiter.next->prev = &waiter;
sigset_t old_mask, mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCONT);
pthread_sigmask(SIG_BLOCK, &mask, &old_mask);
if (f->load(std::memory_order_relaxed) == val) {
waiter.lock.unlock();
waitq->lock.unlock();
int sig;
sigwait(&mask, &sig);
waitq->lock.lock();
waiter.lock.lock();
while (waitq != waiter.waitq) {
auto req = waiter.waitq;
waiter.lock.unlock();
waitq->lock.unlock();
waitq = req;
waitq->lock.lock();
waiter.lock.lock();
}
}
waiter.prev->next = waiter.next;
waiter.next->prev = waiter.prev;
pthread_sigmask(SIG_SETMASK, &old_mask, NULL);
waiter.lock.unlock();
waitq->lock.unlock();
}
#endif #endif
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
+1
View File
@@ -825,6 +825,7 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) {
case TargetOs_essence: case TargetOs_essence:
case TargetOs_freebsd: case TargetOs_freebsd:
case TargetOs_openbsd: case TargetOs_openbsd:
case TargetOs_haiku:
debug_format = TB_DEBUGFMT_DWARF; debug_format = TB_DEBUGFMT_DWARF;
break; break;
} }
+10 -31
View File
@@ -86,7 +86,6 @@ import "core:fmt"
import "core:mem" import "core:mem"
import "core:strings" import "core:strings"
USE_LINALG :: #config(RAYLIB_USE_LINALG, true)
import "core:math/linalg" import "core:math/linalg"
_ :: linalg _ :: linalg
@@ -213,39 +212,19 @@ BLANK :: Color{ 0, 0, 0, 0 } // Blank (Transparent)
MAGENTA :: Color{ 255, 0, 255, 255 } // Magenta MAGENTA :: Color{ 255, 0, 255, 255 } // Magenta
RAYWHITE :: Color{ 245, 245, 245, 255 } // My own White (raylib logo) RAYWHITE :: Color{ 245, 245, 245, 255 } // My own White (raylib logo)
// Vector2 type
Vector2 :: linalg.Vector2f32
// Vector3 type
Vector3 :: linalg.Vector3f32
// Vector4 type
Vector4 :: linalg.Vector4f32
when USE_LINALG { // Quaternion type
// Vector2 type Quaternion :: linalg.Quaternionf32
Vector2 :: linalg.Vector2f32
// Vector3 type
Vector3 :: linalg.Vector3f32
// Vector4 type
Vector4 :: linalg.Vector4f32
// Quaternion type // Matrix type (OpenGL style 4x4 - right handed, stored column major)
Quaternion :: linalg.Quaternionf32 Matrix :: linalg.Matrix4x4f32
// Matrix type (OpenGL style 4x4 - right handed, column major)
Matrix :: linalg.Matrix4x4f32
} else {
// Vector2 type
Vector2 :: distinct [2]f32
// Vector3 type
Vector3 :: distinct [3]f32
// Vector4 type
Vector4 :: distinct [4]f32
// Quaternion type
Quaternion :: distinct quaternion128
// Matrix, 4x4 components, column major, OpenGL style, right handed
Matrix :: struct {
m0, m4, m8, m12: f32, // Matrix first row (4 components)
m1, m5, m9, m13: f32, // Matrix second row (4 components)
m2, m6, m10, m14: f32, // Matrix third row (4 components)
m3, m7, m11, m15: f32, // Matrix fourth row (4 components)
}
}
// Color, 4 components, R8G8B8A8 (32bit) // Color, 4 components, R8G8B8A8 (32bit)
// //
+23 -23
View File
@@ -85,33 +85,33 @@ Vector2SubtractValue :: proc "c" (v: Vector2, value: f32) -> Vector2 {
return v - value return v - value
} }
// Calculate vector length // Calculate vector length
@(require_results, deprecated="Prefer linalg.length(v)") @(require_results)
Vector2Length :: proc "c" (v: Vector2) -> f32 { Vector2Length :: proc "c" (v: Vector2) -> f32 {
return linalg.length(v) return linalg.length(v)
} }
// Calculate vector square length // Calculate vector square length
@(require_results, deprecated="Prefer linalg.length2(v)") @(require_results)
Vector2LengthSqr :: proc "c" (v: Vector2) -> f32 { Vector2LengthSqr :: proc "c" (v: Vector2) -> f32 {
return linalg.length2(v) return linalg.length2(v)
} }
// Calculate two vectors dot product // Calculate two vectors dot product
@(require_results, deprecated="Prefer linalg.dot(v1, v2)") @(require_results)
Vector2DotProduct :: proc "c" (v1, v2: Vector2) -> f32 { Vector2DotProduct :: proc "c" (v1, v2: Vector2) -> f32 {
return linalg.dot(v1, v2) return linalg.dot(v1, v2)
} }
// Calculate distance between two vectors // Calculate distance between two vectors
@(require_results, deprecated="Prefer linalg.distance(v1, v2)") @(require_results)
Vector2Distance :: proc "c" (v1, v2: Vector2) -> f32 { Vector2Distance :: proc "c" (v1, v2: Vector2) -> f32 {
return linalg.distance(v1, v2) return linalg.distance(v1, v2)
} }
// Calculate square distance between two vectors // Calculate square distance between two vectors
@(require_results, deprecated="Prefer linalg.length2(v2-v1)") @(require_results)
Vector2DistanceSqrt :: proc "c" (v1, v2: Vector2) -> f32 { Vector2DistanceSqrt :: proc "c" (v1, v2: Vector2) -> f32 {
return linalg.length2(v2-v1) return linalg.length2(v2-v1)
} }
// Calculate angle between two vectors // Calculate angle between two vectors
// NOTE: Angle is calculated from origin point (0, 0) // NOTE: Angle is calculated from origin point (0, 0)
@(require_results, deprecated="Prefer linalg.angle_between(v1, v2)") @(require_results)
Vector2Angle :: proc "c" (v1, v2: Vector2) -> f32 { Vector2Angle :: proc "c" (v1, v2: Vector2) -> f32 {
return linalg.angle_between(v1, v2) return linalg.angle_between(v1, v2)
} }
@@ -146,7 +146,7 @@ Vector2Divide :: proc "c" (v1, v2: Vector2) -> Vector2 {
return v1 / v2 return v1 / v2
} }
// Normalize provided vector // Normalize provided vector
@(require_results, deprecated="Prefer linalg.normalize0(v)") @(require_results)
Vector2Normalize :: proc "c" (v: Vector2) -> Vector2 { Vector2Normalize :: proc "c" (v: Vector2) -> Vector2 {
return linalg.normalize0(v) return linalg.normalize0(v)
} }
@@ -270,38 +270,38 @@ Vector3SubtractValue :: proc "c" (v: Vector3, value: f32) -> Vector3 {
return v - value return v - value
} }
// Calculate vector length // Calculate vector length
@(require_results, deprecated="Prefer linalg.length(v)") @(require_results)
Vector3Length :: proc "c" (v: Vector3) -> f32 { Vector3Length :: proc "c" (v: Vector3) -> f32 {
return linalg.length(v) return linalg.length(v)
} }
// Calculate vector square length // Calculate vector square length
@(require_results, deprecated="Prefer linalg.length2(v)") @(require_results)
Vector3LengthSqr :: proc "c" (v: Vector3) -> f32 { Vector3LengthSqr :: proc "c" (v: Vector3) -> f32 {
return linalg.length2(v) return linalg.length2(v)
} }
// Calculate two vectors dot product // Calculate two vectors dot product
@(require_results, deprecated="Prefer linalg.dot(v1, v2)") @(require_results)
Vector3DotProduct :: proc "c" (v1, v2: Vector3) -> f32 { Vector3DotProduct :: proc "c" (v1, v2: Vector3) -> f32 {
return linalg.dot(v1, v2) return linalg.dot(v1, v2)
} }
// Calculate two vectors dot product // Calculate two vectors dot product
@(require_results, deprecated="Prefer linalg.cross(v1, v2)") @(require_results)
Vector3CrossProduct :: proc "c" (v1, v2: Vector3) -> Vector3 { Vector3CrossProduct :: proc "c" (v1, v2: Vector3) -> Vector3 {
return linalg.cross(v1, v2) return linalg.cross(v1, v2)
} }
// Calculate distance between two vectors // Calculate distance between two vectors
@(require_results, deprecated="Prefer linalg.distance(v1, v2)") @(require_results)
Vector3Distance :: proc "c" (v1, v2: Vector3) -> f32 { Vector3Distance :: proc "c" (v1, v2: Vector3) -> f32 {
return linalg.distance(v1, v2) return linalg.distance(v1, v2)
} }
// Calculate square distance between two vectors // Calculate square distance between two vectors
@(require_results, deprecated="Prefer linalg.length2(v2-v1)") @(require_results)
Vector3DistanceSqrt :: proc "c" (v1, v2: Vector3) -> f32 { Vector3DistanceSqrt :: proc "c" (v1, v2: Vector3) -> f32 {
return linalg.length2(v2-v1) return linalg.length2(v2-v1)
} }
// Calculate angle between two vectors // Calculate angle between two vectors
// NOTE: Angle is calculated from origin point (0, 0) // NOTE: Angle is calculated from origin point (0, 0)
@(require_results, deprecated="Prefer linalg.angle_between(v1, v2)") @(require_results)
Vector3Angle :: proc "c" (v1, v2: Vector3) -> f32 { Vector3Angle :: proc "c" (v1, v2: Vector3) -> f32 {
return linalg.angle_between(v1, v2) return linalg.angle_between(v1, v2)
} }
@@ -336,7 +336,7 @@ Vector3Divide :: proc "c" (v1, v2: Vector3) -> Vector3 {
return v1 / v2 return v1 / v2
} }
// Normalize provided vector // Normalize provided vector
@(require_results, deprecated="Prefer linalg.normalize0(v)") @(require_results)
Vector3Normalize :: proc "c" (v: Vector3) -> Vector3 { Vector3Normalize :: proc "c" (v: Vector3) -> Vector3 {
return linalg.normalize0(v) return linalg.normalize0(v)
} }
@@ -364,7 +364,7 @@ Vector3OrthoNormalize :: proc "c" (v1, v2: ^Vector3) {
} }
// Transform a vector by quaternion rotation // Transform a vector by quaternion rotation
@(require_results, deprecated="Prefer linalg.mul(q, v") @(require_results)
Vector3RotateByQuaternion :: proc "c" (v: Vector3, q: Quaternion) -> Vector3 { Vector3RotateByQuaternion :: proc "c" (v: Vector3, q: Quaternion) -> Vector3 {
return linalg.mul(q, v) return linalg.mul(q, v)
} }
@@ -480,12 +480,12 @@ Vector3Equals :: proc "c" (p, q: Vector3) -> bool {
} }
@(require_results, deprecated="Prefer linalg.min(v1, v2)") @(require_results)
Vector3Min :: proc "c" (v1, v2: Vector3) -> Vector3 { Vector3Min :: proc "c" (v1, v2: Vector3) -> Vector3 {
return linalg.min(v1, v2) return linalg.min(v1, v2)
} }
@(require_results, deprecated="Prefer linalg.max(v1, v2)") @(require_results)
Vector3Max :: proc "c" (v1, v2: Vector3) -> Vector3 { Vector3Max :: proc "c" (v1, v2: Vector3) -> Vector3 {
return linalg.max(v1, v2) return linalg.max(v1, v2)
} }
@@ -539,25 +539,25 @@ Vector3Unproject :: proc "c" (source: Vector3, projection: Matrix, view: Matrix)
//---------------------------------------------------------------------------------- //----------------------------------------------------------------------------------
// Compute matrix determinant // Compute matrix determinant
@(require_results, deprecated="Prefer linalg.determinant(mat)") @(require_results)
MatrixDeterminant :: proc "c" (mat: Matrix) -> f32 { MatrixDeterminant :: proc "c" (mat: Matrix) -> f32 {
return linalg.determinant(mat) return linalg.determinant(mat)
} }
// Get the trace of the matrix (sum of the values along the diagonal) // Get the trace of the matrix (sum of the values along the diagonal)
@(require_results, deprecated="Prefer linalg.trace(mat)") @(require_results)
MatrixTrace :: proc "c" (mat: Matrix) -> f32 { MatrixTrace :: proc "c" (mat: Matrix) -> f32 {
return linalg.trace(mat) return linalg.trace(mat)
} }
// Transposes provided matrix // Transposes provided matrix
@(require_results, deprecated="Prefer linalg.transpose(mat)") @(require_results)
MatrixTranspose :: proc "c" (mat: Matrix) -> Matrix { MatrixTranspose :: proc "c" (mat: Matrix) -> Matrix {
return linalg.transpose(mat) return linalg.transpose(mat)
} }
// Invert provided matrix // Invert provided matrix
@(require_results, deprecated="Prefer linalg.inverse(mat)") @(require_results)
MatrixInvert :: proc "c" (mat: Matrix) -> Matrix { MatrixInvert :: proc "c" (mat: Matrix) -> Matrix {
return linalg.inverse(mat) return linalg.inverse(mat)
} }
@@ -704,7 +704,7 @@ QuaternionLength :: proc "c" (q: Quaternion) -> f32 {
return abs(q) return abs(q)
} }
// Normalize provided quaternion // Normalize provided quaternion
@(require_results, deprecated="Prefer linalg.normalize0(q)") @(require_results)
QuaternionNormalize :: proc "c" (q: Quaternion) -> Quaternion { QuaternionNormalize :: proc "c" (q: Quaternion) -> Quaternion {
return linalg.normalize0(q) return linalg.normalize0(q)
} }