Merge pull request #4427 from laytan/posix-additions

Finish sys/posix with Linux and partial Windows support & clean up other packages as a result
This commit is contained in:
gingerBill
2024-10-30 11:43:47 +00:00
committed by GitHub
80 changed files with 1372 additions and 1601 deletions

View File

@@ -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 <weilercdale@gmail.com>.
```
```

133
core/c/libc/locale.odin Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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. */
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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"`,
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
core/sys/unix/unix.odin Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
#+build darwin, freebsd, openbsd, netbsd
#+build linux, darwin, freebsd, openbsd, netbsd
package tests_core_posix
import "core:log"

View File

@@ -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));

View File

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

View File

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