Browse Source

Merge pull request #4427 from laytan/posix-additions

Finish sys/posix with Linux and partial Windows support & clean up other packages as a result
gingerBill 9 months ago
parent
commit
ee76acd665
80 changed files with 1372 additions and 1601 deletions
  1. 2 2
      core/c/libc/README.md
  2. 133 0
      core/c/libc/locale.odin
  3. 5 5
      core/dynlib/lib.odin
  4. 5 3
      core/dynlib/lib_js.odin
  5. 20 10
      core/dynlib/lib_unix.odin
  6. 5 3
      core/dynlib/lib_windows.odin
  7. 1 1
      core/os/os_linux.odin
  8. 5 32
      core/path/filepath/path_unix.odin
  9. 1 0
      core/sys/posix/arpa_inet.odin
  10. 1 2
      core/sys/posix/dirent.odin
  11. 1 2
      core/sys/posix/dlfcn.odin
  12. 80 2
      core/sys/posix/errno.odin
  13. 3 4
      core/sys/posix/fcntl.odin
  14. 1 2
      core/sys/posix/fnmatch.odin
  15. 1 2
      core/sys/posix/glob.odin
  16. 1 2
      core/sys/posix/grp.odin
  17. 1 0
      core/sys/posix/iconv.odin
  18. 1 0
      core/sys/posix/langinfo.odin
  19. 8 0
      core/sys/posix/libgen.odin
  20. 1 2
      core/sys/posix/limits.odin
  21. 6 126
      core/sys/posix/locale.odin
  22. 1 0
      core/sys/posix/monetary.odin
  23. 1 2
      core/sys/posix/net_if.odin
  24. 1 2
      core/sys/posix/netdb.odin
  25. 6 2
      core/sys/posix/netinet_in.odin
  26. 1 2
      core/sys/posix/netinet_tcp.odin
  27. 1 3
      core/sys/posix/poll.odin
  28. 3 0
      core/sys/posix/posix.odin
  29. 46 7
      core/sys/posix/pthread.odin
  30. 13 2
      core/sys/posix/pwd.odin
  31. 1 2
      core/sys/posix/sched.odin
  32. 1 5
      core/sys/posix/setjmp.odin
  33. 11 0
      core/sys/posix/setjmp_libc.odin
  34. 2 109
      core/sys/posix/signal.odin
  35. 145 0
      core/sys/posix/signal_libc.odin
  36. 8 165
      core/sys/posix/stdio.odin
  37. 207 0
      core/sys/posix/stdio_libc.odin
  38. 1 78
      core/sys/posix/stdlib.odin
  39. 101 0
      core/sys/posix/stdlib_libc.odin
  40. 1 14
      core/sys/posix/string.odin
  41. 30 0
      core/sys/posix/string_libc.odin
  42. 1 2
      core/sys/posix/sys_ipc.odin
  43. 1 2
      core/sys/posix/sys_mman.odin
  44. 21 2
      core/sys/posix/sys_msg.odin
  45. 1 2
      core/sys/posix/sys_resource.odin
  46. 2 3
      core/sys/posix/sys_select.odin
  47. 1 2
      core/sys/posix/sys_sem.odin
  48. 21 2
      core/sys/posix/sys_shm.odin
  49. 5 5
      core/sys/posix/sys_socket.odin
  50. 120 67
      core/sys/posix/sys_stat.odin
  51. 24 2
      core/sys/posix/sys_statvfs.odin
  52. 1 2
      core/sys/posix/sys_time.odin
  53. 1 2
      core/sys/posix/sys_times.odin
  54. 1 2
      core/sys/posix/sys_uio.odin
  55. 1 2
      core/sys/posix/sys_un.odin
  56. 17 10
      core/sys/posix/sys_utsname.odin
  57. 51 2
      core/sys/posix/sys_wait.odin
  58. 8 9
      core/sys/posix/termios.odin
  59. 13 2
      core/sys/posix/time.odin
  60. 1 2
      core/sys/posix/ulimit.odin
  61. 2 110
      core/sys/posix/unistd.odin
  62. 153 0
      core/sys/posix/unistd_libc.odin
  63. 1 2
      core/sys/posix/utime.odin
  64. 1 2
      core/sys/posix/wordexp.odin
  65. 0 96
      core/sys/unix/pthread_darwin.odin
  66. 0 122
      core/sys/unix/pthread_freebsd.odin
  67. 0 71
      core/sys/unix/pthread_haiku.odin
  68. 0 124
      core/sys/unix/pthread_linux.odin
  69. 0 102
      core/sys/unix/pthread_netbsd.odin
  70. 0 74
      core/sys/unix/pthread_openbsd.odin
  71. 0 127
      core/sys/unix/pthread_unix.odin
  72. 8 0
      core/sys/unix/unix.odin
  73. 3 3
      core/testing/signal_handler_libc.odin
  74. 30 30
      core/thread/thread_unix.odin
  75. 4 0
      src/check_builtin.cpp
  76. 1 14
      tests/core/sys/posix/posix.odin
  77. 1 1
      tests/core/sys/posix/structs.odin
  78. 2 0
      tests/core/sys/posix/structs/structs.c
  79. 5 1
      tests/core/sys/posix/structs/structs.odin
  80. 7 7
      vendor/miniaudio/common_unix.odin

+ 2 - 2
core/c/libc/README.md

@@ -14,7 +14,7 @@ The following is a mostly-complete projection of the C11 standard library as def
 | `<inttypes.h>`    | Fully projected                                    |
 | `<iso646.h>`      | Not applicable, use Odin's operators               |
 | `<limits.h>`      | Not projected                                      |
-| `<locale.h>`      | Not projected                                      |
+| `<locale.h>`      | Fully projected                                    |
 | `<math.h>`        | Mostly projected, see [limitations](#Limitations)  |
 | `<setjmp.h>`      | Fully projected                                    |
 | `<signal.h>`      | Fully projected                                    |
@@ -70,4 +70,4 @@ with the following copyright.
 
 ```
 Copyright 2021 Dale Weiler <[email protected]>.
-```
+```

+ 133 - 0
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
+
+}

+ 5 - 5
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()
-}
+}

+ 5 - 3
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 ""
-}
+}

+ 20 - 10
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
-}
+}

+ 5 - 3
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
-}
+}

+ 1 - 1
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 ---

+ 5 - 32
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 ---
-	}
-}

+ 1 - 0
core/sys/posix/arpa_inet.odin

@@ -1,3 +1,4 @@
+#+build darwin, linux, freebsd, openbsd, netbsd
 package posix
 
 import "core:c"

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }
 

+ 80 - 2
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
 }
 

+ 3 - 4
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")
 }

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 1 - 0
core/sys/posix/iconv.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 
 import "core:c"

+ 1 - 0
core/sys/posix/langinfo.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 
 import "core:c"

+ 8 - 0
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"
+}

+ 1 - 2
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")
 }

+ 6 - 126
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

+ 1 - 0
core/sys/posix/monetary.odin

@@ -1,3 +1,4 @@
+#+build linux, darwin, netbsd, openbsd, freebsd
 package posix
 
 import "core:c"

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 6 - 2
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")
 }

+ 1 - 2
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")
 }

+ 1 - 3
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")
 }
-

+ 3 - 0
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:

+ 46 - 7
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"
@@ -398,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,
@@ -431,10 +442,20 @@ when ODIN_OS == .Darwin {
 
 	pthread_t :: distinct u64
 
-	pthread_attr_t :: distinct rawptr
+	pthread_attr_t :: struct #align(8) {
+		_: [8]byte,
+	}
 
 	pthread_key_t :: distinct c.int
 
+	pthread_mutex_t :: struct #align(8) {
+		_: [8]byte,
+	}
+
+	pthread_cond_t  :: struct #align(8) {
+		_: [8]byte,
+	}
+
 	sched_param :: struct {
 		sched_priority: c.int,     /* [PSX] process or thread execution scheduling priority */
 	}
@@ -475,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 */
 	}
@@ -505,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 */
@@ -548,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 */
 
@@ -557,6 +598,4 @@ when ODIN_OS == .Darwin {
 		__reserved3: c.int,
 	}
 
-} else {
-	#panic("posix is unimplemented for the current target")
 }

+ 13 - 2
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.  */
+	}
+
 }

+ 1 - 2
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")
 }

+ 1 - 5
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"

+ 11 - 0
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

+ 2 - 109
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")
 }

+ 145 - 0
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
+}

+ 8 - 165
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/"
+
 }

+ 207 - 0
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

+ 1 - 78
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"

+ 101 - 0
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"
+}

+ 1 - 14
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())
-}

+ 30 - 0
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())
+}

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 21 - 2
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,
+	}
+
 }

+ 1 - 2
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")
 }

+ 2 - 3
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")
 }

+ 1 - 2
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")
 }

+ 21 - 2
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,
+	}
 }

+ 5 - 5
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")
 }
-

+ 120 - 67
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,
+		}
+	}
 }

+ 24 - 2
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
 }

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 17 - 10
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"`,
+	}
 }

+ 51 - 2
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
+	}
 }

+ 8 - 9
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")
 }

+ 13 - 2
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
+	}
 }

+ 1 - 2
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")
 }

+ 2 - 110
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")
 }
-

+ 153 - 0
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)
+}

+ 1 - 2
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")
 }

+ 1 - 2
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")
 }

+ 0 - 96
core/sys/unix/pthread_darwin.odin

@@ -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 ---
-}

+ 0 - 122
core/sys/unix/pthread_freebsd.odin

@@ -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 ---
-}

+ 0 - 71
core/sys/unix/pthread_haiku.odin

@@ -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 ---
-}

+ 0 - 124
core/sys/unix/pthread_linux.odin

@@ -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 ---
-}

+ 0 - 102
core/sys/unix/pthread_netbsd.odin

@@ -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 ---
-}

+ 0 - 74
core/sys/unix/pthread_openbsd.odin

@@ -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 ---
-}

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

@@ -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 () ---
-}

+ 8 - 0
core/sys/unix/unix.odin

@@ -0,0 +1,8 @@
+package unix
+
+import "core:c"
+
+timespec :: struct {
+	secs:  i64,
+	nsecs: c.long,
+}

+ 3 - 3
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()
 			}
 		}
 	}

+ 30 - 30
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, &params)
-	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, &params)
+	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, &params)
-	assert(res == 0)
+	res = posix.pthread_attr_setschedparam(&attrs, &params)
+	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()
 }

+ 4 - 0
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 {

+ 1 - 14
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" },
@@ -203,18 +202,6 @@ test_stat :: proc(t: ^testing.T) {
 	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)

+ 1 - 1
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"

+ 2 - 0
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));
 

+ 5 - 1
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))
 	

+ 7 - 7
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,
 }