mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 15:18:49 +00:00
Merge remote-tracking branch 'offical/master'
This commit is contained in:
@@ -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,4 +1,4 @@
|
|||||||
//+build linux, darwin, freebsd, openbsd
|
//+build linux, darwin, freebsd, openbsd, haiku
|
||||||
//+private
|
//+private
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
;;
|
;;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -1181,28 +1181,18 @@ internal_cmp_digit :: internal_compare_digit
|
|||||||
*/
|
*/
|
||||||
internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: int) {
|
internal_int_compare_magnitude :: #force_inline proc(a, b: ^Int) -> (comparison: int) {
|
||||||
assert_if_nil(a, b)
|
assert_if_nil(a, b)
|
||||||
/*
|
|
||||||
Compare based on used digits.
|
// Compare based on used digits.
|
||||||
*/
|
|
||||||
if a.used != b.used {
|
if a.used != b.used {
|
||||||
if a.used > b.used {
|
return +1 if a.used > b.used else -1
|
||||||
return +1
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Same number of used digits, compare based on their value.
|
||||||
Same number of used digits, compare based on their value.
|
|
||||||
*/
|
|
||||||
#no_bounds_check for n := a.used - 1; n >= 0; n -= 1 {
|
#no_bounds_check for n := a.used - 1; n >= 0; n -= 1 {
|
||||||
if a.digit[n] != b.digit[n] {
|
if a.digit[n] != b.digit[n] {
|
||||||
if a.digit[n] > b.digit[n] {
|
return +1 if a.digit[n] > b.digit[n] else -1
|
||||||
return +1
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
internal_compare_magnitude :: proc { internal_int_compare_magnitude, }
|
internal_compare_magnitude :: proc { internal_int_compare_magnitude, }
|
||||||
|
|||||||
+28
-75
@@ -2865,147 +2865,100 @@ _private_inverse_modulo :: proc(dest, a, b: ^Int, allocator := context.allocator
|
|||||||
x, y, u, v, A, B, C, D := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
x, y, u, v, A, B, C, D := &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}, &Int{}
|
||||||
defer internal_destroy(x, y, u, v, A, B, C, D)
|
defer internal_destroy(x, y, u, v, A, B, C, D)
|
||||||
|
|
||||||
/*
|
// `b` cannot be negative.
|
||||||
`b` cannot be negative.
|
|
||||||
*/
|
|
||||||
if b.sign == .Negative || internal_is_zero(b) {
|
if b.sign == .Negative || internal_is_zero(b) {
|
||||||
return .Invalid_Argument
|
return .Invalid_Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// init temps.
|
||||||
init temps.
|
|
||||||
*/
|
|
||||||
internal_init_multi(x, y, u, v, A, B, C, D) or_return
|
internal_init_multi(x, y, u, v, A, B, C, D) or_return
|
||||||
|
|
||||||
/*
|
// `x` = `a` % `b`, `y` = `b`
|
||||||
`x` = `a` % `b`, `y` = `b`
|
|
||||||
*/
|
|
||||||
internal_mod(x, a, b) or_return
|
internal_mod(x, a, b) or_return
|
||||||
internal_copy(y, b) or_return
|
internal_copy(y, b) or_return
|
||||||
|
|
||||||
/*
|
// 2. [modified] if x,y are both even then return an error!
|
||||||
2. [modified] if x,y are both even then return an error!
|
|
||||||
*/
|
|
||||||
if internal_is_even(x) && internal_is_even(y) {
|
if internal_is_even(x) && internal_is_even(y) {
|
||||||
return .Invalid_Argument
|
return .Invalid_Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// 3. u=x, v=y, A=1, B=0, C=0, D=1
|
||||||
3. u=x, v=y, A=1, B=0, C=0, D=1
|
|
||||||
*/
|
|
||||||
internal_copy(u, x) or_return
|
internal_copy(u, x) or_return
|
||||||
internal_copy(v, y) or_return
|
internal_copy(v, y) or_return
|
||||||
internal_one(A) or_return
|
internal_one(A) or_return
|
||||||
internal_one(D) or_return
|
internal_one(D) or_return
|
||||||
|
|
||||||
for {
|
for {
|
||||||
/*
|
// 4. while `u` is even do:
|
||||||
4. while `u` is even do:
|
|
||||||
*/
|
|
||||||
for internal_is_even(u) {
|
for internal_is_even(u) {
|
||||||
/*
|
// 4.1 `u` = `u` / 2
|
||||||
4.1 `u` = `u` / 2
|
|
||||||
*/
|
|
||||||
internal_int_shr1(u, u) or_return
|
internal_int_shr1(u, u) or_return
|
||||||
|
|
||||||
/*
|
// 4.2 if `A` or `B` is odd then:
|
||||||
4.2 if `A` or `B` is odd then:
|
|
||||||
*/
|
|
||||||
if internal_is_odd(A) || internal_is_odd(B) {
|
if internal_is_odd(A) || internal_is_odd(B) {
|
||||||
/*
|
// `A` = (`A`+`y`) / 2, `B` = (`B`-`x`) / 2
|
||||||
`A` = (`A`+`y`) / 2, `B` = (`B`-`x`) / 2
|
|
||||||
*/
|
|
||||||
internal_add(A, A, y) or_return
|
internal_add(A, A, y) or_return
|
||||||
internal_add(B, B, x) or_return
|
internal_sub(B, B, x) or_return
|
||||||
}
|
}
|
||||||
/*
|
// `A` = `A` / 2, `B` = `B` / 2
|
||||||
`A` = `A` / 2, `B` = `B` / 2
|
|
||||||
*/
|
|
||||||
internal_int_shr1(A, A) or_return
|
internal_int_shr1(A, A) or_return
|
||||||
internal_int_shr1(B, B) or_return
|
internal_int_shr1(B, B) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// 5. while `v` is even do:
|
||||||
5. while `v` is even do:
|
|
||||||
*/
|
|
||||||
for internal_is_even(v) {
|
for internal_is_even(v) {
|
||||||
/*
|
// 5.1 `v` = `v` / 2
|
||||||
5.1 `v` = `v` / 2
|
|
||||||
*/
|
|
||||||
internal_int_shr1(v, v) or_return
|
internal_int_shr1(v, v) or_return
|
||||||
|
|
||||||
/*
|
// 5.2 if `C` or `D` is odd then:
|
||||||
5.2 if `C` or `D` is odd then:
|
|
||||||
*/
|
|
||||||
if internal_is_odd(C) || internal_is_odd(D) {
|
if internal_is_odd(C) || internal_is_odd(D) {
|
||||||
/*
|
// `C` = (`C`+`y`) / 2, `D` = (`D`-`x`) / 2
|
||||||
`C` = (`C`+`y`) / 2, `D` = (`D`-`x`) / 2
|
|
||||||
*/
|
|
||||||
internal_add(C, C, y) or_return
|
internal_add(C, C, y) or_return
|
||||||
internal_add(D, D, x) or_return
|
internal_sub(D, D, x) or_return
|
||||||
}
|
}
|
||||||
/*
|
// `C` = `C` / 2, `D` = `D` / 2
|
||||||
`C` = `C` / 2, `D` = `D` / 2
|
|
||||||
*/
|
|
||||||
internal_int_shr1(C, C) or_return
|
internal_int_shr1(C, C) or_return
|
||||||
internal_int_shr1(D, D) or_return
|
internal_int_shr1(D, D) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// 6. if `u` >= `v` then:
|
||||||
6. if `u` >= `v` then:
|
|
||||||
*/
|
|
||||||
if internal_cmp(u, v) != -1 {
|
if internal_cmp(u, v) != -1 {
|
||||||
/*
|
// `u` = `u` - `v`, `A` = `A` - `C`, `B` = `B` - `D`
|
||||||
`u` = `u` - `v`, `A` = `A` - `C`, `B` = `B` - `D`
|
|
||||||
*/
|
|
||||||
internal_sub(u, u, v) or_return
|
internal_sub(u, u, v) or_return
|
||||||
internal_sub(A, A, C) or_return
|
internal_sub(A, A, C) or_return
|
||||||
internal_sub(B, B, D) or_return
|
internal_sub(B, B, D) or_return
|
||||||
} else {
|
} else {
|
||||||
/* v - v - u, C = C - A, D = D - B */
|
// v - v - u, C = C - A, D = D - B
|
||||||
internal_sub(v, v, u) or_return
|
internal_sub(v, v, u) or_return
|
||||||
internal_sub(C, C, A) or_return
|
internal_sub(C, C, A) or_return
|
||||||
internal_sub(D, D, B) or_return
|
internal_sub(D, D, B) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// If not zero goto step 4
|
||||||
If not zero goto step 4
|
|
||||||
*/
|
|
||||||
if internal_is_zero(u) {
|
if internal_is_zero(u) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Now `a` = `C`, `b` = `D`, `gcd` == `g`*`v`
|
||||||
Now `a` = `C`, `b` = `D`, `gcd` == `g`*`v`
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
// If `v` != `1` then there is no inverse.
|
||||||
If `v` != `1` then there is no inverse.
|
|
||||||
*/
|
|
||||||
if !internal_eq(v, 1) {
|
if !internal_eq(v, 1) {
|
||||||
return .Invalid_Argument
|
return .Invalid_Argument
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// If its too low.
|
||||||
If its too low.
|
for internal_is_negative(C) {
|
||||||
*/
|
|
||||||
if internal_is_negative(C) {
|
|
||||||
internal_add(C, C, b) or_return
|
internal_add(C, C, b) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Too big.
|
||||||
Too big.
|
for internal_cmp_mag(C, b) > -1 {
|
||||||
*/
|
|
||||||
if internal_gte(C, 0) {
|
|
||||||
internal_sub(C, C, b) or_return
|
internal_sub(C, C, b) or_return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// `C` is now the inverse.
|
||||||
`C` is now the inverse.
|
|
||||||
*/
|
|
||||||
swap(dest, C)
|
swap(dest, C)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,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
@@ -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})
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
//+private
|
||||||
|
package sync
|
||||||
|
|
||||||
|
import "core:sys/haiku"
|
||||||
|
|
||||||
|
_current_thread_id :: proc "contextless" () -> int {
|
||||||
|
return int(haiku.find_thread(nil))
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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) ---
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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 ---
|
||||||
|
}
|
||||||
@@ -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,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 {
|
||||||
|
|||||||
@@ -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, ¶ms)
|
res = unix.pthread_attr_getschedparam(&attrs, ¶ms)
|
||||||
assert(res == 0)
|
assert(res == 0)
|
||||||
|
|||||||
@@ -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
@@ -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) {
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+10
-31
@@ -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)
|
||||||
//
|
//
|
||||||
|
|||||||
Vendored
+23
-23
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user