From 61795232f4bab46f4f9fccc542ef7ec1ebcac02f Mon Sep 17 00:00:00 2001 From: Yawning Angel Date: Fri, 25 Oct 2024 11:46:47 +0900 Subject: [PATCH 01/21] src/big_int.cpp: Use square-multiply for exponentiation For utterly unrealistic constant sizes, this still crashes on my system, but it crashes fast due to the OOM killer, and people using rediculously large exponents get what they deserve. --- src/big_int.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/big_int.cpp b/src/big_int.cpp index 83235483c..8e476f090 100644 --- a/src/big_int.cpp +++ b/src/big_int.cpp @@ -62,6 +62,7 @@ gb_internal void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y); gb_internal void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y); gb_internal void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y); gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y); +gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success); gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r); gb_internal void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y); @@ -250,9 +251,7 @@ gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success exp *= 10; exp += v; } - for (u64 x = 0; x < exp; x++) { - big_int_mul_eq(dst, &b); - } + big_int_exp_u64(dst, &b, exp, success); } if (is_negative) { @@ -328,6 +327,18 @@ gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) { big_int_dealloc(&d); } +gb_internal void big_int_exp_u64(BigInt *dst, BigInt const *x, u64 y, bool *success) { + if (y > INT_MAX) { + *success = false; + return; + } + + // Note: The cutoff for square-multiply being faster than the naive + // for loop is when exp > 4, but it probably isn't worth adding + // a fast path. + mp_err err = mp_expt_n(x, int(y), dst); + *success = err == MP_OKAY; +} gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) { mp_mul(x, y, dst); From 8906ffb39cab54e8478b48044db9b3602b802f50 Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Sat, 26 Oct 2024 01:25:12 +0200 Subject: [PATCH 02/21] core/io: correctly escape runes greater than 0xFFFF --- core/io/util.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/io/util.odin b/core/io/util.odin index e65a69fb3..296be7bc0 100644 --- a/core/io/util.odin +++ b/core/io/util.odin @@ -225,7 +225,7 @@ write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, } else { write_byte(w, '\\', &n) or_return write_byte(w, 'U', &n) or_return - for s := 24; s >= 0; s -= 4 { + for s := 28; s >= 0; s -= 4 { write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return } } From 10c2f8dbeb2126419bfdaadb3d6e21dbbeca0633 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 26 Oct 2024 13:50:28 +0200 Subject: [PATCH 03/21] math/rand: add `choice_bit_set` --- base/runtime/core_builtin.odin | 14 +--------- core/math/rand/rand.odin | 49 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 3dad2fdbc..8b7a5004a 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -939,19 +939,7 @@ map_upsert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) @builtin card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { - when size_of(S) == 1 { - return int(intrinsics.count_ones(transmute(u8)s)) - } else when size_of(S) == 2 { - return int(intrinsics.count_ones(transmute(u16)s)) - } else when size_of(S) == 4 { - return int(intrinsics.count_ones(transmute(u32)s)) - } else when size_of(S) == 8 { - return int(intrinsics.count_ones(transmute(u64)s)) - } else when size_of(S) == 16 { - return int(intrinsics.count_ones(transmute(u128)s)) - } else { - #panic("Unhandled card bit_set size") - } + return int(intrinsics.count_ones(transmute(intrinsics.type_bit_set_underlying_type(S))s)) } diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index d5c6dc635..a8f274204 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -687,3 +687,52 @@ choice_enum :: proc($T: typeid, gen := context.random_generator) -> T where intr return T(choice(values)) } } + +/* +Returns a random *set* bit from the provided `bit_set`. + +Inputs: +- set: The `bit_set` to choose a random set bit from + +Returns: +- res: The randomly selected bit, or the zero value if `not_empty` is `false` +- not_empty: Whether the bit_set was not empty and thus `res` is actually a random set bit + +Example: + import "core:math/rand" + import "core:fmt" + + choice_bit_set_example :: proc() { + Flags :: enum { + A, + B = 10, + C, + } + + fmt.println(rand.choice_bit_set(bit_set[Flags]{})) + fmt.println(rand.choice_bit_set(bit_set[Flags]{.B})) + fmt.println(rand.choice_bit_set(bit_set[Flags]{.B, .C})) + fmt.println(rand.choice_bit_set(bit_set[0..<15]{5, 1, 4})) + } + +Possible Output: + A false + B true + C true + 5 true +*/ +@(require_results) +choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, not_empty: bool) { + total_set := card(set) + if total_set == 0 { + return {}, false + } + + core_set := transmute(intrinsics.type_bit_set_underlying_type(T))set + + for target := int_max(total_set, gen); target > 0; target -= 1 { + core_set &= core_set - 1 + } + + return E(intrinsics.count_trailing_zeros(core_set)), true +} From 771d308d643f9e3d59b2451fe18c5bdd845aba1e Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 18:11:46 +0000 Subject: [PATCH 04/21] Fix invalid union access UBSan spotted that |src->Basic.kind| had a value outside the range of |BasicKind| due to it actually being a |Type_Pointer|. Since these are stored in a union there could be cases where the value of |kind| just so happens to be |Basic_string|, in which case the branch would have been taken when it shouldn't have been. To fix this simply check that it's a |Type_Basic| before treating it as a |Basic|. --- src/llvm_backend_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index de7cadaf3..b5f6437a4 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -1647,7 +1647,7 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { lb_emit_store(p, a1, id); return lb_addr_load(p, res); } else if (dst->kind == Type_Basic) { - if (src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) { + if (src->kind == Type_Basic && src->Basic.kind == Basic_string && dst->Basic.kind == Basic_cstring) { String str = lb_get_const_string(m, value); lbValue res = {}; res.type = t; From e67692b0661ab23837079b2ed7340ff85ca88cd6 Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 18:35:14 +0000 Subject: [PATCH 05/21] Avoid member access through nullptr in debug If |result_count| is 0 then |results| will be a nullptr and hence the access |results->Tuple| is undefined behaviour. There's already an early return in the 0 branch so move that to be the first thing so that we can guarantee that it's not a nullptr. Note that technically we take the address of the result so it's not actually dereferencing it, however UBSan doesn't care about that. --- src/llvm_backend_stmt.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index 288e7206a..06d66ac80 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2018,14 +2018,7 @@ gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) { gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return_results) { lb_ensure_abi_function_type(p->module, p); - lbValue res = {}; - - TypeTuple *tuple = &p->type->Proc.results->Tuple; isize return_count = p->type->Proc.result_count; - isize res_count = return_results.count; - - lbFunctionType *ft = lb_get_function_type(p->module, p->type); - bool return_by_pointer = ft->ret.kind == lbArg_Indirect; if (return_count == 0) { // No return values @@ -2038,7 +2031,17 @@ gb_internal void lb_build_return_stmt(lbProcedure *p, Slice const &return LLVMBuildRetVoid(p->builder); } return; - } else if (return_count == 1) { + } + + lbValue res = {}; + + TypeTuple *tuple = &p->type->Proc.results->Tuple; + isize res_count = return_results.count; + + lbFunctionType *ft = lb_get_function_type(p->module, p->type); + bool return_by_pointer = ft->ret.kind == lbArg_Indirect; + + if (return_count == 1) { Entity *e = tuple->variables[0]; if (res_count == 0) { rw_mutex_shared_lock(&p->module->values_mutex); From 4f800a7fdaaa430226108e3bb2bf9fafbda41be8 Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 19:42:25 +0000 Subject: [PATCH 06/21] Avoid undefined arithmetic shifting The result of a left shift on a positive signed integer (Rune) must fit into an unsigned integer otherwise it's undefined behaviour, as is left shifting a negative integer by any amount. This code can only be hit if |x >= 0xf0| and hence a left shift of 31 will always be undefined unless the input is 0 or 1. To avoid hitting this we can instead extend the lowest bit to be the mask if we assume that ints are 2's complement, which we already do elsewhere. This generates identical code in testing on Compiler Explorer and the Odin test suite passes locally with this change. Note that the original code would change to be defined behaviour in C++20, however we are currently build with |-std=c++14| in the build scripts. --- src/unicode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unicode.cpp b/src/unicode.cpp index 665d5b182..ef95cde71 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -109,7 +109,7 @@ gb_internal isize utf8_decode(u8 const *str, isize str_len, Rune *codepoint_out) u8 b1, b2, b3; Utf8AcceptRange accept; if (x >= 0xf0) { - Rune mask = (cast(Rune)x << 31) >> 31; + Rune mask = -cast(Rune)(x & 1); codepoint = (cast(Rune)s0 & (~mask)) | (GB_RUNE_INVALID & mask); width = 1; goto end; From c1496ab6c055974ac401865bdca87a4fc0a76ea3 Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 20:11:42 +0000 Subject: [PATCH 07/21] Fix passing nullptr to args marked as non-null libstdc++'s |memcpy| and |memset| both state that their inputs should never be a nullptr since this matches the C spec. Some compilers act on these hints, so we shouldn't unconditionally call these as it would signal to the compiler that they can't be nullptrs. As an example, the following code will always call |do_something()| when compiled with optimisations since GCC version 4.9: ``` void clear(void *ptr, int size) { memset(ptr, 0, size); } void example(void *ptr, int size) { clear(ptr, size); if (ptr != nullptr) do_something(); } ``` --- src/gb/gb.h | 6 +++++- src/string.cpp | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/gb/gb.h b/src/gb/gb.h index 1fef4b4f5..f74026c7d 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -2541,7 +2541,11 @@ gb_inline void const *gb_pointer_add_const(void const *ptr, isize bytes) { gb_inline void const *gb_pointer_sub_const(void const *ptr, isize bytes) { return cast(void const *)(cast(u8 const *)ptr - bytes); } gb_inline isize gb_pointer_diff (void const *begin, void const *end) { return cast(isize)(cast(u8 const *)end - cast(u8 const *)begin); } -gb_inline void gb_zero_size(void *ptr, isize size) { memset(ptr, 0, size); } +gb_inline void gb_zero_size(void *ptr, isize size) { + if (size != 0) { + memset(ptr, 0, size); + } +} #if defined(_MSC_VER) && !defined(__clang__) diff --git a/src/string.cpp b/src/string.cpp index 3c7d96934..190b69041 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -156,6 +156,7 @@ gb_internal isize string_index_byte(String const &s, u8 x) { gb_internal gb_inline bool str_eq(String const &a, String const &b) { if (a.len != b.len) return false; + if (a.len == 0) return true; return memcmp(a.text, b.text, a.len) == 0; } gb_internal gb_inline bool str_ne(String const &a, String const &b) { return !str_eq(a, b); } From bb308b3ff4a88fa2ab17aef087ec91b46d9a3768 Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 20:23:50 +0000 Subject: [PATCH 08/21] Add missing guards around push/pop pragmas This matches all the other places where we silence Windows warnings. --- src/unicode.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/unicode.cpp b/src/unicode.cpp index ef95cde71..cb9fb12ab 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -1,10 +1,15 @@ -#pragma warning(push) -#pragma warning(disable: 4245) +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(push) + #pragma warning(disable: 4245) +#endif extern "C" { #include "utf8proc/utf8proc.c" } -#pragma warning(pop) + +#if defined(GB_SYSTEM_WINDOWS) + #pragma warning(pop) +#endif gb_internal bool rune_is_letter(Rune r) { From b59647084b11a7f08ad3aa54ae47ceb157f12c46 Mon Sep 17 00:00:00 2001 From: bobsayshilol Date: Sun, 27 Oct 2024 20:26:34 +0000 Subject: [PATCH 09/21] Plug a memory leak The call to |array_make()| always allocates and since this variable was unused it lead to a leak. Simply plug it by removing it. --- src/parser.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/parser.cpp b/src/parser.cpp index 4029d49de..9d8b0d231 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4262,8 +4262,6 @@ gb_internal bool allow_field_separator(AstFile *f) { gb_internal Ast *parse_struct_field_list(AstFile *f, isize *name_count_) { Token start_token = f->curr_token; - auto decls = array_make(ast_allocator(f)); - isize total_name_count = 0; Ast *params = parse_field_list(f, &total_name_count, FieldFlag_Struct, Token_CloseBrace, false, false); From b6599a52b50eebffbe57bc5d3bfa9d86ce394927 Mon Sep 17 00:00:00 2001 From: Patric Dexheimer Date: Sun, 27 Oct 2024 23:27:18 -0300 Subject: [PATCH 10/21] Update process_windows.odin Mistype --- core/os/os2/process_windows.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/os/os2/process_windows.odin b/core/os/os2/process_windows.odin index 201fa28e7..1984cbfdf 100644 --- a/core/os/os2/process_windows.odin +++ b/core/os/os2/process_windows.odin @@ -442,7 +442,7 @@ _process_start :: proc(desc: Process_Desc) -> (process: Process, err: Error) { stderr_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd) } if desc.stdin != nil { - stdin_handle = win32.HANDLE((^File_Impl)(desc.stderr.impl).fd) + stdin_handle = win32.HANDLE((^File_Impl)(desc.stdin.impl).fd) } working_dir_w := (win32_utf8_to_wstring(desc.working_dir, temp_allocator()) or_else nil) if len(desc.working_dir) > 0 else nil From 1cebc025b0e1e0f7872d8a54f177e97a9a07f628 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 20 Oct 2024 18:38:37 +0200 Subject: [PATCH 11/21] sys/posix: impl rest of linux, impl some of Windows --- core/c/libc/README.md | 4 +- core/c/libc/locale.odin | 133 ++++++++++++++ core/os/os_linux.odin | 2 +- core/sys/posix/arpa_inet.odin | 1 + core/sys/posix/dirent.odin | 3 +- core/sys/posix/dlfcn.odin | 3 +- core/sys/posix/errno.odin | 82 ++++++++- core/sys/posix/fcntl.odin | 7 +- core/sys/posix/fnmatch.odin | 3 +- core/sys/posix/glob.odin | 3 +- core/sys/posix/grp.odin | 3 +- core/sys/posix/iconv.odin | 1 + core/sys/posix/langinfo.odin | 1 + core/sys/posix/libgen.odin | 8 + core/sys/posix/limits.odin | 3 +- core/sys/posix/locale.odin | 132 +------------- core/sys/posix/monetary.odin | 1 + core/sys/posix/net_if.odin | 3 +- core/sys/posix/netdb.odin | 3 +- core/sys/posix/netinet_in.odin | 8 +- core/sys/posix/netinet_tcp.odin | 3 +- core/sys/posix/poll.odin | 4 +- core/sys/posix/posix.odin | 3 + core/sys/posix/pthread.odin | 5 +- core/sys/posix/pwd.odin | 15 +- core/sys/posix/sched.odin | 3 +- core/sys/posix/setjmp.odin | 6 +- core/sys/posix/setjmp_libc.odin | 11 ++ core/sys/posix/signal.odin | 111 +----------- core/sys/posix/signal_libc.odin | 145 +++++++++++++++ core/sys/posix/stdio.odin | 173 +----------------- core/sys/posix/stdio_libc.odin | 207 ++++++++++++++++++++++ core/sys/posix/stdlib.odin | 79 +-------- core/sys/posix/stdlib_libc.odin | 101 +++++++++++ core/sys/posix/string.odin | 15 +- core/sys/posix/string_libc.odin | 30 ++++ core/sys/posix/sys_ipc.odin | 3 +- core/sys/posix/sys_mman.odin | 3 +- core/sys/posix/sys_msg.odin | 23 ++- core/sys/posix/sys_resource.odin | 3 +- core/sys/posix/sys_select.odin | 5 +- core/sys/posix/sys_sem.odin | 3 +- core/sys/posix/sys_shm.odin | 23 ++- core/sys/posix/sys_socket.odin | 10 +- core/sys/posix/sys_stat.odin | 187 ++++++++++++------- core/sys/posix/sys_statvfs.odin | 26 ++- core/sys/posix/sys_time.odin | 3 +- core/sys/posix/sys_times.odin | 3 +- core/sys/posix/sys_uio.odin | 3 +- core/sys/posix/sys_un.odin | 3 +- core/sys/posix/sys_utsname.odin | 27 +-- core/sys/posix/sys_wait.odin | 53 +++++- core/sys/posix/termios.odin | 17 +- core/sys/posix/time.odin | 15 +- core/sys/posix/ulimit.odin | 3 +- core/sys/posix/unistd.odin | 112 +----------- core/sys/posix/unistd_libc.odin | 153 ++++++++++++++++ core/sys/posix/utime.odin | 3 +- core/sys/posix/wordexp.odin | 3 +- tests/core/sys/posix/posix.odin | 17 +- tests/core/sys/posix/structs.odin | 2 +- tests/core/sys/posix/structs/structs.c | 2 + tests/core/sys/posix/structs/structs.odin | 6 +- 63 files changed, 1237 insertions(+), 789 deletions(-) create mode 100644 core/c/libc/locale.odin create mode 100644 core/sys/posix/setjmp_libc.odin create mode 100644 core/sys/posix/signal_libc.odin create mode 100644 core/sys/posix/stdio_libc.odin create mode 100644 core/sys/posix/stdlib_libc.odin create mode 100644 core/sys/posix/string_libc.odin create mode 100644 core/sys/posix/unistd_libc.odin diff --git a/core/c/libc/README.md b/core/c/libc/README.md index 95053b963..08e789757 100644 --- a/core/c/libc/README.md +++ b/core/c/libc/README.md @@ -14,7 +14,7 @@ The following is a mostly-complete projection of the C11 standard library as def | `` | Fully projected | | `` | Not applicable, use Odin's operators | | `` | Not projected | -| `` | Not projected | +| `` | Fully projected | | `` | Mostly projected, see [limitations](#Limitations) | | `` | Fully projected | | `` | Fully projected | @@ -70,4 +70,4 @@ with the following copyright. ``` Copyright 2021 Dale Weiler . -``` \ No newline at end of file +``` diff --git a/core/c/libc/locale.odin b/core/c/libc/locale.odin new file mode 100644 index 000000000..371d755c5 --- /dev/null +++ b/core/c/libc/locale.odin @@ -0,0 +1,133 @@ +package libc + +import "core:c" + +when ODIN_OS == .Windows { + foreign import libc "system:libucrt.lib" +} else when ODIN_OS == .Darwin { + foreign import libc "system:System.framework" +} else { + foreign import libc "system:c" +} + +// locale.h - category macros + +foreign libc { + /* + Sets the components of an object with the type lconv with the values appropriate for the + formatting of numeric quantities (monetary and otherwise) according to the rules of the current + locale. + + Returns: a pointer to the lconv structure, might be invalidated by subsequent calls to localeconv() and setlocale() + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localeconv.html ]] + */ + localeconv :: proc() -> ^lconv --- + + /* + Selects the appropriate piece of the global locale, as specified by the category and locale arguments, + and can be used to change or query the entire global locale or portions thereof. + + Returns: the current locale if `locale` is `nil`, the set locale otherwise + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html ]] + */ + @(link_name=LSETLOCALE) + setlocale :: proc(category: Locale_Category, locale: cstring) -> cstring --- +} + +Locale_Category :: enum c.int { + ALL = LC_ALL, + COLLATE = LC_COLLATE, + CTYPE = LC_CTYPE, + MESSAGES = LC_MESSAGES, + MONETARY = LC_MONETARY, + NUMERIC = LC_NUMERIC, + TIME = LC_TIME, +} + +when ODIN_OS == .NetBSD { + @(private) LSETLOCALE :: "__setlocale50" +} else { + @(private) LSETLOCALE :: "setlocale" +} + +when ODIN_OS == .Windows { + lconv :: struct { + decimal_point: cstring, + thousand_sep: cstring, + grouping: cstring, + int_curr_symbol: cstring, + currency_symbol: cstring, + mon_decimal_points: cstring, + mon_thousands_sep: cstring, + mon_grouping: cstring, + positive_sign: cstring, + negative_sign: cstring, + int_frac_digits: c.char, + frac_digits: c.char, + p_cs_precedes: c.char, + p_sep_by_space: c.char, + n_cs_precedes: c.char, + n_sep_by_space: c.char, + p_sign_posn: c.char, + n_sign_posn: c.char, + _W_decimal_point: [^]u16 `fmt:"s,0"`, + _W_thousands_sep: [^]u16 `fmt:"s,0"`, + _W_int_curr_symbol: [^]u16 `fmt:"s,0"`, + _W_currency_symbol: [^]u16 `fmt:"s,0"`, + _W_mon_decimal_point: [^]u16 `fmt:"s,0"`, + _W_mon_thousands_sep: [^]u16 `fmt:"s,0"`, + _W_positive_sign: [^]u16 `fmt:"s,0"`, + _W_negative_sign: [^]u16 `fmt:"s,0"`, + } +} else { + lconv :: struct { + decimal_point: cstring, + thousand_sep: cstring, + grouping: cstring, + int_curr_symbol: cstring, + currency_symbol: cstring, + mon_decimal_points: cstring, + mon_thousands_sep: cstring, + mon_grouping: cstring, + positive_sign: cstring, + negative_sign: cstring, + int_frac_digits: c.char, + frac_digits: c.char, + p_cs_precedes: c.char, + p_sep_by_space: c.char, + n_cs_precedes: c.char, + n_sep_by_space: c.char, + p_sign_posn: c.char, + n_sign_posn: c.char, + _int_p_cs_precedes: c.char, + _int_n_cs_precedes: c.char, + _int_p_sep_by_space: c.char, + _int_n_sep_by_space: c.char, + _int_p_sign_posn: c.char, + _int_n_sign_posn: c.char, + } +} + +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Windows { + + LC_ALL :: 0 + LC_COLLATE :: 1 + LC_CTYPE :: 2 + LC_MESSAGES :: 6 + LC_MONETARY :: 3 + LC_NUMERIC :: 4 + LC_TIME :: 5 + +} else when ODIN_OS == .Linux { + + LC_CTYPE :: 0 + LC_NUMERIC :: 1 + LC_TIME :: 2 + LC_COLLATE :: 3 + LC_MONETARY :: 4 + LC_MESSAGES :: 5 + LC_ALL :: 6 + +} diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index e9039ba20..cfb966275 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -490,7 +490,7 @@ foreign libc { @(link_name="free") _unix_free :: proc(ptr: rawptr) --- @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr --- - @(link_name="execvp") _unix_execvp :: proc(path: cstring, argv: [^]cstring) -> int --- + @(link_name="execvp") _unix_execvp :: proc(path: cstring, argv: [^]cstring) -> c.int --- @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring --- @(link_name="putenv") _unix_putenv :: proc(cstring) -> c.int --- @(link_name="setenv") _unix_setenv :: proc(key: cstring, value: cstring, overwrite: c.int) -> c.int --- diff --git a/core/sys/posix/arpa_inet.odin b/core/sys/posix/arpa_inet.odin index 7e950c4be..d3592dd80 100644 --- a/core/sys/posix/arpa_inet.odin +++ b/core/sys/posix/arpa_inet.odin @@ -1,3 +1,4 @@ +#+build darwin, linux, freebsd, openbsd, netbsd package posix import "core:c" diff --git a/core/sys/posix/dirent.odin b/core/sys/posix/dirent.odin index 48830b030..836800397 100644 --- a/core/sys/posix/dirent.odin +++ b/core/sys/posix/dirent.odin @@ -1,3 +1,4 @@ +#+build darwin, linux, freebsd, openbsd, netbsd package posix import "core:c" @@ -210,6 +211,4 @@ when ODIN_OS == .Darwin { d_name: [256]c.char `fmt:"s,0"`, /* [PSX] entry name */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/dlfcn.odin b/core/sys/posix/dlfcn.odin index 6a467a2bd..e84b29d79 100644 --- a/core/sys/posix/dlfcn.odin +++ b/core/sys/posix/dlfcn.odin @@ -1,3 +1,4 @@ +#+build darwin, linux, freebsd, openbsd, netbsd package posix import "core:c" @@ -120,7 +121,5 @@ when ODIN_OS == .Darwin { _RTLD_LOCAL :: 0 RTLD_LOCAL :: RTLD_Flags{} -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/errno.odin b/core/sys/posix/errno.odin index e670ca889..9bc77f12e 100644 --- a/core/sys/posix/errno.odin +++ b/core/sys/posix/errno.odin @@ -1,3 +1,4 @@ +#+build windows, darwin, linux, freebsd, openbsd, netbsd package posix import "core:c" @@ -456,7 +457,84 @@ when ODIN_OS == .Darwin { EOWNERDEAD :: 130 ENOTRECOVERABLE :: 131 -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Windows { + E2BIG :: 7 + EACCES :: 13 + EADDRINUSE :: 100 + EADDRNOTAVAIL :: 101 + EAFNOSUPPORT :: 102 + EAGAIN :: 11 + EALREADY :: 103 + EBADF :: 9 + EBADMSG :: 104 + EBUSY :: 16 + ECANCELED :: 105 + ECHILD :: 10 + ECONNABORTED :: 106 + ECONNREFUSED :: 107 + ECONNRESET :: 108 + EDEADLK :: 36 + EDESTADDRREQ :: 109 + EDQUOT :: -1 // NOTE: not defined + EEXIST :: 17 + EFAULT :: 14 + EFBIG :: 27 + EHOSTUNREACH :: 110 + EIDRM :: 111 + EINPROGRESS :: 112 + EINTR :: 4 + EINVAL :: 22 + EIO :: 5 + EISCONN :: 113 + EISDIR :: 21 + ELOOP :: 114 + EMFILE :: 24 + EMLINK :: 31 + EMSGSIZE :: 115 + EMULTIHOP :: -1 // NOTE: not defined + ENAMETOOLONG :: 38 + ENETDOWN :: 116 + ENETRESET :: 117 + ENETUNREACH :: 118 + ENFILE :: 23 + ENOBUFS :: 119 + ENODATA :: 120 + ENODEV :: 19 + ENOENT :: 2 + ENOEXEC :: 8 + ENOLCK :: 39 + ENOLINK :: 121 + ENOMEM :: 12 + ENOMSG :: 122 + ENOPROTOOPT :: 123 + ENOSPC :: 28 + ENOSR :: 124 + ENOSTR :: 125 + ENOSYS :: 40 + ENOTCONN :: 126 + ENOTDIR :: 20 + ENOTEMPTY :: 41 + ENOTRECOVERABLE :: 127 + ENOTSOCK :: 128 + ENOTSUP :: 129 + ENOTTY :: 25 + ENXIO :: 6 + EOPNOTSUPP :: 130 + EOVERFLOW :: 132 + EOWNERDEAD :: 133 + EPERM :: 1 + EPIPE :: 32 + EPROTO :: 134 + EPROTONOSUPPORT :: 135 + EPROTOTYPE :: 136 + EROFS :: 30 + ESPIPE :: 29 + ESRCH :: 3 + ESTALE :: -1 // NOTE: not defined + ETIME :: 137 + ETIMEDOUT :: 138 + ETXTBSY :: 139 + EWOULDBLOCK :: 140 + EXDEV :: 18 } diff --git a/core/sys/posix/fcntl.odin b/core/sys/posix/fcntl.odin index 1ccc07c54..d948af600 100644 --- a/core/sys/posix/fcntl.odin +++ b/core/sys/posix/fcntl.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, openbsd, freebsd, netbsd package posix import "core:c" @@ -466,13 +467,11 @@ when ODIN_OS == .Darwin { AT_REMOVEDIR :: 0x200 flock :: struct { + l_type: Lock_Type, /* [PSX] type of lock. */ + l_whence: c.short, /* [PSX] flag (Whence) of starting offset. */ l_start: off_t, /* [PSX] relative offset in bytes. */ l_len: off_t, /* [PSX] size; if 0 then until EOF. */ l_pid: pid_t, /* [PSX] process ID of the process holding the lock. */ - l_type: Lock_Type, /* [PSX] type of lock. */ - l_whence: c.short, /* [PSX] flag (Whence) of starting offset. */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/fnmatch.odin b/core/sys/posix/fnmatch.odin index 1326ce9e4..2d582705c 100644 --- a/core/sys/posix/fnmatch.odin +++ b/core/sys/posix/fnmatch.odin @@ -1,3 +1,4 @@ +#+build darwin, linux, openbsd, freebsd, netbsd package posix import "core:c" @@ -61,6 +62,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS FNM_NOESCAPE :: 0x02 FNM_PERIOD :: 0x04 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/glob.odin b/core/sys/posix/glob.odin index c17f8b2c3..7c8009a59 100644 --- a/core/sys/posix/glob.odin +++ b/core/sys/posix/glob.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -203,6 +204,4 @@ when ODIN_OS == .Darwin { GLOB_ABORTED :: 2 GLOB_NOMATCH :: 3 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/grp.odin b/core/sys/posix/grp.odin index 3a78e2c4c..956ed148b 100644 --- a/core/sys/posix/grp.odin +++ b/core/sys/posix/grp.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -125,6 +126,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS gr_mem: [^]cstring, /* [PSX] group members */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/iconv.odin b/core/sys/posix/iconv.odin index 59248890f..f7447be9e 100644 --- a/core/sys/posix/iconv.odin +++ b/core/sys/posix/iconv.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" diff --git a/core/sys/posix/langinfo.odin b/core/sys/posix/langinfo.odin index 04b46921c..3c001aee0 100644 --- a/core/sys/posix/langinfo.odin +++ b/core/sys/posix/langinfo.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" diff --git a/core/sys/posix/libgen.odin b/core/sys/posix/libgen.odin index 99506797e..69176a557 100644 --- a/core/sys/posix/libgen.odin +++ b/core/sys/posix/libgen.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix when ODIN_OS == .Darwin { @@ -56,6 +57,7 @@ foreign lib { [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/basename.html ]] */ + @(link_name=LBASENAME) basename :: proc(path: cstring) -> cstring --- /* @@ -72,3 +74,9 @@ foreign lib { */ dirname :: proc(path: cstring) -> cstring --- } + +when ODIN_OS == .Linux { + @(private) LBASENAME :: "__xpg_basename" +} else { + @(private) LBASENAME :: "basename" +} diff --git a/core/sys/posix/limits.odin b/core/sys/posix/limits.odin index 58adce0a1..6680986ad 100644 --- a/core/sys/posix/limits.odin +++ b/core/sys/posix/limits.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix // limits.h - implementation-defined constants @@ -549,6 +550,4 @@ when ODIN_OS == .Darwin { NL_TEXTMAX :: 2048 // 255 on glibc, 2048 on musl NZERO :: 20 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/locale.odin b/core/sys/posix/locale.odin index fae692bcb..5b8d7c216 100644 --- a/core/sys/posix/locale.odin +++ b/core/sys/posix/locale.odin @@ -1,131 +1,11 @@ +#+build windows, linux, darwin, netbsd, openbsd, freebsd package posix -import "core:c" +import "core:c/libc" -when ODIN_OS == .Darwin { - foreign import lib "system:System.framework" -} else { - foreign import lib "system:c" -} +localeconv :: libc.localeconv +setlocale :: libc.setlocale -// locale.h - category macros +lconv :: libc.lconv -foreign lib { - /* - Sets the components of an object with the type lconv with the values appropriate for the - formatting of numeric quantities (monetary and otherwise) according to the rules of the current - locale. - - Returns: a pointer to the lconv structure, might be invalidated by subsequent calls to localeconv() and setlocale() - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/localeconv.html ]] - */ - localeconv :: proc() -> ^lconv --- - - /* - Selects the appropriate piece of the global locale, as specified by the category and locale arguments, - and can be used to change or query the entire global locale or portions thereof. - - Returns: the current locale if `locale` is `nil`, the set locale otherwise - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/setlocale.html ]] - */ - @(link_name=LSETLOCALE) - setlocale :: proc(category: Locale_Category, locale: cstring) -> cstring --- -} - -Locale_Category :: enum c.int { - ALL = LC_ALL, - COLLATE = LC_COLLATE, - CTYPE = LC_CTYPE, - MESSAGES = LC_MESSAGES, - MONETARY = LC_MONETARY, - NUMERIC = LC_NUMERIC, - TIME = LC_TIME, -} - -when ODIN_OS == .NetBSD { - @(private) LSETLOCALE :: "__setlocale50" -} else { - @(private) LSETLOCALE :: "setlocale" -} - -when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { - - // NOTE: All of these fields are standard ([PSX]). - lconv :: struct { - decimal_point: cstring, - thousand_sep: cstring, - grouping: cstring, - int_curr_symbol: cstring, - currency_symbol: cstring, - mon_decimal_points: cstring, - mon_thousands_sep: cstring, - mon_grouping: cstring, - positive_sign: cstring, - negative_sign: cstring, - int_frac_digits: c.char, - frac_digits: c.char, - p_cs_precedes: c.char, - p_sep_by_space: c.char, - n_cs_precedes: c.char, - n_sep_by_space: c.char, - p_sign_posn: c.char, - n_sign_posn: c.char, - int_p_cs_precedes: c.char, - int_n_cs_precedes: c.char, - int_p_sep_by_space: c.char, - int_n_sep_by_space: c.char, - int_p_sign_posn: c.char, - int_n_sign_posn: c.char, - } - - LC_ALL :: 0 - LC_COLLATE :: 1 - LC_CTYPE :: 2 - LC_MESSAGES :: 6 - LC_MONETARY :: 3 - LC_NUMERIC :: 4 - LC_TIME :: 5 - -} else when ODIN_OS == .Linux { - - // NOTE: All of these fields are standard ([PSX]). - lconv :: struct { - decimal_point: cstring, - thousand_sep: cstring, - grouping: cstring, - int_curr_symbol: cstring, - currency_symbol: cstring, - mon_decimal_points: cstring, - mon_thousands_sep: cstring, - mon_grouping: cstring, - positive_sign: cstring, - negative_sign: cstring, - int_frac_digits: c.char, - frac_digits: c.char, - p_cs_precedes: c.char, - p_sep_by_space: c.char, - n_cs_precedes: c.char, - n_sep_by_space: c.char, - p_sign_posn: c.char, - n_sign_posn: c.char, - int_p_cs_precedes: c.char, - int_n_cs_precedes: c.char, - int_p_sep_by_space: c.char, - int_n_sep_by_space: c.char, - int_p_sign_posn: c.char, - int_n_sign_posn: c.char, - } - - LC_CTYPE :: 0 - LC_NUMERIC :: 1 - LC_TIME :: 2 - LC_COLLATE :: 3 - LC_MONETARY :: 4 - LC_MESSAGES :: 5 - LC_ALL :: 6 - -} else { - #panic("posix is unimplemented for the current target") -} +Locale_Category :: libc.Locale_Category diff --git a/core/sys/posix/monetary.odin b/core/sys/posix/monetary.odin index b4f0c31ee..ee342e211 100644 --- a/core/sys/posix/monetary.odin +++ b/core/sys/posix/monetary.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" diff --git a/core/sys/posix/net_if.odin b/core/sys/posix/net_if.odin index 75c1a863e..774d11b72 100644 --- a/core/sys/posix/net_if.odin +++ b/core/sys/posix/net_if.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -55,6 +56,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS IF_NAMESIZE :: 16 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/netdb.odin b/core/sys/posix/netdb.odin index f31de2c2b..79e13a140 100644 --- a/core/sys/posix/netdb.odin +++ b/core/sys/posix/netdb.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -472,6 +473,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS EAI_OVERFLOW :: 14 } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/netinet_in.odin b/core/sys/posix/netinet_in.odin index 22bfde9bc..a2cf904ce 100644 --- a/core/sys/posix/netinet_in.odin +++ b/core/sys/posix/netinet_in.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -61,6 +62,11 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS sin6_scope_id: c.uint32_t, /* [PSX] set of interfaces for a scope */ } + ipv6_mreq :: struct { + ipv6mr_multiaddr: in6_addr, /* [PSX] IPv6 multicast address */ + ipv6mr_interface: c.uint, /* [PSX] interface index */ + } + IPV6_MULTICAST_IF :: 17 IPV6_UNICAST_HOPS :: 16 IPV6_MULTICAST_HOPS :: 18 @@ -223,6 +229,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS ) } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/netinet_tcp.odin b/core/sys/posix/netinet_tcp.odin index 284351732..b1da12f5e 100644 --- a/core/sys/posix/netinet_tcp.odin +++ b/core/sys/posix/netinet_tcp.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix // netinet/tcp.h - definitions for the Internet Transmission Control Protocol (TCP) @@ -6,6 +7,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS TCP_NODELAY :: 0x01 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/poll.odin b/core/sys/posix/poll.odin index 9e38afe12..9c3b8b081 100644 --- a/core/sys/posix/poll.odin +++ b/core/sys/posix/poll.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "base:intrinsics" @@ -92,7 +93,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS POLLHUP :: 0x0010 POLLNVAL :: 0x0020 -} else { - #panic("posix is unimplemented for the current target") } - diff --git a/core/sys/posix/posix.odin b/core/sys/posix/posix.odin index 44486e424..d56217407 100644 --- a/core/sys/posix/posix.odin +++ b/core/sys/posix/posix.odin @@ -11,6 +11,9 @@ The struct fields that are cross-platform are documented with `[PSX]`. Accessing these fields on one target should be the same on others. Other fields are implementation specific. +The parts of POSIX that Windows implements are also supported here, but +other symbols are undefined on Windows targets. + Most macros have been reimplemented in Odin with inlined functions. Unimplemented headers: diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 76acb1a3d..6e894117a 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -1,10 +1,11 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" -} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD { +} else when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .Linux { foreign import lib "system:pthread" } else { foreign import lib "system:c" @@ -557,6 +558,4 @@ when ODIN_OS == .Darwin { __reserved3: c.int, } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/pwd.odin b/core/sys/posix/pwd.odin index 546d58309..33cbcd7c5 100644 --- a/core/sys/posix/pwd.odin +++ b/core/sys/posix/pwd.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -163,6 +164,16 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { pw_fields: c.int, } -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + passwd :: struct { + pw_name: cstring, /* [PSX] user name */ + pw_passwd: cstring, /* encrypted password */ + pw_uid: uid_t, /* [PSX] user uid */ + pw_gid: gid_t, /* [PSX] user gid */ + pw_gecos: cstring, /* Real name. */ + pw_dir: cstring, /* Home directory. */ + pw_shell: cstring, /* Shell program. */ + } + } diff --git a/core/sys/posix/sched.odin b/core/sys/posix/sched.odin index 3923257aa..e91178b09 100644 --- a/core/sys/posix/sched.odin +++ b/core/sys/posix/sched.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -100,6 +101,4 @@ when ODIN_OS == .Darwin { SCHED_FIFO :: 1 SCHED_RR :: 2 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/setjmp.odin b/core/sys/posix/setjmp.odin index cb1dad184..926dbd3ad 100644 --- a/core/sys/posix/setjmp.odin +++ b/core/sys/posix/setjmp.odin @@ -1,7 +1,7 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" -import "core:c/libc" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" @@ -43,12 +43,8 @@ foreign lib { sigsetjmp :: proc(env: ^sigjmp_buf, savemask: b32) -> c.int --- } -jmp_buf :: libc.jmp_buf sigjmp_buf :: distinct jmp_buf -longjmp :: libc.longjmp -setjmp :: libc.setjmp - when ODIN_OS == .NetBSD { @(private) LSIGSETJMP :: "__sigsetjmp14" @(private) LSIGLONGJMP :: "__siglongjmp14" diff --git a/core/sys/posix/setjmp_libc.odin b/core/sys/posix/setjmp_libc.odin new file mode 100644 index 000000000..a69dff09f --- /dev/null +++ b/core/sys/posix/setjmp_libc.odin @@ -0,0 +1,11 @@ +#+build windows, linux, darwin, netbsd, openbsd, freebsd +package posix + +import "core:c/libc" + +// setjmp.h - stack environment declarations + +jmp_buf :: libc.jmp_buf + +longjmp :: libc.longjmp +setjmp :: libc.setjmp diff --git a/core/sys/posix/signal.odin b/core/sys/posix/signal.odin index 1e3f05104..4ba4e9943 100644 --- a/core/sys/posix/signal.odin +++ b/core/sys/posix/signal.odin @@ -1,9 +1,9 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "base:intrinsics" import "core:c" -import "core:c/libc" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" @@ -14,31 +14,6 @@ when ODIN_OS == .Darwin { // signal.h - signals foreign lib { - // LIBC: - - /* - Set a signal handler. - - func can either be: - - `auto_cast posix.SIG_DFL` setting the default handler for that specific signal - - `auto_cast posix.SIG_IGN` causing the specific signal to be ignored - - a custom signal handler - - Returns: SIG_ERR (setting errno), the last value of func on success - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html ]] - */ - signal :: proc(sig: Signal, func: proc "c" (Signal)) -> proc "c" (Signal) --- - - /* - Raises a signal, calling its handler and then returning. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html ]] - */ - raise :: proc(sig: Signal) -> result --- - - // POSIX: - /* Raise a signal to the process/group specified by pid. @@ -227,72 +202,6 @@ sigval :: struct #raw_union { sigval_ptr: rawptr, /* [PSX] pointer signal value */ } -Signal :: enum c.int { - NONE, - - // LIBC: - - // Process abort signal. - SIGABRT = SIGABRT, - // Erronous arithemtic operation. - SIGFPE = SIGFPE, - // Illegal instruction. - SIGILL = SIGILL, - // Terminal interrupt signal. - SIGINT = SIGINT, - // Invalid memory reference. - SIGSEGV = SIGSEGV, - // Termination signal. - SIGTERM = SIGTERM, - - // POSIX: - - // Process abort signal. - SIGALRM = SIGALRM, - // Access to an undefined portion of a memory object. - SIGBUS = SIGBUS, - // Child process terminated, stopped, or continued. - SIGCHLD = SIGCHLD, - // Continue execution, if stopped. - SIGCONT = SIGCONT, - // Hangup. - SIGHUP = SIGHUP, - // Kill (cannot be caught or ignored). - SIGKILL = SIGKILL, - // Write on a pipe with no one to read it. - SIGPIPE = SIGPIPE, - // Terminal quit signal. - SIGQUIT = SIGQUIT, - // Stop executing (cannot be caught or ignored). - SIGSTOP = SIGSTOP, - // Terminal stop process. - SIGTSTP = SIGTSTP, - // Background process attempting read. - SIGTTIN = SIGTTIN, - // Background process attempting write. - SIGTTOU = SIGTTOU, - // User-defined signal 1. - SIGUSR1 = SIGUSR1, - // User-defined signal 2. - SIGUSR2 = SIGUSR2, - // Pollable event. - SIGPOLL = SIGPOLL, - // Profiling timer expired. - SIGPROF = SIGPROF, - // Bad system call. - SIGSYS = SIGSYS, - // Trace/breakpoint trap. - SIGTRAP = SIGTRAP, - // High bandwidth data is available at a socket. - SIGURG = SIGURG, - // Virtual timer expired. - SIGVTALRM = SIGVTALRM, - // CPU time limit exceeded. - SIGXCPU = SIGXCPU, - // File size limit exceeded. - SIGXFSZ = SIGXFSZ, -} - ILL_Code :: enum c.int { // Illegal opcode. ILLOPC = ILL_ILLOPC, @@ -434,20 +343,6 @@ Sig :: enum c.int { SETMASK = SIG_SETMASK, } -// Request for default signal handling. -SIG_DFL :: libc.SIG_DFL -// Return value from signal() in case of error. -SIG_ERR :: libc.SIG_ERR -// Request that signal be ignored. -SIG_IGN :: libc.SIG_IGN - -SIGABRT :: libc.SIGABRT -SIGFPE :: libc.SIGFPE -SIGILL :: libc.SIGILL -SIGINT :: libc.SIGINT -SIGSEGV :: libc.SIGSEGV -SIGTERM :: libc.SIGTERM - when ODIN_OS == .NetBSD { @(private) LSIGPROCMASK :: "__sigprocmask14" @(private) LSIGACTION :: "__sigaction_siginfo" @@ -1118,7 +1013,7 @@ when ODIN_OS == .Darwin { uid_t :: distinct c.uint32_t sigset_t :: struct { - [1024/(8 * size_of(c.ulong))]val, + __val: [1024/(8 * size_of(c.ulong))]c.ulong, } SIGHUP :: 1 @@ -1285,6 +1180,4 @@ when ODIN_OS == .Darwin { SI_TIMER :: -2 SI_MESGQ :: -3 SI_ASYNCIO :: -4 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/signal_libc.odin b/core/sys/posix/signal_libc.odin new file mode 100644 index 000000000..aef22da29 --- /dev/null +++ b/core/sys/posix/signal_libc.odin @@ -0,0 +1,145 @@ +#+build linux, windows, darwin, netbsd, openbsd, freebsd +package posix + +import "base:intrinsics" + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Windows { + foreign import lib "system:libucrt.lib" +} else when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// signal.h - signals + +foreign lib { + /* + Set a signal handler. + + func can either be: + - `auto_cast posix.SIG_DFL` setting the default handler for that specific signal + - `auto_cast posix.SIG_IGN` causing the specific signal to be ignored + - a custom signal handler + + Returns: SIG_ERR (setting errno), the last value of func on success + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html ]] + */ + signal :: proc(sig: Signal, func: proc "c" (Signal)) -> proc "c" (Signal) --- + + /* + Raises a signal, calling its handler and then returning. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/raise.html ]] + */ + raise :: proc(sig: Signal) -> result --- +} + +Signal :: enum c.int { + NONE, + + // LIBC: + + // Process abort signal. + SIGABRT = SIGABRT, + // Erronous arithemtic operation. + SIGFPE = SIGFPE, + // Illegal instruction. + SIGILL = SIGILL, + // Terminal interrupt signal. + SIGINT = SIGINT, + // Invalid memory reference. + SIGSEGV = SIGSEGV, + // Termination signal. + SIGTERM = SIGTERM, + + // POSIX: + + // Process abort signal. + SIGALRM = SIGALRM, + // Access to an undefined portion of a memory object. + SIGBUS = SIGBUS, + // Child process terminated, stopped, or continued. + SIGCHLD = SIGCHLD, + // Continue execution, if stopped. + SIGCONT = SIGCONT, + // Hangup. + SIGHUP = SIGHUP, + // Kill (cannot be caught or ignored). + SIGKILL = SIGKILL, + // Write on a pipe with no one to read it. + SIGPIPE = SIGPIPE, + // Terminal quit signal. + SIGQUIT = SIGQUIT, + // Stop executing (cannot be caught or ignored). + SIGSTOP = SIGSTOP, + // Terminal stop process. + SIGTSTP = SIGTSTP, + // Background process attempting read. + SIGTTIN = SIGTTIN, + // Background process attempting write. + SIGTTOU = SIGTTOU, + // User-defined signal 1. + SIGUSR1 = SIGUSR1, + // User-defined signal 2. + SIGUSR2 = SIGUSR2, + // Pollable event. + SIGPOLL = SIGPOLL, + // Profiling timer expired. + SIGPROF = SIGPROF, + // Bad system call. + SIGSYS = SIGSYS, + // Trace/breakpoint trap. + SIGTRAP = SIGTRAP, + // High bandwidth data is available at a socket. + SIGURG = SIGURG, + // Virtual timer expired. + SIGVTALRM = SIGVTALRM, + // CPU time limit exceeded. + SIGXCPU = SIGXCPU, + // File size limit exceeded. + SIGXFSZ = SIGXFSZ, +} + +// Request for default signal handling. +SIG_DFL :: libc.SIG_DFL +// Return value from signal() in case of error. +SIG_ERR :: libc.SIG_ERR +// Request that signal be ignored. +SIG_IGN :: libc.SIG_IGN + +SIGABRT :: libc.SIGABRT +SIGFPE :: libc.SIGFPE +SIGILL :: libc.SIGILL +SIGINT :: libc.SIGINT +SIGSEGV :: libc.SIGSEGV +SIGTERM :: libc.SIGTERM + +when ODIN_OS == .Windows { + SIGALRM :: -1 + SIGBUS :: -1 + SIGCHLD :: -1 + SIGCONT :: -1 + SIGHUP :: -1 + SIGKILL :: -1 + SIGPIPE :: -1 + SIGQUIT :: -1 + SIGSTOP :: -1 + SIGTSTP :: -1 + SIGTTIN :: -1 + SIGTTOU :: -1 + SIGUSR1 :: -1 + SIGUSR2 :: -1 + SIGPOLL :: -1 + SIGPROF :: -1 + SIGSYS :: -1 + SIGTRAP :: -1 + SIGURG :: -1 + SIGVTALRM :: -1 + SIGXCPU :: -1 + SIGXFSZ :: -1 +} diff --git a/core/sys/posix/stdio.odin b/core/sys/posix/stdio.odin index de716f8d7..24464dfd8 100644 --- a/core/sys/posix/stdio.odin +++ b/core/sys/posix/stdio.odin @@ -1,7 +1,7 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" -import "core:c/libc" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" @@ -32,16 +32,6 @@ foreign lib { */ dprintf :: proc(fildse: FD, format: cstring, #c_vararg args: ..any) -> c.int --- - /* - Equivalent to fprintf but output is written to s, it is the user's responsibility to - ensure there is enough space. - - Return: number of bytes written, negative (setting errno) on failure - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]] - */ - sprintf :: proc(s: [^]byte, format: cstring, #c_vararg args: ..any) -> c.int --- - /* Associate a stream with a file descriptor. @@ -115,34 +105,6 @@ foreign lib { */ open_memstream :: proc(bufp: ^[^]byte, sizep: ^c.size_t) -> ^FILE --- - /* - Equivalent to getc but unaffected by locks. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] - */ - getc_unlocked :: proc(stream: ^FILE) -> c.int --- - - /* - Equivalent to getchar but unaffected by locks. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] - */ - getchar_unlocked :: proc() -> c.int --- - - /* - Equivalent to putc but unaffected by locks. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] - */ - putc_unlocked :: proc(ch: c.int, stream: ^FILE) -> c.int --- - - /* - Equivalent to putchar but unaffected by locks. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] - */ - putchar_unlocked :: proc(ch: c.int) -> c.int --- - /* Read a delimited record from the stream. @@ -181,60 +143,6 @@ foreign lib { */ getline :: proc(lineptr: ^cstring, n: ^c.size_t, stream: ^FILE) -> c.ssize_t --- - /* - Get a string from the stdin stream. - - It is up to the user to make sure s is big enough. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gets.html ]] - */ - gets :: proc(s: [^]byte) -> cstring --- - - /* - Create a name for a temporary file. - - Returns: an allocated cstring that needs to be freed, nil on failure - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html ]] - */ - tempnam :: proc(dir: cstring, pfx: cstring) -> cstring --- - - /* - Executes the command specified, creating a pipe and returning a pointer to a stream that can - read or write from/to the pipe. - - Returns: nil (setting errno) on failure or a pointer to the stream - - Example: - fp := posix.popen("ls *", "r") - if fp == nil { - /* Handle error */ - } - - path: [1024]byte - for posix.fgets(raw_data(path[:]), len(path), fp) != nil { - posix.printf("%s", &path) - } - - status := posix.pclose(fp) - if status == -1 { - /* Error reported by pclose() */ - } else { - /* Use functions described under wait() to inspect `status` in order - to determine success/failure of the command executed by popen() */ - } - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ]] - */ - popen :: proc(command: cstring, mode: cstring) -> ^FILE --- - - /* - Closes a pipe stream to or from a process. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pclose.html ]] - */ - pclose :: proc(stream: ^FILE) -> c.int --- - /* Equivalent to rename but relative directories are resolved from their respective fds. @@ -243,76 +151,6 @@ foreign lib { renameat :: proc(oldfd: FD, old: cstring, newfd: FD, new: cstring) -> result --- } -clearerr :: libc.clearerr -fclose :: libc.fclose -feof :: libc.feof -ferror :: libc.ferror -fflush :: libc.fflush -fgetc :: libc.fgetc -fgetpos :: libc.fgetpos -fgets :: libc.fgets -fopen :: libc.fopen -fprintf :: libc.fprintf -fputc :: libc.fputc -fread :: libc.fread -freopen :: libc.freopen -fscanf :: libc.fscanf -fseek :: libc.fseek -fsetpos :: libc.fsetpos -ftell :: libc.ftell -fwrite :: libc.fwrite -getc :: libc.getc -getchar :: libc.getchar -perror :: libc.perror -printf :: libc.printf -putc :: libc.puts -putchar :: libc.putchar -puts :: libc.puts -remove :: libc.remove -rename :: libc.rename -rewind :: libc.rewind -scanf :: libc.scanf -setbuf :: libc.setbuf -setvbuf :: libc.setvbuf -snprintf :: libc.snprintf -sscanf :: libc.sscanf -tmpfile :: libc.tmpfile -tmpnam :: libc.tmpnam -vfprintf :: libc.vfprintf -vfscanf :: libc.vfscanf -vprintf :: libc.vprintf -vscanf :: libc.vscanf -vsnprintf :: libc.vsnprintf -vsprintf :: libc.vsprintf -vsscanf :: libc.vsscanf -ungetc :: libc.ungetc - -to_stream :: libc.to_stream - -Whence :: libc.Whence -FILE :: libc.FILE -fpos_t :: libc.fpos_t - -BUFSIZ :: libc.BUFSIZ - -_IOFBF :: libc._IOFBF -_IOLBF :: libc._IOLBF -_IONBF :: libc._IONBF - -SEEK_CUR :: libc.SEEK_CUR -SEEK_END :: libc.SEEK_END -SEEK_SET :: libc.SEEK_SET - -FILENAME_MAX :: libc.FILENAME_MAX -FOPEN_MAX :: libc.FOPEN_MAX -TMP_MAX :: libc.TMP_MAX - -EOF :: libc.EOF - -stderr := libc.stderr -stdin := libc.stdin -stdout := libc.stdout - when ODIN_OS == .Darwin { L_ctermid :: 1024 @@ -327,6 +165,11 @@ when ODIN_OS == .Darwin { P_tmpdir :: "/tmp/" -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + L_ctermid :: 20 // 20 on musl, 9 on glibc + L_tmpnam :: 20 + + P_tmpdir :: "/tmp/" + } diff --git a/core/sys/posix/stdio_libc.odin b/core/sys/posix/stdio_libc.odin new file mode 100644 index 000000000..fbd949b2c --- /dev/null +++ b/core/sys/posix/stdio_libc.odin @@ -0,0 +1,207 @@ +#+build linux, windows, linux, darwin, netbsd, openbsd, freebsd +package posix + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Windows { + foreign import lib { + "system:libucrt.lib", + "system:legacy_stdio_definitions.lib", + } +} else when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// stdio.h - standard buffered input/output + +when ODIN_OS == .Windows { + @(private) LGETC_UNLOCKED :: "_getc_nolock" + @(private) LGETCHAR_UNLOCKED :: "_getchar_nolock" + @(private) LPUTC_UNLOCKED :: "_putc_nolock" + @(private) LPUTCHAR_UNLOCKED :: "_putchar_nolock" + @(private) LTEMPNAM :: "_tempnam" + @(private) LPOPEN :: "_popen" + @(private) LPCLOSE :: "_pclose" +} else { + @(private) LGETC_UNLOCKED :: "getc_unlocked" + @(private) LGETCHAR_UNLOCKED :: "getchar_unlocked" + @(private) LPUTC_UNLOCKED :: "putc_unlocked" + @(private) LPUTCHAR_UNLOCKED :: "putchar_unlocked" + @(private) LTEMPNAM :: "tempnam" + @(private) LPOPEN :: "popen" + @(private) LPCLOSE :: "pclose" +} + +foreign lib { + /* + Equivalent to fprintf but output is written to s, it is the user's responsibility to + ensure there is enough space. + + Return: number of bytes written, negative (setting errno) on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html ]] + */ + sprintf :: proc(s: [^]byte, format: cstring, #c_vararg args: ..any) -> c.int --- + + /* + Equivalent to getc but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + @(link_name=LGETC_UNLOCKED) + getc_unlocked :: proc(stream: ^FILE) -> c.int --- + + /* + Equivalent to getchar but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + @(link_name=LGETCHAR_UNLOCKED) + getchar_unlocked :: proc() -> c.int --- + + /* + Equivalent to putc but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + @(link_name=LPUTC_UNLOCKED) + putc_unlocked :: proc(ch: c.int, stream: ^FILE) -> c.int --- + + /* + Equivalent to putchar but unaffected by locks. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getc_unlocked.html ]] + */ + @(link_name=LPUTCHAR_UNLOCKED) + putchar_unlocked :: proc(ch: c.int) -> c.int --- + + /* + Get a string from the stdin stream. + + It is up to the user to make sure s is big enough. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/gets.html ]] + */ + gets :: proc(s: [^]byte) -> cstring --- + + /* + Create a name for a temporary file. + + Returns: an allocated cstring that needs to be freed, nil on failure + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/tempnam.html ]] + */ + @(link_name=LTEMPNAM) + tempnam :: proc(dir: cstring, pfx: cstring) -> cstring --- + + /* + Executes the command specified, creating a pipe and returning a pointer to a stream that can + read or write from/to the pipe. + + Returns: nil (setting errno) on failure or a pointer to the stream + + Example: + fp := posix.popen("ls *", "r") + if fp == nil { + /* Handle error */ + } + + path: [1024]byte + for posix.fgets(raw_data(path[:]), len(path), fp) != nil { + posix.printf("%s", &path) + } + + status := posix.pclose(fp) + if status == -1 { + /* Error reported by pclose() */ + } else { + /* Use functions described under wait() to inspect `status` in order + to determine success/failure of the command executed by popen() */ + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/popen.html ]] + */ + @(link_name=LPOPEN) + popen :: proc(command: cstring, mode: cstring) -> ^FILE --- + + /* + Closes a pipe stream to or from a process. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/pclose.html ]] + */ + @(link_name=LPCLOSE) + pclose :: proc(stream: ^FILE) -> c.int --- +} + +clearerr :: libc.clearerr +fclose :: libc.fclose +feof :: libc.feof +ferror :: libc.ferror +fflush :: libc.fflush +fgetc :: libc.fgetc +fgetpos :: libc.fgetpos +fgets :: libc.fgets +fopen :: libc.fopen +fprintf :: libc.fprintf +fputc :: libc.fputc +fread :: libc.fread +freopen :: libc.freopen +fscanf :: libc.fscanf +fseek :: libc.fseek +fsetpos :: libc.fsetpos +ftell :: libc.ftell +fwrite :: libc.fwrite +getc :: libc.getc +getchar :: libc.getchar +perror :: libc.perror +printf :: libc.printf +putc :: libc.puts +putchar :: libc.putchar +puts :: libc.puts +remove :: libc.remove +rename :: libc.rename +rewind :: libc.rewind +scanf :: libc.scanf +setbuf :: libc.setbuf +setvbuf :: libc.setvbuf +snprintf :: libc.snprintf +sscanf :: libc.sscanf +tmpfile :: libc.tmpfile +tmpnam :: libc.tmpnam +vfprintf :: libc.vfprintf +vfscanf :: libc.vfscanf +vprintf :: libc.vprintf +vscanf :: libc.vscanf +vsnprintf :: libc.vsnprintf +vsprintf :: libc.vsprintf +vsscanf :: libc.vsscanf +ungetc :: libc.ungetc + +to_stream :: libc.to_stream + +Whence :: libc.Whence +FILE :: libc.FILE +fpos_t :: libc.fpos_t + +BUFSIZ :: libc.BUFSIZ + +_IOFBF :: libc._IOFBF +_IOLBF :: libc._IOLBF +_IONBF :: libc._IONBF + +SEEK_CUR :: libc.SEEK_CUR +SEEK_END :: libc.SEEK_END +SEEK_SET :: libc.SEEK_SET + +FILENAME_MAX :: libc.FILENAME_MAX +FOPEN_MAX :: libc.FOPEN_MAX +TMP_MAX :: libc.TMP_MAX + +EOF :: libc.EOF + +stderr := libc.stderr +stdin := libc.stdin +stdout := libc.stdout diff --git a/core/sys/posix/stdlib.odin b/core/sys/posix/stdlib.odin index a1e2eab50..640c70b5a 100644 --- a/core/sys/posix/stdlib.odin +++ b/core/sys/posix/stdlib.odin @@ -1,9 +1,9 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "base:intrinsics" import "core:c" -import "core:c/libc" when ODIN_OS == .Darwin { foreign import lib "system:System.framework" @@ -11,56 +11,6 @@ when ODIN_OS == .Darwin { foreign import lib "system:c" } -// stdlib.h - standard library definitions - -atof :: libc.atof -atoi :: libc.atoi -atol :: libc.atol -atoll :: libc.atoll -strtod :: libc.strtod -strtof :: libc.strtof -strtol :: libc.strtol -strtoll :: libc.strtoll -strtoul :: libc.strtoul -strtoull :: libc.strtoull - -rand :: libc.rand -srand :: libc.srand - -calloc :: libc.calloc -malloc :: libc.malloc -realloc :: libc.realloc - -abort :: libc.abort -atexit :: libc.atexit -at_quick_exit :: libc.at_quick_exit -exit :: libc.exit -_Exit :: libc._Exit -getenv :: libc.getenv -quick_exit :: libc.quick_exit -system :: libc.system - -bsearch :: libc.bsearch -qsort :: libc.qsort - -abs :: libc.abs -labs :: libc.labs -llabs :: libc.llabs -div :: libc.div -ldiv :: libc.ldiv -lldiv :: libc.lldiv - -mblen :: libc.mblen -mbtowc :: libc.mbtowc -wctomb :: libc.wctomb - -mbstowcs :: libc.mbstowcs -wcstombs :: libc.wcstombs - -free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { - libc.free(rawptr(ptr)) -} - foreign lib { /* Takes a pointer to a radix-64 representation, in which the first digit is the least significant, @@ -342,21 +292,6 @@ foreign lib { */ unlockpt :: proc(fildes: FD) -> result --- - /* - Uses the string argument to set environment variable values. - - Returns: 0 on success, non-zero (setting errno) on failure - - Example: - if posix.putenv("HOME=/usr/home") != 0 { - fmt.panicf("putenv failure: %v", posix.strerror(posix.errno())) - } - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html ]] - */ - @(link_name=LPUTENV) - putenv :: proc(string: cstring) -> c.int --- - /* Updates or add a variable in the environment of the calling process. @@ -427,23 +362,11 @@ foreign lib { setkey :: proc(key: [^]byte) --- } -EXIT_FAILURE :: libc.EXIT_FAILURE -EXIT_SUCCESS :: libc.EXIT_SUCCESS - -RAND_MAX :: libc.RAND_MAX -MB_CUR_MAX :: libc.MB_CUR_MAX - -div_t :: libc.div_t -ldiv_t :: libc.ldiv_t -lldiv_t :: libc.lldiv_t - when ODIN_OS == .NetBSD { - @(private) LPUTENV :: "__putenv50" @(private) LINITSTATE :: "__initstate60" @(private) LSRANDOM :: "__srandom60" @(private) LUNSETENV :: "__unsetenv13" } else { - @(private) LPUTENV :: "putenv" @(private) LINITSTATE :: "initstate" @(private) LSRANDOM :: "srandom" @(private) LUNSETENV :: "unsetenv" diff --git a/core/sys/posix/stdlib_libc.odin b/core/sys/posix/stdlib_libc.odin new file mode 100644 index 000000000..fa4d925b2 --- /dev/null +++ b/core/sys/posix/stdlib_libc.odin @@ -0,0 +1,101 @@ +#+build linux, windows, darwin, netbsd, openbsd, freebsd +package posix + +import "base:intrinsics" + +import "core:c" +import "core:c/libc" + +when ODIN_OS == .Windows { + foreign import lib "system:libucrt.lib" +} else when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// stdlib.h - standard library definitions + +atof :: libc.atof +atoi :: libc.atoi +atol :: libc.atol +atoll :: libc.atoll +strtod :: libc.strtod +strtof :: libc.strtof +strtol :: libc.strtol +strtoll :: libc.strtoll +strtoul :: libc.strtoul +strtoull :: libc.strtoull + +rand :: libc.rand +srand :: libc.srand + +calloc :: libc.calloc +malloc :: libc.malloc +realloc :: libc.realloc + +abort :: libc.abort +atexit :: libc.atexit +at_quick_exit :: libc.at_quick_exit +exit :: libc.exit +_Exit :: libc._Exit +getenv :: libc.getenv +quick_exit :: libc.quick_exit +system :: libc.system + +bsearch :: libc.bsearch +qsort :: libc.qsort + +abs :: libc.abs +labs :: libc.labs +llabs :: libc.llabs +div :: libc.div +ldiv :: libc.ldiv +lldiv :: libc.lldiv + +mblen :: libc.mblen +mbtowc :: libc.mbtowc +wctomb :: libc.wctomb + +mbstowcs :: libc.mbstowcs +wcstombs :: libc.wcstombs + +free :: #force_inline proc(ptr: $T) where intrinsics.type_is_pointer(T) || intrinsics.type_is_multi_pointer(T) || T == cstring { + libc.free(rawptr(ptr)) +} + +foreign lib { + + /* + Uses the string argument to set environment variable values. + + Returns: 0 on success, non-zero (setting errno) on failure + + Example: + if posix.putenv("HOME=/usr/home") != 0 { + fmt.panicf("putenv failure: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/putenv.html ]] + */ + @(link_name=LPUTENV) + putenv :: proc(string: cstring) -> c.int --- +} + +EXIT_FAILURE :: libc.EXIT_FAILURE +EXIT_SUCCESS :: libc.EXIT_SUCCESS + +RAND_MAX :: libc.RAND_MAX +MB_CUR_MAX :: libc.MB_CUR_MAX + +div_t :: libc.div_t +ldiv_t :: libc.ldiv_t +lldiv_t :: libc.lldiv_t + +when ODIN_OS == .Windows { + @(private) LPUTENV :: "_putenv" +} else when ODIN_OS == .NetBSD { + @(private) LPUTENV :: "__putenv50" +} else { + @(private) LPUTENV :: "putenv" +} diff --git a/core/sys/posix/string.odin b/core/sys/posix/string.odin index d22f49a96..96b6a9007 100644 --- a/core/sys/posix/string.odin +++ b/core/sys/posix/string.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -13,16 +14,6 @@ when ODIN_OS == .Darwin { // NOTE: most of the symbols in this header are not useful in Odin and have been left out. foreign lib { - /* - Map the error number to a locale-dependent error message string. - - Returns: a string that may be invalidated by subsequent calls - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html ]] - */ - @(link_name="strerror") - _strerror :: proc(errnum: Errno) -> cstring --- - /* Map the error number to a locale-dependent error message string and put it in the buffer. @@ -41,7 +32,3 @@ foreign lib { */ strsignal :: proc(sig: Signal) -> cstring --- } - -strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring { - return _strerror(errnum.? or_else errno()) -} diff --git a/core/sys/posix/string_libc.odin b/core/sys/posix/string_libc.odin new file mode 100644 index 000000000..336352cbc --- /dev/null +++ b/core/sys/posix/string_libc.odin @@ -0,0 +1,30 @@ +#+build linux, windows, darwin, netbsd, openbsd, freebsd +package posix + +when ODIN_OS == .Windows { + foreign import lib "system:libucrt.lib" +} else when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// string.h - string operations + +// NOTE: most of the symbols in this header are not useful in Odin and have been left out. + +foreign lib { + /* + Map the error number to a locale-dependent error message string. + + Returns: a string that may be invalidated by subsequent calls + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html ]] + */ + @(link_name="strerror") + _strerror :: proc(errnum: Errno) -> cstring --- +} + +strerror :: #force_inline proc "contextless" (errnum: Maybe(Errno) = nil) -> cstring { + return _strerror(errnum.? or_else errno()) +} diff --git a/core/sys/posix/sys_ipc.odin b/core/sys/posix/sys_ipc.odin index 33f8fa259..0f7ec06c5 100644 --- a/core/sys/posix/sys_ipc.odin +++ b/core/sys/posix/sys_ipc.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -110,6 +111,4 @@ when ODIN_OS == .Darwin { IPC_SET :: 1 IPC_STAT :: 2 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_mman.odin b/core/sys/posix/sys_mman.odin index 2f4eb566b..9e2939a05 100644 --- a/core/sys/posix/sys_mman.odin +++ b/core/sys/posix/sys_mman.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -225,6 +226,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS POSIX_MADV_SEQUENTIAL :: 2 POSIX_MADV_WILLNEED :: 3 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_msg.odin b/core/sys/posix/sys_msg.odin index 98b76c3a5..0e78777f9 100644 --- a/core/sys/posix/sys_msg.odin +++ b/core/sys/posix/sys_msg.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -150,6 +151,24 @@ when ODIN_OS == .Darwin { msg_pad4: [4]c.long, } -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + msgqnum_t :: distinct c.ulong + msglen_t :: distinct c.ulong + + MSG_NOERROR :: 0o10000 + + msqid_ds :: struct { + msg_perm: ipc_perm, /* [PSX] operation permission structure */ + msg_stime: time_t, /* [PSX] time of last msgsnd() */ + msg_rtime: time_t, /* [PSX] time of last msgrcv() */ + msg_ctime: time_t, /* [PSX] time of last change */ + msg_cbytes: c.ulong, + msg_qnum: msgqnum_t, /* [PSX] number of messages currently on queue */ + msg_qbytes: msglen_t, /* [PSX] maximum number of bytes allowed on queue */ + msg_lspid: pid_t, /* [PSX] process ID of last msgsnd() */ + msg_lrpid: pid_t, /* [PSX] process ID of last msgrcv() */ + __unused: [2]c.ulong, + } + } diff --git a/core/sys/posix/sys_resource.odin b/core/sys/posix/sys_resource.odin index 55789ee95..9af2a929b 100644 --- a/core/sys/posix/sys_resource.odin +++ b/core/sys/posix/sys_resource.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -154,6 +155,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS RLIMIT_AS :: 10 } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_select.odin b/core/sys/posix/sys_select.odin index c20636b21..2058ee777 100644 --- a/core/sys/posix/sys_select.odin +++ b/core/sys/posix/sys_select.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "base:intrinsics" @@ -72,7 +73,7 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS // NOTE: this seems correct for FreeBSD but they do use a set backed by the long type themselves (thus the align change). @(private) - ALIGN :: align_of(c.long) when ODIN_OS == .FreeBSD else align_of(c.int32_t) + ALIGN :: align_of(c.long) when ODIN_OS == .FreeBSD || ODIN_OS == .Linux else align_of(c.int32_t) fd_set :: struct #align(ALIGN) { fds_bits: [(FD_SETSIZE / __NFDBITS) when (FD_SETSIZE % __NFDBITS) == 0 else (FD_SETSIZE / __NFDBITS) + 1]c.int32_t, @@ -115,6 +116,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS intrinsics.mem_zero(_p, size_of(fd_set)) } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_sem.odin b/core/sys/posix/sys_sem.odin index 2d7bd1b1e..6b695e766 100644 --- a/core/sys/posix/sys_sem.odin +++ b/core/sys/posix/sys_sem.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -153,6 +154,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS sem_flg: c.short, /* [PSX] operation flags */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_shm.odin b/core/sys/posix/sys_shm.odin index ff56ba441..8f3c56b9c 100644 --- a/core/sys/posix/sys_shm.odin +++ b/core/sys/posix/sys_shm.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -137,6 +138,24 @@ when ODIN_OS == .Darwin { _shm_internal: rawptr, } -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + SHM_RDONLY :: 0o10000 + SHM_RND :: 0o20000 + + SHMLBA :: 4096 + + shmatt_t :: distinct c.ulong + + shmid_ds :: struct { + shm_perm: ipc_perm, /* [PSX] operation permission structure */ + shm_segsz: c.size_t, /* [PSX] size of segment in bytes */ + shm_atime: time_t, /* [PSX] time of last shmat() */ + shm_dtime: time_t, /* [PSX] time of last shmdt() */ + shm_ctime: time_t, /* [PSX] time of last change by shmctl() */ + shm_cpid: pid_t, /* [PSX] process ID of creator */ + shm_lpid: pid_t, /* [PSX] process ID of last shared memory operation */ + shm_nattch: shmatt_t, /* [PSX] number of current attaches */ + _: [2]c.ulong, + } } diff --git a/core/sys/posix/sys_socket.odin b/core/sys/posix/sys_socket.odin index e613f0a10..3c9db5bfa 100644 --- a/core/sys/posix/sys_socket.odin +++ b/core/sys/posix/sys_socket.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -325,14 +326,16 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS socklen_t :: distinct c.uint - _sa_family_t :: distinct c.uint8_t - when ODIN_OS == .Linux { + _sa_family_t :: distinct c.ushort + sockaddr :: struct { sa_family: sa_family_t, /* [PSX] address family */ sa_data: [14]c.char, /* [PSX] socket address */ } } else { + _sa_family_t :: distinct c.uint8_t + sockaddr :: struct { sa_len: c.uint8_t, /* total length */ sa_family: sa_family_t, /* [PSX] address family */ @@ -560,7 +563,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS SHUT_RDWR :: 2 SHUT_WR :: 1 -} else { - #panic("posix is unimplemented for the current target") } - diff --git a/core/sys/posix/sys_stat.odin b/core/sys/posix/sys_stat.odin index dd66d7d14..61b98ef35 100644 --- a/core/sys/posix/sys_stat.odin +++ b/core/sys/posix/sys_stat.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -280,20 +281,20 @@ when ODIN_OS == .Darwin { ino_t :: distinct c.uint64_t stat_t :: struct { - st_dev: dev_t, /* [XSI] ID of device containing file */ - st_mode: mode_t, /* [XSI] mode of file */ - st_nlink: nlink_t, /* [XSI] number of hard links */ - st_ino: ino_t, /* [XSI] file serial number */ - st_uid: uid_t, /* [XSI] user ID of the file */ - st_gid: gid_t, /* [XSI] group ID of the file */ - st_rdev: dev_t, /* [XSI] device ID */ - st_atim: timespec, /* [XSI] time of last access */ - st_mtim: timespec, /* [XSI] time of last data modification */ - st_ctim: timespec, /* [XSI] time of last status change */ + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_mode: mode_t, /* [PSX] mode of file */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_ino: ino_t, /* [PSX] file serial number */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ + st_rdev: dev_t, /* [PSX] device ID */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ st_birthtimespec: timespec, /* time of file creation(birth) */ - st_size: off_t, /* [XSI] file size, in bytes */ - st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ - st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ st_flags: c.uint32_t, /* user defined flags for file */ st_gen: c.uint32_t, /* file generation number */ st_lspare: c.int32_t, /* RESERVED */ @@ -314,47 +315,47 @@ when ODIN_OS == .Darwin { when ODIN_ARCH == .i386 { stat_t :: struct { - st_dev: dev_t, /* [XSI] ID of device containing file */ - st_ino: ino_t, /* [XSI] file serial number */ - st_nlink: nlink_t, /* [XSI] number of hard links */ - st_mode: mode_t, /* [XSI] mode of file */ + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_mode: mode_t, /* [PSX] mode of file */ st_padding0: c.int16_t, - st_uid: uid_t, /* [XSI] user ID of the file */ - st_gid: gid_t, /* [XSI] group ID of the file */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ st_padding1: c.int32_t, - st_rdev: dev_t, /* [XSI] device ID */ + st_rdev: dev_t, /* [PSX] device ID */ st_atim_ext: c.int32_t, - st_atim: timespec, /* [XSI] time of last access */ + st_atim: timespec, /* [PSX] time of last access */ st_mtim_ext: c.int32_t, - st_mtim: timespec, /* [XSI] time of last data modification */ + st_mtim: timespec, /* [PSX] time of last data modification */ st_ctim_ext: c.int32_t, - st_ctim: timespec, /* [XSI] time of last status change */ + st_ctim: timespec, /* [PSX] time of last status change */ st_birthtimespec: timespec, /* time of file creation(birth) */ - st_size: off_t, /* [XSI] file size, in bytes */ - st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ - st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ st_flags: c.uint32_t, /* user defined flags for file */ st_gen: c.uint64_t, st_spare: [10]c.uint64_t, } } else { stat_t :: struct { - st_dev: dev_t, /* [XSI] ID of device containing file */ - st_ino: ino_t, /* [XSI] file serial number */ - st_nlink: nlink_t, /* [XSI] number of hard links */ - st_mode: mode_t, /* [XSI] mode of file */ + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_mode: mode_t, /* [PSX] mode of file */ st_padding0: c.int16_t, - st_uid: uid_t, /* [XSI] user ID of the file */ - st_gid: gid_t, /* [XSI] group ID of the file */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ st_padding1: c.int32_t, - st_rdev: dev_t, /* [XSI] device ID */ - st_atim: timespec, /* [XSI] time of last access */ - st_mtim: timespec, /* [XSI] time of last data modification */ - st_ctim: timespec, /* [XSI] time of last status change */ + st_rdev: dev_t, /* [PSX] device ID */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ st_birthtimespec: timespec, /* time of file creation(birth) */ - st_size: off_t, /* [XSI] file size, in bytes */ - st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ - st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ st_flags: c.uint32_t, /* user defined flags for file */ st_gen: c.uint64_t, st_spare: [10]c.uint64_t, @@ -374,20 +375,20 @@ when ODIN_OS == .Darwin { ino_t :: distinct c.uint64_t stat_t :: struct { - st_dev: dev_t, /* [XSI] ID of device containing file */ - st_mode: mode_t, /* [XSI] mode of file */ - st_ino: ino_t, /* [XSI] file serial number */ - st_nlink: nlink_t, /* [XSI] number of hard links */ - st_uid: uid_t, /* [XSI] user ID of the file */ - st_gid: gid_t, /* [XSI] group ID of the file */ - st_rdev: dev_t, /* [XSI] device ID */ - st_atim: timespec, /* [XSI] time of last access */ - st_mtim: timespec, /* [XSI] time of last data modification */ - st_ctim: timespec, /* [XSI] time of last status change */ + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_mode: mode_t, /* [PSX] mode of file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ + st_rdev: dev_t, /* [PSX] device ID */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ st_birthtimespec: timespec, /* time of file creation(birth) */ - st_size: off_t, /* [XSI] file size, in bytes */ - st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ - st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ st_flags: c.uint32_t, /* user defined flags for file */ st_gen: c.uint64_t, st_spare: [2]c.uint32_t, @@ -406,19 +407,19 @@ when ODIN_OS == .Darwin { ino_t :: distinct c.uint64_t stat_t :: struct { - st_mode: mode_t, /* [XSI] mode of file */ - st_dev: dev_t, /* [XSI] ID of device containing file */ - st_ino: ino_t, /* [XSI] file serial number */ - st_nlink: nlink_t, /* [XSI] number of hard links */ - st_uid: uid_t, /* [XSI] user ID of the file */ - st_gid: gid_t, /* [XSI] group ID of the file */ - st_rdev: dev_t, /* [XSI] device ID */ - st_atim: timespec, /* [XSI] time of last access */ - st_mtim: timespec, /* [XSI] time of last data modification */ - st_ctim: timespec, /* [XSI] time of last status change */ - st_size: off_t, /* [XSI] file size, in bytes */ - st_blocks: blkcnt_t, /* [XSI] blocks allocated for file */ - st_blksize: blksize_t, /* [XSI] optimal blocksize for I/O */ + st_mode: mode_t, /* [PSX] mode of file */ + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ + st_rdev: dev_t, /* [PSX] device ID */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ st_flags: c.uint32_t, /* user defined flags for file */ st_gen: c.int32_t, st_birthtimespec: timespec, @@ -427,6 +428,58 @@ when ODIN_OS == .Darwin { UTIME_NOW :: -2 UTIME_OMIT :: -1 -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + dev_t :: distinct u64 + _mode_t :: distinct c.uint + blkcnt_t :: distinct i64 + + when ODIN_ARCH == .arm64 || ODIN_ARCH == .riscv64 { + nlink_t :: distinct c.uint + blksize_t :: distinct c.int + } else { + nlink_t :: distinct c.size_t + blksize_t :: distinct c.long + } + + ino_t :: distinct u64 + + when ODIN_ARCH == .amd64 { + stat_t :: struct { + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_mode: mode_t, /* [PSX] mode of file */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ + _pad0: c.uint, + st_rdev: dev_t, /* [PSX] device ID */ + st_size: off_t, /* [PSX] file size, in bytes */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ + __unused: [3]c.long, + } + } else { + stat_t :: struct { + st_dev: dev_t, /* [PSX] ID of device containing file */ + st_ino: ino_t, /* [PSX] file serial number */ + st_mode: mode_t, /* [PSX] mode of file */ + st_nlink: nlink_t, /* [PSX] number of hard links */ + st_uid: uid_t, /* [PSX] user ID of the file */ + st_gid: gid_t, /* [PSX] group ID of the file */ + st_rdev: dev_t, /* [PSX] device ID */ + __pad: c.ulonglong, + st_size: off_t, /* [PSX] file size, in bytes */ + st_blksize: blksize_t, /* [PSX] optimal blocksize for I/O */ + __pad2: c.int, + st_blocks: blkcnt_t, /* [PSX] blocks allocated for file */ + st_atim: timespec, /* [PSX] time of last access */ + st_mtim: timespec, /* [PSX] time of last data modification */ + st_ctim: timespec, /* [PSX] time of last status change */ + __unused: [2]c.uint, + } + } } diff --git a/core/sys/posix/sys_statvfs.odin b/core/sys/posix/sys_statvfs.odin index eb6c16806..47c810135 100644 --- a/core/sys/posix/sys_statvfs.odin +++ b/core/sys/posix/sys_statvfs.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -130,6 +131,27 @@ when ODIN_OS == .Darwin || ODIN_OS == .OpenBSD { ST_RDONLY :: 0x00000001 ST_NOSUID :: 0x00000008 -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + fsblkcnt_t :: distinct c.uint64_t + + statvfs_t :: struct { + f_bsize: c.ulong, /* [PSX] file system block size */ + f_frsize: c.ulong, /* [PSX] fundamental file system block size */ + f_blocks: fsblkcnt_t, /* [PSX] total number of blocks on file system in units of f_frsize */ + f_bfree: fsblkcnt_t, /* [PSX] total number of free blocks */ + f_bavail: fsblkcnt_t, /* [PSX] number of free blocks available to non-privileged process */ + f_files: fsblkcnt_t, /* [PSX] total number of file serial numbers */ + f_ffree: fsblkcnt_t, /* [PSX] total number of free file serial numbers */ + f_favail: fsblkcnt_t, /* [PSX] number of file serial numbers available to non-privileged process */ + f_fsid: c.ulong, /* [PSX] file system ID */ + _: [2*size_of(c.int)-size_of(c.long)]byte, + f_flag: VFS_Flags, /* [PSX] bit mask of f_flag values */ + f_namemax: c.ulong, /* [PSX] maximum filename length */ + f_type: c.uint, + __reserved: [5]c.int, + } + + ST_RDONLY :: 0x00000001 + ST_NOSUID :: 0x00000002 } diff --git a/core/sys/posix/sys_time.odin b/core/sys/posix/sys_time.odin index fd2e58121..3036352aa 100644 --- a/core/sys/posix/sys_time.odin +++ b/core/sys/posix/sys_time.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -77,6 +78,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS ITIMER_VIRTUAL :: 1 ITIMER_PROF :: 2 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_times.odin b/core/sys/posix/sys_times.odin index d38f3efc4..113e3f963 100644 --- a/core/sys/posix/sys_times.odin +++ b/core/sys/posix/sys_times.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix when ODIN_OS == .Darwin { @@ -33,6 +34,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS tms_cstime: clock_t, /* [PSX] terminated children system CPU time */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_uio.odin b/core/sys/posix/sys_uio.odin index 6755fe2ae..a0ad2934e 100644 --- a/core/sys/posix/sys_uio.odin +++ b/core/sys/posix/sys_uio.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -37,6 +38,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS iov_len: c.size_t, /* [PSX] size of the region iov_base points to */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_un.odin b/core/sys/posix/sys_un.odin index 15eb7b5fc..ca5c4ee31 100644 --- a/core/sys/posix/sys_un.odin +++ b/core/sys/posix/sys_un.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -19,6 +20,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS sun_path: [108]c.char, /* [PSX] socket pathname */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/sys_utsname.odin b/core/sys/posix/sys_utsname.odin index 4786eb4fd..64930160f 100644 --- a/core/sys/posix/sys_utsname.odin +++ b/core/sys/posix/sys_utsname.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -37,15 +38,10 @@ foreign lib { uname :: proc(uname: ^utsname) -> c.int --- } -when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD || ODIN_OS == .Linux { +when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS == .OpenBSD { - when ODIN_OS == .Linux { - @(private) - _SYS_NAMELEN :: 65 - } else { - @(private) - _SYS_NAMELEN :: 256 - } + @(private) + _SYS_NAMELEN :: 256 utsname :: struct { sysname: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */ @@ -55,6 +51,17 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS machine: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */ } -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + @(private) + _SYS_NAMELEN :: 65 + + utsname :: struct { + sysname: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of OS */ + nodename: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] name of this network node */ + release: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] release level */ + version: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] version level */ + machine: [_SYS_NAMELEN]c.char `fmt:"s,0"`, /* [PSX] hardware type */ + __domainname: [_SYS_NAMELEN]c.char `fmt:"s,0"`, + } } diff --git a/core/sys/posix/sys_wait.odin b/core/sys/posix/sys_wait.odin index e0e2ae21b..812bd8c62 100644 --- a/core/sys/posix/sys_wait.odin +++ b/core/sys/posix/sys_wait.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -391,6 +392,54 @@ when ODIN_OS == .Darwin { return (x & _WCONTINUED) == _WCONTINUED } -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + id_t :: distinct c.uint + + WCONTINUED :: 8 + WNOHANG :: 1 + WUNTRACED :: 2 + + WEXITED :: 4 + WNOWAIT :: 0x1000000 + WSTOPPED :: 2 + + _P_ALL :: 0 + _P_PID :: 1 + _P_PGID :: 2 + + @(private) + _WIFEXITED :: #force_inline proc "contextless" (x: c.int) -> bool { + return _WTERMSIG(x) == nil + } + + @(private) + _WEXITSTATUS :: #force_inline proc "contextless" (x: c.int) -> c.int { + return (x & 0xff00) >> 8 + } + + @(private) + _WIFSIGNALED :: #force_inline proc "contextless" (x: c.int) -> bool { + return (x & 0xffff) - 1 < 0xff + } + + @(private) + _WTERMSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(x & 0x7f) + } + + @(private) + _WIFSTOPPED :: #force_inline proc "contextless" (x: c.int) -> bool { + return ((x & 0xffff) * 0x10001) >> 8 > 0x7f00 + } + + @(private) + _WSTOPSIG :: #force_inline proc "contextless" (x: c.int) -> Signal { + return Signal(_WEXITSTATUS(x)) + } + + @(private) + _WIFCONTINUED :: #force_inline proc "contextless" (x: c.int) -> bool { + return x == 0xffff + } } diff --git a/core/sys/posix/termios.odin b/core/sys/posix/termios.odin index c73936d58..0c07eceb9 100644 --- a/core/sys/posix/termios.odin +++ b/core/sys/posix/termios.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -152,7 +153,7 @@ CControl_Flag_Bits :: enum tcflag_t { CControl_Flags :: bit_set[CControl_Flag_Bits; tcflag_t] // character size mask -CSIZE :: CControl_Flags{ .CS6, .CS7, .CS8 } +CSIZE :: transmute(CControl_Flags)tcflag_t(_CSIZE) COutput_Flag_Bits :: enum tcflag_t { OPOST = log2(OPOST), /* enable following output processing */ @@ -181,17 +182,17 @@ COutput_Flag_Bits :: enum tcflag_t { COutput_Flags :: bit_set[COutput_Flag_Bits; tcflag_t] // \n delay mask -NLDLY :: COutput_Flags{ .NL1, COutput_Flag_Bits(9) } +NLDLY :: transmute(COutput_Flags)tcflag_t(_NLDLY) // \r delay mask -CRDLY :: COutput_Flags{ .CR1, .CR2, .CR3 } +CRDLY :: transmute(COutput_Flags)tcflag_t(_CRDLY) // horizontal tab delay mask -TABDLY :: COutput_Flags{ .TAB1, .TAB3, COutput_Flag_Bits(2) } +TABDLY :: transmute(COutput_Flags)tcflag_t(_TABDLY) // \b delay mask -BSDLY :: COutput_Flags{ .BS1 } +BSDLY :: transmute(COutput_Flags)tcflag_t(_BSDLY) // vertical tab delay mask -VTDLY :: COutput_Flags{ .VT1 } +VTDLY :: transmute(COutput_Flags)tcflag_t(_VTDLY) // form feed delay mask -FFDLY :: COutput_Flags{ .FF1 } +FFDLY :: transmute(COutput_Flags)tcflag_t(_FFDLY) speed_t :: enum _speed_t { B0 = B0, @@ -596,6 +597,4 @@ when ODIN_OS == .Darwin { TCOOFF :: 0 TCOON :: 1 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/time.odin b/core/sys/posix/time.odin index 5c6ebcf2f..f9c51c63c 100644 --- a/core/sys/posix/time.odin +++ b/core/sys/posix/time.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -229,6 +230,16 @@ when ODIN_OS == .Darwin { getdate_err: Errno = .ENOSYS // NOTE: looks like it's not a thing on OpenBSD. -} else { - #panic("posix is unimplemented for the current target") +} else when ODIN_OS == .Linux { + + clockid_t :: distinct c.int + + CLOCK_MONOTONIC :: 1 + CLOCK_PROCESS_CPUTIME_ID :: 2 + CLOCK_REALTIME :: 0 + CLOCK_THREAD_CPUTIME_ID :: 3 + + foreign lib { + getdate_err: Errno + } } diff --git a/core/sys/posix/ulimit.odin b/core/sys/posix/ulimit.odin index 782756f6e..0f87641fa 100644 --- a/core/sys/posix/ulimit.odin +++ b/core/sys/posix/ulimit.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -38,6 +39,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS // NOTE: I don't think OpenBSD implements this API. -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/unistd.odin b/core/sys/posix/unistd.odin index 5b428ef6f..0526b3235 100644 --- a/core/sys/posix/unistd.odin +++ b/core/sys/posix/unistd.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -11,19 +12,6 @@ when ODIN_OS == .Darwin { // unistd.h - standard symbolic constants and types foreign lib { - /* - Checks the file named by the pathname pointed to by the path argument for - accessibility according to the bit pattern contained in amode. - - Example: - if (posix.access("/tmp/myfile", posix.F_OK) != .OK) { - fmt.printfln("/tmp/myfile access check failed: %v", posix.strerror(posix.errno())) - } - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]] - */ - access :: proc(path: cstring, amode: Mode_Flags = F_OK) -> result --- - /* Equivalent to `access` but relative paths are resolved based on `fd`. @@ -42,18 +30,6 @@ foreign lib { */ alarm :: proc(seconds: c.uint) -> c.uint --- - /* - Causes the directory named by path to become the current working directory. - - Example: - if (posix.chdir("/tmp") == .OK) { - fmt.println("changed current directory to /tmp") - } - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html ]] - */ - chdir :: proc(path: cstring) -> result --- - /* Equivalent to chdir but instead of a path the fildes is resolved to a directory. @@ -204,15 +180,6 @@ foreign lib { */ dup2 :: proc(fildes, fildes2: FD) -> FD --- - /* - Exits but, shall not call functions registered with atexit() nor any registered signal handlers. - Open streams shall not be flushed. - Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ]] - */ - _exit :: proc(status: c.int) -> ! --- - /* The exec family of functions shall replace the current process image with a new process image. The new image shall be constructed from a regular, executable file called the new process image file. @@ -392,44 +359,6 @@ foreign lib { */ ftruncate :: proc(fildes: FD, length: off_t) -> result --- - /* - Places an absolute pathname of the current working directory into buf. - - Returns: buf as a cstring on success, nil (setting errno) on failure - - Example: - size: int - path_max := posix.pathconf(".", ._PATH_MAX) - if path_max == -1 { - size = 1024 - } else if path_max > 10240 { - size = 10240 - } else { - size = int(path_max) - } - - buf: [dynamic]byte - cwd: cstring - for ; cwd == nil; size *= 2 { - if err := resize(&buf, size); err != nil { - fmt.panicf("allocation failure: %v", err) - } - - cwd = posix.getcwd(raw_data(buf), len(buf)) - if cwd == nil { - errno := posix.errno() - if errno != .ERANGE { - fmt.panicf("getcwd failure: %v", posix.strerror(errno)) - } - } - } - - fmt.println(path_max, cwd) - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html ]] - */ - getcwd :: proc(buf: [^]c.char, size: c.size_t) -> cstring --- - /* Returns the effective group ID of the calling process. @@ -829,13 +758,6 @@ foreign lib { */ readlinkat :: proc(fd: FD, path: cstring, buf: [^]byte, bufsize: c.size_t) -> c.ssize_t --- - /* - Remove an (empty) directory. - - ]] More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ]] - */ - rmdir :: proc(path: cstring) -> result --- - /* Set the effective group ID. @@ -912,13 +834,6 @@ foreign lib { */ sleep :: proc(seconds: c.uint) -> c.uint --- - /* - Copy nbyte bytes, from src, to dest, exchanging adjecent bytes. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/swab.html ]] - */ - swab :: proc(src: [^]byte, dest: [^]byte, nbytes: c.ssize_t) --- - /* Schedule file system updates. @@ -958,13 +873,6 @@ foreign lib { */ ttyname_r :: proc(fildes: FD, name: [^]byte, namesize: c.size_t) -> Errno --- - /* - Remove a directory entry. - - [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]] - */ - unlink :: proc(path: cstring) -> result --- - /* Equivalent to unlink or rmdir (if flag is .REMOVEDIR) but relative paths are relative to the dir fd. @@ -973,20 +881,6 @@ foreign lib { unlinkat :: proc(fd: FD, path: cstring, flag: AT_Flags) -> result --- } -STDERR_FILENO :: 2 -STDIN_FILENO :: 0 -STDOUT_FILENO :: 1 - -Mode_Flag_Bits :: enum c.int { - X_OK = log2(X_OK), - W_OK = log2(W_OK), - R_OK = log2(R_OK), -} -Mode_Flags :: bit_set[Mode_Flag_Bits; c.int] - -#assert(_F_OK == 0) -F_OK :: Mode_Flags{} - CS :: enum c.int { _PATH = _CS_PATH, _POSIX_V6_ILP32_OFF32_CFLAGS = _CS_POSIX_V6_ILP32_OFF32_CFLAGS, @@ -2063,6 +1957,7 @@ when ODIN_OS == .Darwin { _SC_TYPED_MEMORY_OBJECTS :: 165 _SC_2_PBS :: 168 _SC_2_PBS_ACCOUNTING :: 169 + _SC_2_PBS_LOCATE :: 170 _SC_2_PBS_MESSAGE :: 171 _SC_2_PBS_TRACK :: 172 _SC_SYMLOOP_MAX :: 173 @@ -2097,7 +1992,4 @@ when ODIN_OS == .Darwin { // NOTE: Not implemented. _POSIX_VDISABLE :: 0 -} else { - #panic("posix is unimplemented for the current target") } - diff --git a/core/sys/posix/unistd_libc.odin b/core/sys/posix/unistd_libc.odin new file mode 100644 index 000000000..bbfe3d59d --- /dev/null +++ b/core/sys/posix/unistd_libc.odin @@ -0,0 +1,153 @@ +#+build linux, windows, darwin, netbsd, openbsd, freebsd +package posix + +import "core:c" + +when ODIN_OS == .Windows { + foreign import lib "system:libucrt.lib" +} else when ODIN_OS == .Darwin { + foreign import lib "system:System.framework" +} else { + foreign import lib "system:c" +} + +// unistd.h - standard symbolic constants and types + +foreign lib { + /* + Checks the file named by the pathname pointed to by the path argument for + accessibility according to the bit pattern contained in amode. + + Example: + if (posix.access("/tmp/myfile", posix.F_OK) != .OK) { + fmt.printfln("/tmp/myfile access check failed: %v", posix.strerror(posix.errno())) + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html ]] + */ + @(link_name=LACCESS) + access :: proc(path: cstring, amode: Mode_Flags = F_OK) -> result --- + + /* + Causes the directory named by path to become the current working directory. + + Example: + if (posix.chdir("/tmp") == .OK) { + fmt.println("changed current directory to /tmp") + } + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/chdir.html ]] + */ + @(link_name=LCHDIR) + chdir :: proc(path: cstring) -> result --- + + /* + Exits but, shall not call functions registered with atexit() nor any registered signal handlers. + Open streams shall not be flushed. + Whether open streams are closed (without flushing) is implementation-defined. Finally, the calling process shall be terminated with the consequences described below. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html ]] + */ + _exit :: proc(status: c.int) -> ! --- + + /* + Places an absolute pathname of the current working directory into buf. + + Returns: buf as a cstring on success, nil (setting errno) on failure + + Example: + size: int + path_max := posix.pathconf(".", ._PATH_MAX) + if path_max == -1 { + size = 1024 + } else if path_max > 10240 { + size = 10240 + } else { + size = int(path_max) + } + + buf: [dynamic]byte + cwd: cstring + for ; cwd == nil; size *= 2 { + if err := resize(&buf, size); err != nil { + fmt.panicf("allocation failure: %v", err) + } + + cwd = posix.getcwd(raw_data(buf), len(buf)) + if cwd == nil { + errno := posix.errno() + if errno != .ERANGE { + fmt.panicf("getcwd failure: %v", posix.strerror(errno)) + } + } + } + + fmt.println(path_max, cwd) + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/getcwd.html ]] + */ + @(link_name=LGETCWD) + getcwd :: proc(buf: [^]c.char, size: c.size_t) -> cstring --- + + /* + Remove an (empty) directory. + + ]] More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/rmdir.html ]] + */ + @(link_name=LRMDIR) + rmdir :: proc(path: cstring) -> result --- + + /* + Copy nbyte bytes, from src, to dest, exchanging adjecent bytes. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/swab.html ]] + */ + @(link_name=LSWAB) + swab :: proc(src: [^]byte, dest: [^]byte, nbytes: c.ssize_t) --- + + /* + Remove a directory entry. + + [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/unlink.html ]] + */ + @(link_name=LUNLINK) + unlink :: proc(path: cstring) -> result --- +} + +when ODIN_OS == .Windows { + @(private) LACCESS :: "_access" + @(private) LCHDIR :: "_chdir" + @(private) LGETCWD :: "_getcwd" + @(private) LRMDIR :: "_rmdir" + @(private) LSWAB :: "_swab" + @(private) LUNLINK :: "_unlink" +} else { + @(private) LACCESS :: "access" + @(private) LCHDIR :: "chdir" + @(private) LGETCWD :: "getcwd" + @(private) LRMDIR :: "rmdir" + @(private) LSWAB :: "swab" + @(private) LUNLINK :: "unlink" +} + +STDERR_FILENO :: 2 +STDIN_FILENO :: 0 +STDOUT_FILENO :: 1 + +Mode_Flag_Bits :: enum c.int { + X_OK = log2(X_OK), + W_OK = log2(W_OK), + R_OK = log2(R_OK), +} +Mode_Flags :: bit_set[Mode_Flag_Bits; c.int] + +#assert(_F_OK == 0) +F_OK :: Mode_Flags{} + +when ODIN_OS == .Windows { + _F_OK :: 0 + X_OK :: 1 + W_OK :: 2 + R_OK :: 4 + #assert(W_OK|R_OK == 6) +} diff --git a/core/sys/posix/utime.odin b/core/sys/posix/utime.odin index 1207cb402..e884eb1a3 100644 --- a/core/sys/posix/utime.odin +++ b/core/sys/posix/utime.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix when ODIN_OS == .Darwin { @@ -31,6 +32,4 @@ when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD || ODIN_OS modtime: time_t, /* [PSX] modification time (seconds since epoch) */ } -} else { - #panic("posix is unimplemented for the current target") } diff --git a/core/sys/posix/wordexp.odin b/core/sys/posix/wordexp.odin index 6bb362625..a9e6f39a7 100644 --- a/core/sys/posix/wordexp.odin +++ b/core/sys/posix/wordexp.odin @@ -1,3 +1,4 @@ +#+build linux, darwin, netbsd, openbsd, freebsd package posix import "core:c" @@ -123,6 +124,4 @@ when ODIN_OS == .Darwin { WRDE_CMDSUB :: 4 WRDE_SYNTAX :: 5 -} else { - #panic("posix is unimplemented for the current target") } diff --git a/tests/core/sys/posix/posix.odin b/tests/core/sys/posix/posix.odin index d73e49ffb..c215747e4 100644 --- a/tests/core/sys/posix/posix.odin +++ b/tests/core/sys/posix/posix.odin @@ -1,4 +1,4 @@ -#+build darwin, freebsd, openbsd, netbsd +#+build linux, darwin, freebsd, openbsd, netbsd package tests_core_posix import "core:log" @@ -144,7 +144,6 @@ test_libgen :: proc(t: ^testing.T) { { "usr/", ".", "usr" }, { "", ".", "." }, { "/", "/", "/" }, - { "//", "/", "/" }, { "///", "/", "/" }, { "/usr/", "/", "usr" }, { "/usr/lib", "/usr", "lib" }, @@ -197,24 +196,12 @@ test_stat :: proc(t: ^testing.T) { stat: posix.stat_t testing.expect_value(t, posix.stat(#file, &stat), posix.result.OK) testing.expect(t, posix.S_ISREG(stat.st_mode)) - testing.expect_value(t, stat.st_mode, posix.mode_t{.IROTH, .IRGRP, .IRUSR, .IWUSR, .IFREG}) + testing.expect_value(t, stat.st_mode, posix.mode_t{.IROTH, .IRGRP, .IRUSR, .IWGRP, .IWUSR, .IFREG}) CONTENT := #load(#file) testing.expect_value(t, stat.st_size, posix.off_t(len(CONTENT))) } -@(test) -test_termios :: proc(t: ^testing.T) { - testing.expect_value(t, transmute(posix.CControl_Flags)posix.tcflag_t(posix._CSIZE), posix.CSIZE) - - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._NLDLY), posix.NLDLY) - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._CRDLY), posix.CRDLY) - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._TABDLY), posix.TABDLY) - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._BSDLY), posix.BSDLY) - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._VTDLY), posix.VTDLY) - testing.expect_value(t, transmute(posix.COutput_Flags)posix.tcflag_t(posix._FFDLY), posix.FFDLY) -} - @(test) test_pthreads :: proc(t: ^testing.T) { testing.set_fail_timeout(t, time.Second) diff --git a/tests/core/sys/posix/structs.odin b/tests/core/sys/posix/structs.odin index de9511634..a0e8fea99 100644 --- a/tests/core/sys/posix/structs.odin +++ b/tests/core/sys/posix/structs.odin @@ -1,4 +1,4 @@ -#+build darwin, freebsd, openbsd, netbsd +#+build linux, darwin, freebsd, openbsd, netbsd package tests_core_posix import "core:log" diff --git a/tests/core/sys/posix/structs/structs.c b/tests/core/sys/posix/structs/structs.c index 7d8038fbb..6cabb8488 100644 --- a/tests/core/sys/posix/structs/structs.c +++ b/tests/core/sys/posix/structs/structs.c @@ -40,7 +40,9 @@ int main(int argc, char *argv[]) printf("pthread_attr_t %zu %zu\n", sizeof(pthread_attr_t), _Alignof(pthread_attr_t)); printf("pthread_key_t %zu %zu\n", sizeof(pthread_key_t), _Alignof(pthread_key_t)); +#ifndef __linux__ printf("sched_param %zu %zu\n", sizeof(struct sched_param), _Alignof(struct sched_param)); +#endif printf("termios %zu %zu\n", sizeof(struct termios), _Alignof(struct termios)); diff --git a/tests/core/sys/posix/structs/structs.odin b/tests/core/sys/posix/structs/structs.odin index 2663d1e30..e159ddf3c 100644 --- a/tests/core/sys/posix/structs/structs.odin +++ b/tests/core/sys/posix/structs/structs.odin @@ -14,7 +14,11 @@ main :: proc() { fmt.println("pthread_attr_t", size_of(posix.pthread_attr_t), align_of(posix.pthread_attr_t)) fmt.println("pthread_key_t", size_of(posix.pthread_key_t), align_of(posix.pthread_key_t)) - fmt.println("sched_param", size_of(posix.sched_param), align_of(posix.sched_param)) + // NOTE: On Linux, differences between libc may mean the Odin side is larger than the other side, + // this is fine in practice. + when ODIN_OS != .Linux { + fmt.println("sched_param", size_of(posix.sched_param), align_of(posix.sched_param)) + } fmt.println("termios", size_of(posix.termios), align_of(posix.termios)) From e064f8c6bec2e656446b52afb35af7bfee02e6a9 Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 18:58:26 +0100 Subject: [PATCH 12/21] fix `#load_directory` including nested directories --- src/check_builtin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index ab18123dd..ebdfa41b0 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1533,6 +1533,10 @@ gb_internal LoadDirectiveResult check_load_directory_directive(CheckerContext *c for (FileInfo fi : list) { LoadFileCache *cache = nullptr; + if (fi.is_dir) { + continue; + } + if (cache_load_file_directive(c, call, fi.fullpath, err_on_not_found, &cache, LoadFileTier_Contents, /*use_mutex*/false)) { array_add(&file_caches, cache); } else { From afed3ce6b5ae00d12e46f2799f16e286369ef3b3 Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 19:20:43 +0100 Subject: [PATCH 13/21] remove pthread from sys/unix and use sys/posix where used --- core/sys/unix/pthread_darwin.odin | 96 ------------------- core/sys/unix/pthread_freebsd.odin | 122 ------------------------- core/sys/unix/pthread_haiku.odin | 71 -------------- core/sys/unix/pthread_linux.odin | 124 ------------------------- core/sys/unix/pthread_netbsd.odin | 102 --------------------- core/sys/unix/pthread_openbsd.odin | 74 --------------- core/sys/unix/pthread_unix.odin | 127 -------------------------- core/sys/unix/unix.odin | 5 + core/testing/signal_handler_libc.odin | 6 +- core/thread/thread_unix.odin | 60 ++++++------ 10 files changed, 38 insertions(+), 749 deletions(-) delete mode 100644 core/sys/unix/pthread_darwin.odin delete mode 100644 core/sys/unix/pthread_freebsd.odin delete mode 100644 core/sys/unix/pthread_haiku.odin delete mode 100644 core/sys/unix/pthread_linux.odin delete mode 100644 core/sys/unix/pthread_netbsd.odin delete mode 100644 core/sys/unix/pthread_openbsd.odin delete mode 100644 core/sys/unix/pthread_unix.odin create mode 100644 core/sys/unix/unix.odin diff --git a/core/sys/unix/pthread_darwin.odin b/core/sys/unix/pthread_darwin.odin deleted file mode 100644 index eb2cc4c9f..000000000 --- a/core/sys/unix/pthread_darwin.odin +++ /dev/null @@ -1,96 +0,0 @@ -#+build darwin -package unix - -import "core:c" - -// NOTE(tetra): No 32-bit Macs. -// Source: _pthread_types.h on my Mac. -PTHREAD_SIZE :: 8176 -PTHREAD_ATTR_SIZE :: 56 -PTHREAD_MUTEXATTR_SIZE :: 8 -PTHREAD_MUTEX_SIZE :: 56 -PTHREAD_CONDATTR_SIZE :: 8 -PTHREAD_COND_SIZE :: 40 -PTHREAD_ONCE_SIZE :: 8 -PTHREAD_RWLOCK_SIZE :: 192 -PTHREAD_RWLOCKATTR_SIZE :: 16 - -pthread_t :: distinct u64 - -pthread_attr_t :: struct { - sig: c.long, - _: [PTHREAD_ATTR_SIZE] c.char, -} - -pthread_cond_t :: struct { - sig: c.long, - _: [PTHREAD_COND_SIZE] c.char, -} - -pthread_condattr_t :: struct { - sig: c.long, - _: [PTHREAD_CONDATTR_SIZE] c.char, -} - -pthread_mutex_t :: struct { - sig: c.long, - _: [PTHREAD_MUTEX_SIZE] c.char, -} - -pthread_mutexattr_t :: struct { - sig: c.long, - _: [PTHREAD_MUTEXATTR_SIZE] c.char, -} - -pthread_once_t :: struct { - sig: c.long, - _: [PTHREAD_ONCE_SIZE] c.char, -} - -pthread_rwlock_t :: struct { - sig: c.long, - _: [PTHREAD_RWLOCK_SIZE] c.char, -} - -pthread_rwlockattr_t :: struct { - sig: c.long, - _: [PTHREAD_RWLOCKATTR_SIZE] c.char, -} - -SCHED_OTHER :: 1 // Avoid if you are writing portable software. -SCHED_FIFO :: 4 -SCHED_RR :: 2 // Round robin. - -SCHED_PARAM_SIZE :: 4 - -sched_param :: struct { - sched_priority: c.int, - _: [SCHED_PARAM_SIZE] c.char, -} - -// Source: https://github.com/apple/darwin-libpthread/blob/03c4628c8940cca6fd6a82957f683af804f62e7f/pthread/pthread.h#L138 -PTHREAD_CREATE_JOINABLE :: 1 -PTHREAD_CREATE_DETACHED :: 2 -PTHREAD_INHERIT_SCHED :: 1 -PTHREAD_EXPLICIT_SCHED :: 2 -PTHREAD_PROCESS_SHARED :: 1 -PTHREAD_PROCESS_PRIVATE :: 2 - - -PTHREAD_MUTEX_NORMAL :: 0 -PTHREAD_MUTEX_RECURSIVE :: 1 -PTHREAD_MUTEX_ERRORCHECK :: 2 - -PTHREAD_CANCEL_ENABLE :: 0 -PTHREAD_CANCEL_DISABLE :: 1 -PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 1 - -foreign import pthread "system:System.framework" - -@(default_calling_convention="c") -foreign pthread { - 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 --- -} diff --git a/core/sys/unix/pthread_freebsd.odin b/core/sys/unix/pthread_freebsd.odin deleted file mode 100644 index 38fe7db55..000000000 --- a/core/sys/unix/pthread_freebsd.odin +++ /dev/null @@ -1,122 +0,0 @@ -#+build freebsd -package unix - -import "core:c" - -pthread_t :: distinct u64 -// pthread_t :: struct #align(16) { x: u64 } - -PTHREAD_COND_T_SIZE :: 8 - -PTHREAD_MUTEXATTR_T_SIZE :: 8 -PTHREAD_CONDATTR_T_SIZE :: 8 -PTHREAD_RWLOCKATTR_T_SIZE :: 8 -PTHREAD_BARRIERATTR_T_SIZE :: 8 - -// WARNING: The sizes of these things are different yet again -// on non-X86! -when size_of(int) == 8 { - PTHREAD_ATTR_T_SIZE :: 8 - PTHREAD_MUTEX_T_SIZE :: 8 - PTHREAD_RWLOCK_T_SIZE :: 8 - PTHREAD_BARRIER_T_SIZE :: 8 -} else when size_of(int) == 4 { // TODO - PTHREAD_ATTR_T_SIZE :: 32 - PTHREAD_MUTEX_T_SIZE :: 32 - PTHREAD_RWLOCK_T_SIZE :: 44 - PTHREAD_BARRIER_T_SIZE :: 20 -} - -pthread_cond_t :: struct #align(16) { - _: [PTHREAD_COND_T_SIZE] c.char, -} -pthread_mutex_t :: struct #align(16) { - _: [PTHREAD_MUTEX_T_SIZE] c.char, -} -pthread_rwlock_t :: struct #align(16) { - _: [PTHREAD_RWLOCK_T_SIZE] c.char, -} -pthread_barrier_t :: struct #align(16) { - _: [PTHREAD_BARRIER_T_SIZE] c.char, -} - -pthread_attr_t :: struct #align(16) { - _: [PTHREAD_ATTR_T_SIZE] c.char, -} -pthread_condattr_t :: struct #align(16) { - _: [PTHREAD_CONDATTR_T_SIZE] c.char, -} -pthread_mutexattr_t :: struct #align(16) { - _: [PTHREAD_MUTEXATTR_T_SIZE] c.char, -} -pthread_rwlockattr_t :: struct #align(16) { - _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, -} -pthread_barrierattr_t :: struct #align(16) { - _: [PTHREAD_BARRIERATTR_T_SIZE] c.char, -} - -PTHREAD_MUTEX_ERRORCHECK :: 1 -PTHREAD_MUTEX_RECURSIVE :: 2 -PTHREAD_MUTEX_NORMAL :: 3 - - -PTHREAD_CREATE_JOINABLE :: 0 -PTHREAD_CREATE_DETACHED :: 1 -PTHREAD_INHERIT_SCHED :: 4 -PTHREAD_EXPLICIT_SCHED :: 0 -PTHREAD_PROCESS_PRIVATE :: 0 -PTHREAD_PROCESS_SHARED :: 1 - -SCHED_FIFO :: 1 -SCHED_OTHER :: 2 -SCHED_RR :: 3 // Round robin. - - -sched_param :: struct { - sched_priority: c.int, -} - -_usem :: struct { - _has_waiters: u32, - _count: u32, - _flags: u32, -} -_usem2 :: struct { - _count: u32, - _flags: u32, -} -sem_t :: struct { - _magic: u32, - _kern: _usem2, - _padding: u32, -} - -PTHREAD_CANCEL_ENABLE :: 0 -PTHREAD_CANCEL_DISABLE :: 1 -PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 2 - -foreign import "system:pthread" - -@(default_calling_convention="c") -foreign pthread { - // create named semaphore. - // used in process-shared semaphores. - sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t --- - - sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int --- - sem_destroy :: proc(sem: ^sem_t) -> c.int --- - sem_post :: proc(sem: ^sem_t) -> c.int --- - sem_wait :: proc(sem: ^sem_t) -> c.int --- - sem_trywait :: proc(sem: ^sem_t) -> c.int --- - // sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int --- - - // NOTE: unclear whether pthread_yield is well-supported on Linux systems, - // see https://linux.die.net/man/3/pthread_yield - 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 --- -} diff --git a/core/sys/unix/pthread_haiku.odin b/core/sys/unix/pthread_haiku.odin deleted file mode 100644 index 1278f34fe..000000000 --- a/core/sys/unix/pthread_haiku.odin +++ /dev/null @@ -1,71 +0,0 @@ -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 --- -} diff --git a/core/sys/unix/pthread_linux.odin b/core/sys/unix/pthread_linux.odin deleted file mode 100644 index d67add24b..000000000 --- a/core/sys/unix/pthread_linux.odin +++ /dev/null @@ -1,124 +0,0 @@ -#+build linux -package unix - -import "core:c" - -// TODO(tetra): For robustness, I'd like to mark this with align 16. -// I cannot currently do this. -// And at the time of writing there is a bug with putting it -// as the only field in a struct. -pthread_t :: distinct u64 -// pthread_t :: struct #align(16) { x: u64 }; - -// NOTE(tetra): Got all the size constants from pthreadtypes-arch.h on my -// Linux machine. - -PTHREAD_COND_T_SIZE :: 48 - -PTHREAD_MUTEXATTR_T_SIZE :: 4 -PTHREAD_CONDATTR_T_SIZE :: 4 -PTHREAD_RWLOCKATTR_T_SIZE :: 8 -PTHREAD_BARRIERATTR_T_SIZE :: 4 - -// WARNING: The sizes of these things are different yet again -// on non-X86! -when size_of(int) == 8 { - PTHREAD_ATTR_T_SIZE :: 56 - PTHREAD_MUTEX_T_SIZE :: 40 - PTHREAD_RWLOCK_T_SIZE :: 56 - PTHREAD_BARRIER_T_SIZE :: 32 -} else when size_of(int) == 4 { - PTHREAD_ATTR_T_SIZE :: 32 - PTHREAD_MUTEX_T_SIZE :: 32 - PTHREAD_RWLOCK_T_SIZE :: 44 - PTHREAD_BARRIER_T_SIZE :: 20 -} - -pthread_cond_t :: struct #align(16) { - _: [PTHREAD_COND_T_SIZE] c.char, -} -pthread_mutex_t :: struct #align(16) { - _: [PTHREAD_MUTEX_T_SIZE] c.char, -} -pthread_rwlock_t :: struct #align(16) { - _: [PTHREAD_RWLOCK_T_SIZE] c.char, -} -pthread_barrier_t :: struct #align(16) { - _: [PTHREAD_BARRIER_T_SIZE] c.char, -} - -pthread_attr_t :: struct #align(16) { - _: [PTHREAD_ATTR_T_SIZE] c.char, -} -pthread_condattr_t :: struct #align(16) { - _: [PTHREAD_CONDATTR_T_SIZE] c.char, -} -pthread_mutexattr_t :: struct #align(16) { - _: [PTHREAD_MUTEXATTR_T_SIZE] c.char, -} -pthread_rwlockattr_t :: struct #align(16) { - _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, -} -pthread_barrierattr_t :: struct #align(16) { - _: [PTHREAD_BARRIERATTR_T_SIZE] c.char, -} - -PTHREAD_MUTEX_NORMAL :: 0 -PTHREAD_MUTEX_RECURSIVE :: 1 -PTHREAD_MUTEX_ERRORCHECK :: 2 - - -// TODO(tetra, 2019-11-01): Maybe make `enum c.int`s for these? -PTHREAD_CREATE_JOINABLE :: 0 -PTHREAD_CREATE_DETACHED :: 1 -PTHREAD_INHERIT_SCHED :: 0 -PTHREAD_EXPLICIT_SCHED :: 1 -PTHREAD_PROCESS_PRIVATE :: 0 -PTHREAD_PROCESS_SHARED :: 1 - -SCHED_OTHER :: 0 -SCHED_FIFO :: 1 -SCHED_RR :: 2 // Round robin. - -sched_param :: struct { - sched_priority: c.int, -} - -sem_t :: struct #align(16) { - _: [SEM_T_SIZE] c.char, -} - -when size_of(int) == 8 { - SEM_T_SIZE :: 32 -} else when size_of(int) == 4 { - SEM_T_SIZE :: 16 -} - -PTHREAD_CANCEL_ENABLE :: 0 -PTHREAD_CANCEL_DISABLE :: 1 -PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 1 - -foreign import "system:pthread" - -@(default_calling_convention="c") -foreign pthread { - // create named semaphore. - // used in process-shared semaphores. - sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t --- - - sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int --- - sem_destroy :: proc(sem: ^sem_t) -> c.int --- - sem_post :: proc(sem: ^sem_t) -> c.int --- - sem_wait :: proc(sem: ^sem_t) -> c.int --- - sem_trywait :: proc(sem: ^sem_t) -> c.int --- - // sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---; - - // NOTE: unclear whether pthread_yield is well-supported on Linux systems, - // see https://linux.die.net/man/3/pthread_yield - pthread_yield :: proc() -> c.int --- - - 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 --- -} diff --git a/core/sys/unix/pthread_netbsd.odin b/core/sys/unix/pthread_netbsd.odin deleted file mode 100644 index 9107f1139..000000000 --- a/core/sys/unix/pthread_netbsd.odin +++ /dev/null @@ -1,102 +0,0 @@ -package unix - -import "core:c" - -pthread_t :: distinct rawptr - -SEM_T_SIZE :: 8 - -PTHREAD_CONDATTR_T_SIZE :: 16 -PTHREAD_MUTEXATTR_T_SIZE :: 16 -PTHREAD_RWLOCKATTR_T_SIZE :: 16 -PTHREAD_BARRIERATTR_T_SIZE :: 16 - -PTHREAD_COND_T_SIZE :: 40 -PTHREAD_MUTEX_T_SIZE :: 48 -PTHREAD_RWLOCK_T_SIZE :: 64 -PTHREAD_BARRIER_T_SIZE :: 48 -PTHREAD_ATTR_T_SIZE :: 16 - -pthread_cond_t :: struct #align(8) { - _: [PTHREAD_COND_T_SIZE] c.char, -} - -pthread_mutex_t :: struct #align(8) { - _: [PTHREAD_MUTEX_T_SIZE] c.char, -} - -pthread_rwlock_t :: struct #align(8) { - _: [PTHREAD_RWLOCK_T_SIZE] c.char, -} - -pthread_barrier_t :: struct #align(8) { - _: [PTHREAD_BARRIER_T_SIZE] c.char, -} - -pthread_attr_t :: struct #align(8) { - _: [PTHREAD_ATTR_T_SIZE] c.char, -} - -pthread_condattr_t :: struct #align(8) { - _: [PTHREAD_CONDATTR_T_SIZE] c.char, -} - -pthread_mutexattr_t :: struct #align(8) { - _: [PTHREAD_MUTEXATTR_T_SIZE] c.char, -} - -pthread_rwlockattr_t :: struct #align(8) { - _: [PTHREAD_RWLOCKATTR_T_SIZE] c.char, -} - -pthread_barrierattr_t :: struct #align(8) { - _: [PTHREAD_BARRIERATTR_T_SIZE] c.char, -} - -PTHREAD_MUTEX_NORMAL :: 0 -PTHREAD_MUTEX_ERRORCHECK :: 1 -PTHREAD_MUTEX_RECURSIVE :: 2 - -PTHREAD_CREATE_JOINABLE :: 0 -PTHREAD_CREATE_DETACHED :: 1 -PTHREAD_INHERIT_SCHED :: 0 -PTHREAD_EXPLICIT_SCHED :: 1 -PTHREAD_PROCESS_PRIVATE :: 0 -PTHREAD_PROCESS_SHARED :: 1 - -SCHED_NONE :: -1 -SCHED_OTHER :: 0 -SCHED_FIFO :: 1 -SCHED_RR :: 3 - -sched_param :: struct { - sched_priority: c.int, -} - -sem_t :: struct #align(16) { - _: [SEM_T_SIZE] c.char, -} - -PTHREAD_CANCEL_ENABLE :: 0 -PTHREAD_CANCEL_DISABLE :: 1 -PTHREAD_CANCEL_DEFERRED :: 0 -PTHREAD_CANCEL_ASYNCHRONOUS :: 1 - -foreign import "system:pthread" - -@(default_calling_convention="c") -foreign pthread { - 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 --- -} diff --git a/core/sys/unix/pthread_openbsd.odin b/core/sys/unix/pthread_openbsd.odin deleted file mode 100644 index 2c6d9e598..000000000 --- a/core/sys/unix/pthread_openbsd.odin +++ /dev/null @@ -1,74 +0,0 @@ -#+build openbsd -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_ERRORCHECK :: 1 -PTHREAD_MUTEX_RECURSIVE :: 2 -PTHREAD_MUTEX_NORMAL :: 3 -PTHREAD_MUTEX_STRICT_NP :: 4 - -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_OTHER :: 2 -SCHED_RR :: 3 - -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 --- - //sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int --- - - // NOTE: unclear whether pthread_yield is well-supported on Linux systems, - // see https://linux.die.net/man/3/pthread_yield - 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 --- -} diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin deleted file mode 100644 index 43c4866ed..000000000 --- a/core/sys/unix/pthread_unix.odin +++ /dev/null @@ -1,127 +0,0 @@ -#+build linux, darwin, freebsd, openbsd, netbsd, haiku -package unix - -foreign import "system:pthread" - -import "core:c" - -timespec :: struct { - tv_sec: i64, - tv_nsec: i64, -} - -// -// On success, these functions return 0. -// - -@(default_calling_convention="c") -foreign pthread { - pthread_create :: proc(t: ^pthread_t, attrs: ^pthread_attr_t, routine: proc(data: rawptr) -> rawptr, arg: rawptr) -> c.int --- - - // retval is a pointer to a location to put the return value of the thread proc. - pthread_join :: proc(t: pthread_t, retval: ^rawptr) -> c.int --- - - pthread_kill :: proc(t: pthread_t, sig: c.int) -> c.int --- - - pthread_self :: proc() -> pthread_t --- - - pthread_equal :: proc(a, b: pthread_t) -> b32 --- - - pthread_detach :: proc(t: pthread_t) -> c.int --- - - sched_get_priority_min :: proc(policy: c.int) -> c.int --- - sched_get_priority_max :: proc(policy: c.int) -> c.int --- - - // NOTE: POSIX says this can fail with OOM. - pthread_attr_init :: proc(attrs: ^pthread_attr_t) -> c.int --- - - pthread_attr_destroy :: proc(attrs: ^pthread_attr_t) -> c.int --- - - pthread_attr_getschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int --- - pthread_attr_setschedparam :: proc(attrs: ^pthread_attr_t, param: ^sched_param) -> c.int --- - - // states: PTHREAD_CREATE_DETACHED, PTHREAD_CREATE_JOINABLE - pthread_attr_setdetachstate :: proc(attrs: ^pthread_attr_t, detach_state: c.int) -> c.int --- - - // NOTE(tetra, 2019-11-06): WARNING: Different systems have different alignment requirements. - // For maximum usefulness, use the OS's page size. - // ALSO VERY MAJOR WARNING: `stack_ptr` must be the LAST byte of the stack on systems - // where the stack grows downwards, which is the common case, so far as I know. - // On systems where it grows upwards, give the FIRST byte instead. - // ALSO SLIGHTLY LESS MAJOR WARNING: Using this procedure DISABLES automatically-provided - // guard pages. If you are using this procedure, YOU must set them up manually. - // If you forget to do this, you WILL get stack corruption bugs if you do not EXTREMELY - // know what you are doing! - pthread_attr_setstack :: proc(attrs: ^pthread_attr_t, stack_ptr: rawptr, stack_size: u64) -> c.int --- - pthread_attr_getstack :: proc(attrs: ^pthread_attr_t, stack_ptr: ^rawptr, stack_size: ^u64) -> c.int --- - - 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") -foreign pthread { - // NOTE: POSIX says this can fail with OOM. - pthread_cond_init :: proc(cond: ^pthread_cond_t, attrs: ^pthread_condattr_t) -> c.int --- - - pthread_cond_destroy :: proc(cond: ^pthread_cond_t) -> c.int --- - - pthread_cond_signal :: proc(cond: ^pthread_cond_t) -> c.int --- - - // same as signal, but wakes up _all_ threads that are waiting - pthread_cond_broadcast :: proc(cond: ^pthread_cond_t) -> c.int --- - - - // assumes the mutex is pre-locked - pthread_cond_wait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t) -> c.int --- - pthread_cond_timedwait :: proc(cond: ^pthread_cond_t, mutex: ^pthread_mutex_t, timeout: ^timespec) -> c.int --- - - pthread_condattr_init :: proc(attrs: ^pthread_condattr_t) -> c.int --- - pthread_condattr_destroy :: proc(attrs: ^pthread_condattr_t) -> c.int --- - - // p-shared = "process-shared" - i.e: is this condition shared among multiple processes? - // values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED - pthread_condattr_setpshared :: proc(attrs: ^pthread_condattr_t, value: c.int) -> c.int --- - pthread_condattr_getpshared :: proc(attrs: ^pthread_condattr_t, result: ^c.int) -> c.int --- - -} - -@(default_calling_convention="c") -foreign pthread { - // NOTE: POSIX says this can fail with OOM. - pthread_mutex_init :: proc(mutex: ^pthread_mutex_t, attrs: ^pthread_mutexattr_t) -> c.int --- - - pthread_mutex_destroy :: proc(mutex: ^pthread_mutex_t) -> c.int --- - - pthread_mutex_trylock :: proc(mutex: ^pthread_mutex_t) -> c.int --- - - pthread_mutex_lock :: proc(mutex: ^pthread_mutex_t) -> c.int --- - - pthread_mutex_timedlock :: proc(mutex: ^pthread_mutex_t, timeout: ^timespec) -> c.int --- - - pthread_mutex_unlock :: proc(mutex: ^pthread_mutex_t) -> c.int --- - - - pthread_mutexattr_init :: proc(attrs: ^pthread_mutexattr_t) -> c.int --- - pthread_mutexattr_destroy :: proc(attrs: ^pthread_mutexattr_t) -> c.int --- - pthread_mutexattr_settype :: proc(attrs: ^pthread_mutexattr_t, type: c.int) -> c.int --- - - // p-shared = "process-shared" - i.e: is this mutex shared among multiple processes? - // values: PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED - pthread_mutexattr_setpshared :: proc(attrs: ^pthread_mutexattr_t, value: c.int) -> c.int --- - pthread_mutexattr_getpshared :: proc(attrs: ^pthread_mutexattr_t, result: ^c.int) -> c.int --- - - pthread_testcancel :: proc () --- -} diff --git a/core/sys/unix/unix.odin b/core/sys/unix/unix.odin new file mode 100644 index 000000000..0291d0d4a --- /dev/null +++ b/core/sys/unix/unix.odin @@ -0,0 +1,5 @@ +package unix + +import "core:sys/posix" + +timespec :: posix.timespec diff --git a/core/testing/signal_handler_libc.odin b/core/testing/signal_handler_libc.odin index 7442c100c..6b82b59bf 100644 --- a/core/testing/signal_handler_libc.odin +++ b/core/testing/signal_handler_libc.odin @@ -15,7 +15,7 @@ import "core:c/libc" import "core:encoding/ansi" import "core:sync" import "core:os" -@require import "core:sys/unix" +@require import "core:sys/posix" @(private="file") stop_runner_flag: libc.sig_atomic_t @@ -114,8 +114,8 @@ This is a dire bug and should be reported to the Odin developers. // properly set to PTHREAD_CANCEL_ASYNCHRONOUS. // // The runner would stall after returning from `pthread_cancel`. - - unix.pthread_testcancel() + + posix.pthread_testcancel() } } } diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 9576a3040..1e663bc87 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -4,14 +4,14 @@ package thread import "base:runtime" import "core:sync" -import "core:sys/unix" +import "core:sys/posix" _IS_SUPPORTED :: true // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t. Thread_Os_Specific :: struct #align(16) { - unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux. + unix_thread: posix.pthread_t, // NOTE: very large on Darwin, small on Linux. start_ok: sync.Sema, } // @@ -23,7 +23,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { t := (^Thread)(t) // We need to give the thread a moment to start up before we enable cancellation. - can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0 + can_set_thread_cancel_state := posix.pthread_setcancelstate(.ENABLE, nil) == nil t.id = sync.current_thread_id() @@ -37,8 +37,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { // Enable thread's cancelability. if can_set_thread_cancel_state { - unix.pthread_setcanceltype (unix.PTHREAD_CANCEL_ASYNCHRONOUS, nil) - unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) + posix.pthread_setcanceltype (.ASYNCHRONOUS, nil) + posix.pthread_setcancelstate(.ENABLE, nil) } { @@ -59,8 +59,8 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { sync.atomic_or(&t.flags, { .Done }) if .Self_Cleanup in sync.atomic_load(&t.flags) { - res := unix.pthread_detach(t.unix_thread) - assert_contextless(res == 0) + res := posix.pthread_detach(t.unix_thread) + assert_contextless(res == nil) t.unix_thread = {} // NOTE(ftphikari): It doesn't matter which context 'free' received, right? @@ -71,19 +71,19 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { return nil } - attrs: unix.pthread_attr_t - if unix.pthread_attr_init(&attrs) != 0 { + attrs: posix.pthread_attr_t + if posix.pthread_attr_init(&attrs) != nil { return nil // NOTE(tetra, 2019-11-01): POSIX OOM. } - defer unix.pthread_attr_destroy(&attrs) + defer posix.pthread_attr_destroy(&attrs) // NOTE(tetra, 2019-11-01): These only fail if their argument is invalid. - res: i32 - res = unix.pthread_attr_setdetachstate(&attrs, unix.PTHREAD_CREATE_JOINABLE) - assert(res == 0) + res: posix.Errno + res = posix.pthread_attr_setdetachstate(&attrs, .CREATE_JOINABLE) + assert(res == nil) when ODIN_OS != .Haiku && ODIN_OS != .NetBSD { - res = unix.pthread_attr_setinheritsched(&attrs, unix.PTHREAD_EXPLICIT_SCHED) - assert(res == 0) + res = posix.pthread_attr_setinheritsched(&attrs, .EXPLICIT_SCHED) + assert(res == nil) } thread := new(Thread) @@ -93,26 +93,26 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { thread.creation_allocator = context.allocator // Set thread priority. - policy: i32 + policy: posix.Sched_Policy when ODIN_OS != .Haiku && ODIN_OS != .NetBSD { - res = unix.pthread_attr_getschedpolicy(&attrs, &policy) - assert(res == 0) + res = posix.pthread_attr_getschedpolicy(&attrs, &policy) + assert(res == nil) } - params: unix.sched_param - res = unix.pthread_attr_getschedparam(&attrs, ¶ms) - assert(res == 0) - low := unix.sched_get_priority_min(policy) - high := unix.sched_get_priority_max(policy) + params: posix.sched_param + res = posix.pthread_attr_getschedparam(&attrs, ¶ms) + assert(res == nil) + low := posix.sched_get_priority_min(policy) + high := posix.sched_get_priority_max(policy) switch priority { case .Normal: // Okay case .Low: params.sched_priority = low + 1 case .High: params.sched_priority = high } - res = unix.pthread_attr_setschedparam(&attrs, ¶ms) - assert(res == 0) + res = posix.pthread_attr_setschedparam(&attrs, ¶ms) + assert(res == nil) thread.procedure = procedure - if unix.pthread_create(&thread.unix_thread, &attrs, __unix_thread_entry_proc, thread) != 0 { + if posix.pthread_create(&thread.unix_thread, &attrs, __unix_thread_entry_proc, thread) != nil { free(thread, thread.creation_allocator) return nil } @@ -130,7 +130,7 @@ _is_done :: proc(t: ^Thread) -> bool { } _join :: proc(t: ^Thread) { - if unix.pthread_equal(unix.pthread_self(), t.unix_thread) { + if posix.pthread_equal(posix.pthread_self(), t.unix_thread) { return } @@ -144,7 +144,7 @@ _join :: proc(t: ^Thread) { if .Started not_in sync.atomic_load(&t.flags) { _start(t) } - unix.pthread_join(t.unix_thread, nil) + posix.pthread_join(t.unix_thread, nil) } _join_multiple :: proc(threads: ..^Thread) { @@ -170,9 +170,9 @@ _terminate :: proc(t: ^Thread, exit_code: int) { // // This is in contrast to behavior I have seen on Linux where the thread is // just terminated. - unix.pthread_cancel(t.unix_thread) + posix.pthread_cancel(t.unix_thread) } _yield :: proc() { - unix.sched_yield() + posix.sched_yield() } From 0b4a4212bbd156ab8c2ce3345feb1d9ef859b629 Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 19:21:16 +0100 Subject: [PATCH 14/21] clean up dynlib and path/filepath with sys/posix --- core/dynlib/lib.odin | 10 ++++----- core/dynlib/lib_js.odin | 8 ++++--- core/dynlib/lib_unix.odin | 30 ++++++++++++++++--------- core/dynlib/lib_windows.odin | 8 ++++--- core/path/filepath/path_unix.odin | 37 +++++-------------------------- 5 files changed, 40 insertions(+), 53 deletions(-) diff --git a/core/dynlib/lib.odin b/core/dynlib/lib.odin index 09e16002d..84675a560 100644 --- a/core/dynlib/lib.odin +++ b/core/dynlib/lib.odin @@ -37,8 +37,8 @@ Example: fmt.println("The library %q was successfully loaded", LIBRARY_PATH) } */ -load_library :: proc(path: string, global_symbols := false) -> (library: Library, did_load: bool) { - return _load_library(path, global_symbols) +load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (library: Library, did_load: bool) { + return _load_library(path, global_symbols, allocator) } /* @@ -98,8 +98,8 @@ Example: } } */ -symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) #optional_ok { - return _symbol_address(library, symbol) +symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) #optional_ok { + return _symbol_address(library, symbol, allocator) } /* @@ -174,4 +174,4 @@ initialize_symbols :: proc( // Returns an error message for the last failed procedure call. last_error :: proc() -> string { return _last_error() -} \ No newline at end of file +} diff --git a/core/dynlib/lib_js.odin b/core/dynlib/lib_js.odin index 698cfee9c..b99143ba0 100644 --- a/core/dynlib/lib_js.odin +++ b/core/dynlib/lib_js.odin @@ -2,7 +2,9 @@ #+private package dynlib -_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { +import "base:runtime" + +_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { return nil, false } @@ -10,10 +12,10 @@ _unload_library :: proc(library: Library) -> bool { return false } -_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { +_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) { return nil, false } _last_error :: proc() -> string { return "" -} \ No newline at end of file +} diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin index f467d730d..337bf496d 100644 --- a/core/dynlib/lib_unix.odin +++ b/core/dynlib/lib_unix.odin @@ -2,28 +2,38 @@ #+private package dynlib -import "core:os" +import "base:runtime" -_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) { - flags := os.RTLD_NOW +import "core:strings" +import "core:sys/posix" + +_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { + flags := posix.RTLD_Flags{.NOW} if global_symbols { - flags |= os.RTLD_GLOBAL + flags += {.GLOBAL} } - lib := os.dlopen(path, flags) + + cpath := strings.clone_to_cstring(path, allocator) + defer delete(cpath, allocator) + + lib := posix.dlopen(cpath, flags) return Library(lib), lib != nil } _unload_library :: proc(library: Library) -> bool { - return os.dlclose(rawptr(library)) + return posix.dlclose(posix.Symbol_Table(library)) == 0 } -_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) { - ptr = os.dlsym(rawptr(library), symbol) +_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) { + csymbol := strings.clone_to_cstring(symbol, allocator) + defer delete(csymbol, allocator) + + ptr = posix.dlsym(posix.Symbol_Table(library), csymbol) found = ptr != nil return } _last_error :: proc() -> string { - err := os.dlerror() + err := string(posix.dlerror()) return "unknown" if err == "" else err -} \ No newline at end of file +} diff --git a/core/dynlib/lib_windows.odin b/core/dynlib/lib_windows.odin index 6c41a1a75..928a1510d 100644 --- a/core/dynlib/lib_windows.odin +++ b/core/dynlib/lib_windows.odin @@ -2,11 +2,13 @@ #+private package dynlib +import "base:runtime" + import win32 "core:sys/windows" import "core:strings" import "core:reflect" -_load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (Library, bool) { +_load_library :: proc(path: string, global_symbols: bool, allocator: runtime.Allocator) -> (Library, bool) { // NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL wide_path := win32.utf8_to_wstring(path, allocator) defer free(wide_path, allocator) @@ -19,7 +21,7 @@ _unload_library :: proc(library: Library) -> bool { return bool(ok) } -_symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) { +_symbol_address :: proc(library: Library, symbol: string, allocator: runtime.Allocator) -> (ptr: rawptr, found: bool) { c_str := strings.clone_to_cstring(symbol, allocator) defer delete(c_str, allocator) ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str) @@ -31,4 +33,4 @@ _last_error :: proc() -> string { err := win32.System_Error(win32.GetLastError()) err_msg := reflect.enum_string(err) return "unknown" if err_msg == "" else err_msg -} \ No newline at end of file +} diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin index a18dc739e..35b98a7ae 100644 --- a/core/path/filepath/path_unix.odin +++ b/core/path/filepath/path_unix.odin @@ -1,14 +1,10 @@ #+build linux, darwin, freebsd, openbsd, netbsd package filepath -when ODIN_OS == .Darwin { - foreign import libc "system:System.framework" -} else { - foreign import libc "system:c" -} - import "base:runtime" + import "core:strings" +import "core:sys/posix" SEPARATOR :: '/' SEPARATOR_STRING :: `/` @@ -28,11 +24,11 @@ abs :: proc(path: string, allocator := context.allocator) -> (string, bool) { rel = "." } rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator) - path_ptr := realpath(rel_cstr, nil) + path_ptr := posix.realpath(rel_cstr, nil) if path_ptr == nil { - return "", __error()^ == 0 + return "", posix.errno() == nil } - defer _unix_free(rawptr(path_ptr)) + defer posix.free(path_ptr) path_str := strings.clone(string(path_ptr), allocator) return path_str, true @@ -48,26 +44,3 @@ join :: proc(elems: []string, allocator := context.allocator) -> (joined: string } return "", nil } - -@(private) -foreign libc { - realpath :: proc(path: cstring, resolved_path: [^]byte = nil) -> cstring --- - @(link_name="free") _unix_free :: proc(ptr: rawptr) --- - -} -when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD { - @(private) - foreign libc { - @(link_name="__error") __error :: proc() -> ^i32 --- - } -} else when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD { - @(private) - foreign libc { - @(link_name="__errno") __error :: proc() -> ^i32 --- - } -} else { - @(private) - foreign libc { - @(link_name="__errno_location") __error :: proc() -> ^i32 --- - } -} From b7140875cfb3b699fc26001936a8974b71b6aafb Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 19:42:27 +0100 Subject: [PATCH 15/21] port pthread_mutex_t and pthread_cond_t from sys/unix cause miniaudio wants it --- core/sys/posix/pthread.odin | 48 ++++++++++++++++++++++++++++--- vendor/miniaudio/common_unix.odin | 14 ++++----- 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 6e894117a..8bad71f57 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -399,6 +399,16 @@ when ODIN_OS == .Darwin { pthread_key_t :: distinct c.ulong + pthread_mutex_t :: struct { + __sig: c.long, + __opaque: [56]c.char, + } + + pthread_cond_t :: struct { + __sig: c.long, + __opaque: [40]c.char, + } + sched_param :: struct { sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ _: [4]c.char, @@ -432,10 +442,20 @@ when ODIN_OS == .Darwin { pthread_t :: distinct u64 - pthread_attr_t :: distinct rawptr + pthread_attr_t :: struct #align(16) { + _: [8]byte, + } pthread_key_t :: distinct c.int + pthread_mutex_t :: struct #align(16) { + _: [8]byte, + } + + pthread_cond_t :: struct #align(16) { + _: [8]byte, + } + sched_param :: struct { sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ } @@ -476,6 +496,14 @@ when ODIN_OS == .Darwin { pthread_key_t :: distinct c.int + pthread_cond_t :: struct #align(8) { + _: [40]byte, + } + + pthread_mutex_t :: struct #align(8) { + _: [48]byte, + } + sched_param :: struct { sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ } @@ -506,9 +534,11 @@ when ODIN_OS == .Darwin { PTHREAD_SCOPE_PROCESS :: 0 PTHREAD_SCOPE_SYSTEM :: 0x2 - pthread_t :: distinct rawptr - pthread_attr_t :: distinct rawptr - pthread_key_t :: distinct c.int + pthread_t :: distinct rawptr + pthread_attr_t :: distinct rawptr + pthread_key_t :: distinct c.int + pthread_mutex_t :: distinct rawptr + pthread_cond_t :: distinct rawptr sched_param :: struct { sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ @@ -549,6 +579,16 @@ when ODIN_OS == .Darwin { pthread_key_t :: distinct c.uint + pthread_cond_t :: struct { + __size: [40]c.char, // NOTE: may be smaller depending on libc or arch, but never larger. + __align: c.long, + } + + pthread_mutex_t :: struct { + __size: [32]c.char, // NOTE: may be smaller depending on libc or arch, but never larger. + __align: c.long, + } + sched_param :: struct { sched_priority: c.int, /* [PSX] process or thread execution scheduling priority */ diff --git a/vendor/miniaudio/common_unix.odin b/vendor/miniaudio/common_unix.odin index 8afcc0b5a..1c0158404 100644 --- a/vendor/miniaudio/common_unix.odin +++ b/vendor/miniaudio/common_unix.odin @@ -1,18 +1,18 @@ #+build !windows package miniaudio -import "core:sys/unix" +import "core:sys/posix" import "core:c" -thread :: unix.pthread_t -mutex :: unix.pthread_mutex_t +thread :: posix.pthread_t +mutex :: posix.pthread_mutex_t event :: struct { value: u32, - lock: unix.pthread_mutex_t, - cond: unix.pthread_cond_t, + lock: posix.pthread_mutex_t, + cond: posix.pthread_cond_t, } semaphore :: struct { value: c.int, - lock: unix.pthread_mutex_t, - cond: unix.pthread_cond_t, + lock: posix.pthread_mutex_t, + cond: posix.pthread_cond_t, } From 7e12e37df900e2264a45d65574cda30b9faeedeb Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 19:45:31 +0100 Subject: [PATCH 16/21] fix test --- core/sys/posix/pthread.odin | 6 +++--- core/sys/unix/unix.odin | 7 +++++-- tests/core/sys/posix/posix.odin | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/core/sys/posix/pthread.odin b/core/sys/posix/pthread.odin index 8bad71f57..9391a6359 100644 --- a/core/sys/posix/pthread.odin +++ b/core/sys/posix/pthread.odin @@ -442,17 +442,17 @@ when ODIN_OS == .Darwin { pthread_t :: distinct u64 - pthread_attr_t :: struct #align(16) { + pthread_attr_t :: struct #align(8) { _: [8]byte, } pthread_key_t :: distinct c.int - pthread_mutex_t :: struct #align(16) { + pthread_mutex_t :: struct #align(8) { _: [8]byte, } - pthread_cond_t :: struct #align(16) { + pthread_cond_t :: struct #align(8) { _: [8]byte, } diff --git a/core/sys/unix/unix.odin b/core/sys/unix/unix.odin index 0291d0d4a..e9f58e554 100644 --- a/core/sys/unix/unix.odin +++ b/core/sys/unix/unix.odin @@ -1,5 +1,8 @@ package unix -import "core:sys/posix" +import "core:c" -timespec :: posix.timespec +timespec :: struct { + secs: i64, + nsecs: c.long, +} diff --git a/tests/core/sys/posix/posix.odin b/tests/core/sys/posix/posix.odin index c215747e4..8daffc5b9 100644 --- a/tests/core/sys/posix/posix.odin +++ b/tests/core/sys/posix/posix.odin @@ -196,7 +196,7 @@ test_stat :: proc(t: ^testing.T) { stat: posix.stat_t testing.expect_value(t, posix.stat(#file, &stat), posix.result.OK) testing.expect(t, posix.S_ISREG(stat.st_mode)) - testing.expect_value(t, stat.st_mode, posix.mode_t{.IROTH, .IRGRP, .IRUSR, .IWGRP, .IWUSR, .IFREG}) + testing.expect_value(t, stat.st_mode, posix.mode_t{.IROTH, .IRGRP, .IRUSR, .IWUSR, .IFREG}) CONTENT := #load(#file) testing.expect_value(t, stat.st_size, posix.off_t(len(CONTENT))) From cb2768625affdd8ec4ee8c0df3b902f40ae620e3 Mon Sep 17 00:00:00 2001 From: Laytan Date: Mon, 28 Oct 2024 20:07:38 +0100 Subject: [PATCH 17/21] math/rand: `choice_bit_set` return `not_empty` -> `ok` --- core/math/rand/rand.odin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/math/rand/rand.odin b/core/math/rand/rand.odin index a8f274204..474277e84 100644 --- a/core/math/rand/rand.odin +++ b/core/math/rand/rand.odin @@ -695,8 +695,8 @@ Inputs: - set: The `bit_set` to choose a random set bit from Returns: -- res: The randomly selected bit, or the zero value if `not_empty` is `false` -- not_empty: Whether the bit_set was not empty and thus `res` is actually a random set bit +- res: The randomly selected bit, or the zero value if `ok` is `false` +- ok: Whether the bit_set was not empty and thus `res` is actually a random set bit Example: import "core:math/rand" @@ -722,7 +722,7 @@ Possible Output: 5 true */ @(require_results) -choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, not_empty: bool) { +choice_bit_set :: proc(set: $T/bit_set[$E], gen := context.random_generator) -> (res: E, ok: bool) { total_set := card(set) if total_set == 0 { return {}, false From 31d5bc48a7f619f112e66e8cf49057f0811fac69 Mon Sep 17 00:00:00 2001 From: Alexis Caraballo Date: Tue, 29 Oct 2024 01:50:38 -0300 Subject: [PATCH 18/21] fix cbor.to_json always returning array of tuples for objects to_json uses a small proc to check if all keys of an object are strings. It was always returning false for any input. --- core/encoding/cbor/cbor.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/encoding/cbor/cbor.odin b/core/encoding/cbor/cbor.odin index 692be0020..8eb829ed3 100644 --- a/core/encoding/cbor/cbor.odin +++ b/core/encoding/cbor/cbor.odin @@ -563,7 +563,7 @@ to_json :: proc(val: Value, allocator := context.allocator) -> (json.Value, mem. case: return false } } - return false + return true } if keys_all_strings(v) { From 28a3a68dc917cd066328f069a6faf969d51011fd Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 29 Oct 2024 09:55:27 +0100 Subject: [PATCH 19/21] Fix image.which_bytes Invert test in `which_bytes` to fix Softimage PIC detection. Fixes #4429. --- core/image/general.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/image/general.odin b/core/image/general.odin index f12b6410b..c4a884071 100644 --- a/core/image/general.odin +++ b/core/image/general.odin @@ -193,7 +193,7 @@ which_bytes :: proc(data: []byte) -> Which_File_Type { return .HDR case s[:4] == "\x38\x42\x50\x53": return .PSD - case s[:4] != "\x53\x80\xF6\x34" && s[88:92] == "PICT": + case s[:4] == "\x53\x80\xF6\x34" && s[88:92] == "PICT": return .PIC case s[:4] == "\x69\x63\x6e\x73": return .ICNS From b46b34228e01d7c85f01140529f083743aaa0e8f Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 29 Oct 2024 13:59:11 +0100 Subject: [PATCH 20/21] match_exact_value: return when type is compound fixes #4431 --- src/exact_value.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/exact_value.cpp b/src/exact_value.cpp index 1a42a82a9..5d6016ecc 100644 --- a/src/exact_value.cpp +++ b/src/exact_value.cpp @@ -687,6 +687,7 @@ gb_internal void match_exact_values(ExactValue *x, ExactValue *y) { case ExactValue_String: case ExactValue_Quaternion: case ExactValue_Pointer: + case ExactValue_Compound: case ExactValue_Procedure: case ExactValue_Typeid: return; From 36b958c1204a6ce28d5dc3b3173641b9ef79e3e3 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Wed, 30 Oct 2024 11:09:46 +0100 Subject: [PATCH 21/21] Fix for using utf8string.at with last rune index returning wrong rune. --- core/unicode/utf8/utf8string/string.odin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/unicode/utf8/utf8string/string.odin b/core/unicode/utf8/utf8string/string.odin index 431939efe..4b0fe7241 100644 --- a/core/unicode/utf8/utf8string/string.odin +++ b/core/unicode/utf8/utf8string/string.odin @@ -66,7 +66,7 @@ at :: proc(s: ^String, i: int, loc := #caller_location) -> (r: rune) { return case s.rune_count-1: - r, s.width = utf8.decode_rune_in_string(s.contents) + r, s.width = utf8.decode_last_rune(s.contents) s.rune_pos = i s.byte_pos = _len(s.contents) - s.width return