aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml3
-rw-r--r--Makefile14
-rw-r--r--core/c/libc/errno.odin13
-rw-r--r--core/c/libc/stdio.odin25
-rw-r--r--core/c/libc/time.odin9
-rw-r--r--core/c/libc/wctype.odin5
-rw-r--r--core/crypto/rand_generic.odin2
-rw-r--r--core/crypto/rand_openbsd.odin12
-rw-r--r--core/dynlib/lib_unix.odin2
-rw-r--r--core/os/dir_openbsd.odin71
-rw-r--r--core/os/os_openbsd.odin706
-rw-r--r--core/os/stat_unix.odin2
-rw-r--r--core/path/filepath/path_unix.odin7
-rw-r--r--core/runtime/entry_unix.odin2
-rw-r--r--core/sync/channel_unix.odin2
-rw-r--r--core/sync/sync2/futex_openbsd.odin78
-rw-r--r--core/sync/sync2/primitives_openbsd.odin9
-rw-r--r--core/sync/sync2/primitives_pthreads.odin2
-rw-r--r--core/sync/sync_openbsd.odin36
-rw-r--r--core/sync/sync_unix.odin2
-rw-r--r--core/sys/unix/pthread_openbsd.odin65
-rw-r--r--core/sys/unix/pthread_unix.odin2
-rw-r--r--core/thread/thread_unix.odin2
-rw-r--r--core/time/time_unix.odin34
-rw-r--r--src/bug_report.cpp23
-rw-r--r--src/build_settings.cpp51
-rw-r--r--src/check_builtin.cpp1
-rw-r--r--src/checker.cpp1
-rw-r--r--src/common.cpp2
-rw-r--r--src/gb/gb.h88
-rw-r--r--src/threading.cpp2
-rw-r--r--tests/vendor/Makefile9
-rw-r--r--vendor/botan/bindings/botan.odin4
33 files changed, 1250 insertions, 36 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c62fcd36b..788c59311 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -38,6 +38,9 @@ jobs:
cd tests/vendor
make
timeout-minutes: 10
+ - name: Odin check examples/all for OpenBSD amd64
+ run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
+ timeout-minutes: 10
build_macOS:
runs-on: macos-latest
steps:
diff --git a/Makefile b/Makefile
index 7f1b07f6d..ceff3c207 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
GIT_SHA=$(shell git rev-parse --short HEAD)
DISABLED_WARNINGS=-Wno-switch -Wno-macro-redefined -Wno-unused-value
-LDFLAGS=-pthread -ldl -lm -lstdc++
+LDFLAGS=-pthread -lm -lstdc++
CFLAGS=-std=c++14 -DGIT_SHA=\"$(GIT_SHA)\"
CFLAGS:=$(CFLAGS) -DODIN_VERSION_RAW=\"dev-$(shell date +"%Y-%m")\"
CC=clang
@@ -8,7 +8,7 @@ CC=clang
OS=$(shell uname)
ifeq ($(OS), Darwin)
-
+
ARCH=$(shell uname -m)
LLVM_CONFIG=llvm-config
@@ -35,7 +35,7 @@ ifeq ($(OS), Darwin)
endif
endif
- LDFLAGS:=$(LDFLAGS) -liconv
+ LDFLAGS:=$(LDFLAGS) -liconv -ldl
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) -lLLVM-C
endif
@@ -51,6 +51,14 @@ ifeq ($(OS), Linux)
endif
endif
+ LDFLAGS:=$(LDFLAGS) -ldl
+ CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
+ LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
+endif
+ifeq ($(OS), OpenBSD)
+ LLVM_CONFIG=/usr/local/bin/llvm-config
+
+ LDFLAGS:=$(LDFLAGS) -liconv
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
endif
diff --git a/core/c/libc/errno.odin b/core/c/libc/errno.odin
index ecde6af59..53437f42f 100644
--- a/core/c/libc/errno.odin
+++ b/core/c/libc/errno.odin
@@ -27,6 +27,19 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD {
ERANGE :: 34
}
+when ODIN_OS == .OpenBSD {
+ @(private="file")
+ @(default_calling_convention="c")
+ foreign libc {
+ @(link_name="__errno")
+ _get_errno :: proc() -> ^int ---
+ }
+
+ EDOM :: 33
+ EILSEQ :: 84
+ ERANGE :: 34
+}
+
when ODIN_OS == .Windows {
@(private="file")
@(default_calling_convention="c")
diff --git a/core/c/libc/stdio.odin b/core/c/libc/stdio.odin
index 9c4a1a708..fc65b954a 100644
--- a/core/c/libc/stdio.odin
+++ b/core/c/libc/stdio.odin
@@ -78,6 +78,31 @@ when ODIN_OS == .Linux {
}
}
+when ODIN_OS == .OpenBSD {
+ fpos_t :: i64
+
+ _IOFBF :: 0
+ _IOLBF :: 1
+ _IONBF :: 1
+
+ BUFSIZ :: 1024
+
+ EOF :: int(-1)
+
+ FOPEN_MAX :: 20
+ FILENAME_MAX :: 1024
+
+ SEEK_SET :: 0
+ SEEK_CUR :: 1
+ SEEK_END :: 2
+
+ foreign libc {
+ stderr: ^FILE
+ stdin: ^FILE
+ stdout: ^FILE
+ }
+}
+
when ODIN_OS == .Darwin {
fpos_t :: distinct i64
diff --git a/core/c/libc/time.odin b/core/c/libc/time.odin
index b3539a227..b337e139a 100644
--- a/core/c/libc/time.odin
+++ b/core/c/libc/time.odin
@@ -45,7 +45,7 @@ when ODIN_OS == .Windows {
}
}
-when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin {
+when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS == .OpenBSD {
@(default_calling_convention="c")
foreign libc {
// 7.27.2 Time manipulation functions
@@ -63,7 +63,12 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin {
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
}
- CLOCKS_PER_SEC :: 1000000
+ when ODIN_OS == .OpenBSD {
+ CLOCKS_PER_SEC :: 100
+ } else {
+ CLOCKS_PER_SEC :: 1000000
+ }
+
TIME_UTC :: 1
time_t :: distinct i64
diff --git a/core/c/libc/wctype.odin b/core/c/libc/wctype.odin
index 942726ba6..f833af51f 100644
--- a/core/c/libc/wctype.odin
+++ b/core/c/libc/wctype.odin
@@ -25,6 +25,11 @@ when ODIN_OS == .Darwin {
wctype_t :: distinct u32
}
+when ODIN_OS == .OpenBSD {
+ wctrans_t :: distinct rawptr
+ wctype_t :: distinct rawptr
+}
+
@(default_calling_convention="c")
foreign libc {
// 7.30.2.1 Wide character classification functions
diff --git a/core/crypto/rand_generic.odin b/core/crypto/rand_generic.odin
index be6987ee2..10edc1c8a 100644
--- a/core/crypto/rand_generic.odin
+++ b/core/crypto/rand_generic.odin
@@ -1,6 +1,6 @@
package crypto
-when ODIN_OS != .Linux {
+when ODIN_OS != .Linux && ODIN_OS != .OpenBSD {
_rand_bytes :: proc (dst: []byte) {
unimplemented("crypto: rand_bytes not supported on this OS")
}
diff --git a/core/crypto/rand_openbsd.odin b/core/crypto/rand_openbsd.odin
new file mode 100644
index 000000000..bae97e8f0
--- /dev/null
+++ b/core/crypto/rand_openbsd.odin
@@ -0,0 +1,12 @@
+package crypto
+
+import "core:c"
+
+foreign import libc "system:c"
+foreign libc {
+ arc4random_buf :: proc "c" (buf: rawptr, nbytes: c.size_t) ---
+}
+
+_rand_bytes :: proc (dst: []byte) {
+ arc4random_buf(raw_data(dst), len(dst))
+}
diff --git a/core/dynlib/lib_unix.odin b/core/dynlib/lib_unix.odin
index bb8affb79..e52ade153 100644
--- a/core/dynlib/lib_unix.odin
+++ b/core/dynlib/lib_unix.odin
@@ -1,4 +1,4 @@
-// +build linux, darwin, freebsd
+// +build linux, darwin, freebsd, openbsd
package dynlib
import "core:os"
diff --git a/core/os/dir_openbsd.odin b/core/os/dir_openbsd.odin
new file mode 100644
index 000000000..465fd35ae
--- /dev/null
+++ b/core/os/dir_openbsd.odin
@@ -0,0 +1,71 @@
+package os
+
+import "core:strings"
+import "core:mem"
+
+read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
+ dirp: Dir
+ dirp, err = _fdopendir(fd)
+ if err != ERROR_NONE {
+ return
+ }
+
+ defer _closedir(dirp)
+
+ // XXX OpenBSD
+ dirpath: string
+ dirpath, err = absolute_path_from_handle(fd)
+
+ if err != ERROR_NONE {
+ return
+ }
+
+ defer delete(dirpath)
+
+ n := n
+ size := n
+ if n <= 0 {
+ n = -1
+ size = 100
+ }
+
+ dfi := make([dynamic]File_Info, 0, size, allocator)
+
+ for {
+ entry: Dirent
+ end_of_stream: bool
+ entry, err, end_of_stream = _readdir(dirp)
+ if err != ERROR_NONE {
+ for fi_ in dfi {
+ file_info_delete(fi_, allocator)
+ }
+ delete(dfi)
+ return
+ } else if end_of_stream {
+ break
+ }
+
+ fi_: File_Info
+ filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
+
+ if filename == "." || filename == ".." {
+ continue
+ }
+
+ fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
+ defer delete(fullpath, context.temp_allocator)
+
+ fi_, err = stat(fullpath, allocator)
+ if err != ERROR_NONE {
+ for fi__ in dfi {
+ file_info_delete(fi__, allocator)
+ }
+ delete(dfi)
+ return
+ }
+
+ append(&dfi, fi_)
+ }
+
+ return dfi[:], ERROR_NONE
+}
diff --git a/core/os/os_openbsd.odin b/core/os/os_openbsd.odin
new file mode 100644
index 000000000..3862851a1
--- /dev/null
+++ b/core/os/os_openbsd.odin
@@ -0,0 +1,706 @@
+package os
+
+foreign import libc "system:c"
+
+import "core:runtime"
+import "core:strings"
+import "core:c"
+
+Handle :: distinct i32
+Pid :: distinct i32
+File_Time :: distinct u64
+Errno :: distinct i32
+
+INVALID_HANDLE :: ~Handle(0)
+
+ERROR_NONE: Errno: 0
+
+EPERM: Errno: 1
+ENOENT: Errno: 2
+ESRCH: Errno: 3
+EINTR: Errno: 4
+EIO: Errno: 5
+ENXIO: Errno: 6
+E2BIG: Errno: 7
+ENOEXEC: Errno: 8
+EBADF: Errno: 9
+ECHILD: Errno: 10
+EDEADLK: Errno: 11
+ENOMEM: Errno: 12
+EACCES: Errno: 13
+EFAULT: Errno: 14
+ENOTBLK: Errno: 15
+EBUSY: Errno: 16
+EEXIST: Errno: 17
+EXDEV: Errno: 18
+ENODEV: Errno: 19
+ENOTDIR: Errno: 20
+EISDIR: Errno: 21
+EINVAL: Errno: 22
+ENFILE: Errno: 23
+EMFILE: Errno: 24
+ENOTTY: Errno: 25
+ETXTBSY: Errno: 26
+EFBIG: Errno: 27
+ENOSPC: Errno: 28
+ESPIPE: Errno: 29
+EROFS: Errno: 30
+EMLINK: Errno: 31
+EPIPE: Errno: 32
+EDOM: Errno: 33
+ERANGE: Errno: 34
+EAGAIN: Errno: 35
+EWOULDBLOCK: Errno: EAGAIN
+EINPROGRESS: Errno: 36
+EALREADY: Errno: 37
+ENOTSOCK: Errno: 38
+EDESTADDRREQ: Errno: 39
+EMSGSIZE: Errno: 40
+EPROTOTYPE: Errno: 41
+ENOPROTOOPT: Errno: 42
+EPROTONOSUPPORT: Errno: 43
+ESOCKTNOSUPPORT: Errno: 44
+EOPNOTSUPP: Errno: 45
+EPFNOSUPPORT: Errno: 46
+EAFNOSUPPORT: Errno: 47
+EADDRINUSE: Errno: 48
+EADDRNOTAVAIL: Errno: 49
+ENETDOWN: Errno: 50
+ENETUNREACH: Errno: 51
+ENETRESET: Errno: 52
+ECONNABORTED: Errno: 53
+ECONNRESET: Errno: 54
+ENOBUFS: Errno: 55
+EISCONN: Errno: 56
+ENOTCONN: Errno: 57
+ESHUTDOWN: Errno: 58
+ETOOMANYREFS: Errno: 59
+ETIMEDOUT: Errno: 60
+ECONNREFUSED: Errno: 61
+ELOOP: Errno: 62
+ENAMETOOLONG: Errno: 63
+EHOSTDOWN: Errno: 64
+EHOSTUNREACH: Errno: 65
+ENOTEMPTY: Errno: 66
+EPROCLIM: Errno: 67
+EUSERS: Errno: 68
+EDQUOT: Errno: 69
+ESTALE: Errno: 70
+EREMOTE: Errno: 71
+EBADRPC: Errno: 72
+ERPCMISMATCH: Errno: 73
+EPROGUNAVAIL: Errno: 74
+EPROGMISMATCH: Errno: 75
+EPROCUNAVAIL: Errno: 76
+ENOLCK: Errno: 77
+ENOSYS: Errno: 78
+EFTYPE: Errno: 79
+EAUTH: Errno: 80
+ENEEDAUTH: Errno: 81
+EIPSEC: Errno: 82
+ENOATTR: Errno: 83
+EILSEQ: Errno: 84
+ENOMEDIUM: Errno: 85
+EMEDIUMTYPE: Errno: 86
+EOVERFLOW: Errno: 87
+ECANCELED: Errno: 88
+EIDRM: Errno: 89
+ENOMSG: Errno: 90
+ENOTSUP: Errno: 91
+EBADMSG: Errno: 92
+ENOTRECOVERABLE: Errno: 93
+EOWNERDEAD: Errno: 94
+EPROTO: Errno: 95
+
+O_RDONLY :: 0x00000
+O_WRONLY :: 0x00001
+O_RDWR :: 0x00002
+O_NONBLOCK :: 0x00004
+O_APPEND :: 0x00008
+O_ASYNC :: 0x00040
+O_SYNC :: 0x00080
+O_CREATE :: 0x00200
+O_TRUNC :: 0x00400
+O_EXCL :: 0x00800
+O_NOCTTY :: 0x08000
+O_CLOEXEC :: 0x10000
+
+SEEK_SET :: 0
+SEEK_CUR :: 1
+SEEK_END :: 2
+
+RTLD_LAZY :: 0x001
+RTLD_NOW :: 0x002
+RTLD_LOCAL :: 0x000
+RTLD_GLOBAL :: 0x100
+RTLD_TRACE :: 0x200
+RTLD_NODELETE :: 0x400
+
+MAX_PATH :: 1024
+
+// "Argv" arguments converted to Odin strings
+args := _alloc_command_line_arguments()
+
+pid_t :: i32
+time_t :: i64
+mode_t :: u32
+dev_t :: i32
+ino_t :: u64
+nlink_t :: u32
+uid_t :: u32
+gid_t :: u32
+off_t :: i64
+blkcnt_t :: u64
+blksize_t :: i32
+
+Unix_File_Time :: struct {
+ seconds: time_t,
+ nanoseconds: c.long,
+}
+
+OS_Stat :: struct {
+ mode: mode_t, // inode protection mode
+ device_id: dev_t, // inode's device
+ serial: ino_t, // inode's number
+ nlink: nlink_t, // number of hard links
+ uid: uid_t, // user ID of the file's owner
+ gid: gid_t, // group ID of the file's group
+ rdev: dev_t, // device type
+
+ last_access: Unix_File_Time, // time of last access
+ modified: Unix_File_Time, // time of last data modification
+ status_change: Unix_File_Time, // time of last file status change
+
+ size: off_t, // file size, in bytes
+ blocks: blkcnt_t, // blocks allocated for file
+ block_size: blksize_t, // optimal blocksize for I/O
+
+ flags: u32, // user defined flags for file
+ gen: u32, // file generation number
+ birthtime: Unix_File_Time, // time of file creation
+}
+
+MAXNAMLEN :: 255
+
+// NOTE(laleksic, 2021-01-21): Comment and rename these to match OS_Stat above
+Dirent :: struct {
+ ino: ino_t, // file number of entry
+ off: off_t, // offset after this entry
+ reclen: u16, // length of this record
+ type: u8, // file type
+ namlen: u8, // length of string in name
+ _padding: [4]u8,
+ name: [MAXNAMLEN + 1]byte, // name
+}
+
+Dir :: distinct rawptr // DIR*
+
+// File type
+S_IFMT :: 0o170000 // Type of file mask
+S_IFIFO :: 0o010000 // Named pipe (fifo)
+S_IFCHR :: 0o020000 // Character special
+S_IFDIR :: 0o040000 // Directory
+S_IFBLK :: 0o060000 // Block special
+S_IFREG :: 0o100000 // Regular
+S_IFLNK :: 0o120000 // Symbolic link
+S_IFSOCK :: 0o140000 // Socket
+S_ISVTX :: 0o001000 // Save swapped text even after use
+
+// File mode
+ // Read, write, execute/search by owner
+S_IRWXU :: 0o0700 // RWX mask for owner
+S_IRUSR :: 0o0400 // R for owner
+S_IWUSR :: 0o0200 // W for owner
+S_IXUSR :: 0o0100 // X for owner
+
+ // Read, write, execute/search by group
+S_IRWXG :: 0o0070 // RWX mask for group
+S_IRGRP :: 0o0040 // R for group
+S_IWGRP :: 0o0020 // W for group
+S_IXGRP :: 0o0010 // X for group
+
+ // Read, write, execute/search by others
+S_IRWXO :: 0o0007 // RWX mask for other
+S_IROTH :: 0o0004 // R for other
+S_IWOTH :: 0o0002 // W for other
+S_IXOTH :: 0o0001 // X for other
+
+S_ISUID :: 0o4000 // Set user id on execution
+S_ISGID :: 0o2000 // Set group id on execution
+S_ISTXT :: 0o1000 // Sticky bit
+
+S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
+S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
+S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
+S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
+S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
+S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
+S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
+
+F_OK :: 0x00 // Test for file existance
+X_OK :: 0x01 // Test for execute permission
+W_OK :: 0x02 // Test for write permission
+R_OK :: 0x04 // Test for read permission
+
+AT_FDCWD :: -100
+AT_EACCESS :: 0x01
+AT_SYMLINK_NOFOLLOW :: 0x02
+AT_SYMLINK_FOLLOW :: 0x04
+AT_REMOVEDIR :: 0x08
+
+@(default_calling_convention="c")
+foreign libc {
+ @(link_name="__errno") __errno :: proc() -> ^int ---
+
+ @(link_name="fork") _unix_fork :: proc() -> pid_t ---
+ @(link_name="getthrid") _unix_getthrid :: proc() -> int ---
+
+ @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
+ @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
+ @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+ @(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: off_t, whence: c.int) -> off_t ---
+ @(link_name="stat") _unix_stat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="fstat") _unix_fstat :: proc(fd: Handle, sb: ^OS_Stat) -> c.int ---
+ @(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
+ @(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
+ @(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
+ @(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
+ @(link_name="chdir") _unix_chdir :: proc(path: cstring) -> c.int ---
+ @(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
+ @(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
+ @(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
+ @(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
+
+ @(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
+ @(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
+ @(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
+ @(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
+ @(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
+
+ @(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
+ @(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
+ @(link_name="free") _unix_free :: proc(ptr: rawptr) ---
+ @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
+
+ @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
+ @(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
+
+ @(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
+
+ @(link_name="dlopen") _unix_dlopen :: proc(filename: cstring, flags: c.int) -> rawptr ---
+ @(link_name="dlsym") _unix_dlsym :: proc(handle: rawptr, symbol: cstring) -> rawptr ---
+ @(link_name="dlclose") _unix_dlclose :: proc(handle: rawptr) -> c.int ---
+ @(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
+}
+
+is_path_separator :: proc(r: rune) -> bool {
+ return r == '/'
+}
+
+get_last_error :: proc() -> int {
+ return __errno()^
+}
+
+fork :: proc() -> (Pid, Errno) {
+ pid := _unix_fork()
+ if pid == -1 {
+ return Pid(-1), Errno(get_last_error())
+ }
+ return Pid(pid), ERROR_NONE
+}
+
+open :: proc(path: string, flags: int = O_RDONLY, mode: int = 0) -> (Handle, Errno) {
+ cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ handle := _unix_open(cstr, c.int(flags), c.int(mode))
+ if handle == -1 {
+ return INVALID_HANDLE, Errno(get_last_error())
+ }
+ return handle, ERROR_NONE
+}
+
+close :: proc(fd: Handle) -> Errno {
+ result := _unix_close(fd)
+ if result == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+ bytes_read := _unix_read(fd, &data[0], c.size_t(len(data)))
+ if bytes_read == -1 {
+ return -1, Errno(get_last_error())
+ }
+ return int(bytes_read), ERROR_NONE
+}
+
+write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
+ if len(data) == 0 {
+ return 0, ERROR_NONE
+ }
+ bytes_written := _unix_write(fd, &data[0], c.size_t(len(data)))
+ if bytes_written == -1 {
+ return -1, Errno(get_last_error())
+ }
+ return int(bytes_written), ERROR_NONE
+}
+
+seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
+ res := _unix_seek(fd, offset, c.int(whence))
+ if res == -1 {
+ return -1, Errno(get_last_error())
+ }
+ return res, ERROR_NONE
+}
+
+file_size :: proc(fd: Handle) -> (i64, Errno) {
+ s, err := _fstat(fd)
+ if err != ERROR_NONE {
+ return -1, err
+ }
+ return s.size, ERROR_NONE
+}
+
+rename :: proc(old_path, new_path: string) -> Errno {
+ old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
+ new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
+ res := _unix_rename(old_path_cstr, new_path_cstr)
+ if res == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+remove :: proc(path: string) -> Errno {
+ path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ res := _unix_unlink(path_cstr)
+ if res == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
+ path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ res := _unix_mkdir(path_cstr, mode)
+ if res == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+remove_directory :: proc(path: string) -> Errno {
+ path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ res := _unix_rmdir(path_cstr)
+ if res == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+is_file_handle :: proc(fd: Handle) -> bool {
+ s, err := _fstat(fd)
+ if err != ERROR_NONE {
+ return false
+ }
+ return S_ISREG(s.mode)
+}
+
+is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
+ s: OS_Stat
+ err: Errno
+ if follow_links {
+ s, err = _stat(path)
+ } else {
+ s, err = _lstat(path)
+ }
+ if err != ERROR_NONE {
+ return false
+ }
+ return S_ISREG(s.mode)
+}
+
+is_dir_handle :: proc(fd: Handle) -> bool {
+ s, err := _fstat(fd)
+ if err != ERROR_NONE {
+ return false
+ }
+ return S_ISDIR(s.mode)
+}
+
+is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
+ s: OS_Stat
+ err: Errno
+ if follow_links {
+ s, err = _stat(path)
+ } else {
+ s, err = _lstat(path)
+ }
+ if err != ERROR_NONE {
+ return false
+ }
+ return S_ISDIR(s.mode)
+}
+
+is_file :: proc {is_file_path, is_file_handle}
+is_dir :: proc {is_dir_path, is_dir_handle}
+
+// NOTE(bill): Uses startup to initialize it
+
+stdin: Handle = 0
+stdout: Handle = 1
+stderr: Handle = 2
+
+/* TODO(zangent): Implement these!
+last_write_time :: proc(fd: Handle) -> File_Time {}
+last_write_time_by_name :: proc(name: string) -> File_Time {}
+*/
+last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
+ s, err := _fstat(fd)
+ if err != ERROR_NONE {
+ return 0, err
+ }
+ modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
+ return File_Time(modified), ERROR_NONE
+}
+
+last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
+ s, err := _stat(name)
+ if err != ERROR_NONE {
+ return 0, err
+ }
+ modified := s.modified.seconds * 1_000_000_000 + s.modified.nanoseconds
+ return File_Time(modified), ERROR_NONE
+}
+
+@private
+_stat :: proc(path: string) -> (OS_Stat, Errno) {
+ cstr := strings.clone_to_cstring(path, context.temp_allocator)
+
+ // deliberately uninitialized
+ s: OS_Stat = ---
+ res := _unix_stat(cstr, &s)
+ if res == -1 {
+ return s, Errno(get_last_error())
+ }
+ return s, ERROR_NONE
+}
+
+@private
+_lstat :: proc(path: string) -> (OS_Stat, Errno) {
+ cstr := strings.clone_to_cstring(path, context.temp_allocator)
+
+ // deliberately uninitialized
+ s: OS_Stat = ---
+ res := _unix_lstat(cstr, &s)
+ if res == -1 {
+ return s, Errno(get_last_error())
+ }
+ return s, ERROR_NONE
+}
+
+@private
+_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
+ // deliberately uninitialized
+ s: OS_Stat = ---
+ res := _unix_fstat(fd, &s)
+ if res == -1 {
+ return s, Errno(get_last_error())
+ }
+ return s, ERROR_NONE
+}
+
+@private
+_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
+ dirp := _unix_fdopendir(fd)
+ if dirp == cast(Dir)nil {
+ return nil, Errno(get_last_error())
+ }
+ return dirp, ERROR_NONE
+}
+
+@private
+_closedir :: proc(dirp: Dir) -> Errno {
+ rc := _unix_closedir(dirp)
+ if rc != 0 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+@private
+_rewinddir :: proc(dirp: Dir) {
+ _unix_rewinddir(dirp)
+}
+
+@private
+_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
+ result: ^Dirent
+ rc := _unix_readdir_r(dirp, &entry, &result)
+
+ if rc != 0 {
+ err = Errno(get_last_error())
+ return
+ }
+ err = ERROR_NONE
+
+ if result == nil {
+ end_of_stream = true
+ return
+ }
+
+ return
+}
+
+@private
+_readlink :: proc(path: string) -> (string, Errno) {
+ path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
+
+ bufsz : uint = MAX_PATH
+ buf := make([]byte, MAX_PATH)
+ for {
+ rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
+ if rc == -1 {
+ delete(buf)
+ return "", Errno(get_last_error())
+ } else if rc == int(bufsz) {
+ bufsz += MAX_PATH
+ delete(buf)
+ buf = make([]byte, bufsz)
+ } else {
+ return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
+ }
+ }
+ unreachable()
+}
+
+// XXX OpenBSD
+absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
+ return "", Errno(ENOSYS)
+}
+
+absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
+ rel := rel
+ if rel == "" {
+ rel = "."
+ }
+
+ rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
+
+ path_ptr := _unix_realpath(rel_cstr, nil)
+ if path_ptr == nil {
+ return "", Errno(get_last_error())
+ }
+ defer _unix_free(path_ptr)
+
+ path_cstr := transmute(cstring)path_ptr
+ path = strings.clone( string(path_cstr) )
+
+ return path, ERROR_NONE
+}
+
+access :: proc(path: string, mask: int) -> (bool, Errno) {
+ cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ res := _unix_access(cstr, c.int(mask))
+ if res == -1 {
+ return false, Errno(get_last_error())
+ }
+ return true, ERROR_NONE
+}
+
+heap_alloc :: proc(size: int) -> rawptr {
+ assert(size >= 0)
+ return _unix_calloc(1, c.size_t(size))
+}
+
+heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
+ // NOTE: _unix_realloc doesn't guarantee new memory will be zeroed on
+ // POSIX platforms. Ensure your caller takes this into account.
+ return _unix_realloc(ptr, c.size_t(new_size))
+}
+
+heap_free :: proc(ptr: rawptr) {
+ _unix_free(ptr)
+}
+
+getenv :: proc(name: string) -> (string, bool) {
+ path_str := strings.clone_to_cstring(name, context.temp_allocator)
+ cstr := _unix_getenv(path_str)
+ if cstr == nil {
+ return "", false
+ }
+ return string(cstr), true
+}
+
+get_current_directory :: proc() -> string {
+ buf := make([dynamic]u8, MAX_PATH)
+ for {
+ cwd := _unix_getcwd(cstring(raw_data(buf)), c.size_t(len(buf)))
+ if cwd != nil {
+ return string(cwd)
+ }
+ if Errno(get_last_error()) != ERANGE {
+ return ""
+ }
+ resize(&buf, len(buf) + MAX_PATH)
+ }
+ unreachable()
+}
+
+set_current_directory :: proc(path: string) -> (err: Errno) {
+ cstr := strings.clone_to_cstring(path, context.temp_allocator)
+ res := _unix_chdir(cstr)
+ if res == -1 {
+ return Errno(get_last_error())
+ }
+ return ERROR_NONE
+}
+
+exit :: proc "contextless" (code: int) -> ! {
+ _unix_exit(c.int(code))
+}
+
+current_thread_id :: proc "contextless" () -> int {
+ return _unix_getthrid()
+}
+
+dlopen :: proc(filename: string, flags: int) -> rawptr {
+ cstr := strings.clone_to_cstring(filename, context.temp_allocator)
+ handle := _unix_dlopen(cstr, c.int(flags))
+ return handle
+}
+dlsym :: proc(handle: rawptr, symbol: string) -> rawptr {
+ assert(handle != nil)
+ cstr := strings.clone_to_cstring(symbol, context.temp_allocator)
+ proc_handle := _unix_dlsym(handle, cstr)
+ return proc_handle
+}
+dlclose :: proc(handle: rawptr) -> bool {
+ assert(handle != nil)
+ return _unix_dlclose(handle) == 0
+}
+dlerror :: proc() -> string {
+ return string(_unix_dlerror())
+}
+
+get_page_size :: proc() -> int {
+ // NOTE(tetra): The page size never changes, so why do anything complicated
+ // if we don't have to.
+ @static page_size := -1
+ if page_size != -1 {
+ return page_size
+ }
+
+ page_size = int(_unix_getpagesize())
+ return page_size
+}
+
+
+_alloc_command_line_arguments :: proc() -> []string {
+ res := make([]string, len(runtime.args__))
+ for arg, i in runtime.args__ {
+ res[i] = string(arg)
+ }
+ return res
+}
diff --git a/core/os/stat_unix.odin b/core/os/stat_unix.odin
index 08c6f53c4..2aa9fc283 100644
--- a/core/os/stat_unix.odin
+++ b/core/os/stat_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd
+//+build linux, darwin, freebsd, openbsd
package os
import "core:time"
diff --git a/core/path/filepath/path_unix.odin b/core/path/filepath/path_unix.odin
index 3e49c4710..d0eaa3635 100644
--- a/core/path/filepath/path_unix.odin
+++ b/core/path/filepath/path_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd
+//+build linux, darwin, freebsd, openbsd
package filepath
when ODIN_OS == .Darwin {
@@ -59,6 +59,11 @@ when ODIN_OS == .Darwin {
foreign libc {
@(link_name="__error") __error :: proc() -> ^i32 ---
}
+} else when ODIN_OS == .OpenBSD {
+ @(private)
+ foreign libc {
+ @(link_name="__errno") __error :: proc() -> ^i32 ---
+ }
} else {
@(private)
foreign libc {
diff --git a/core/runtime/entry_unix.odin b/core/runtime/entry_unix.odin
index dd1e06625..1a3def200 100644
--- a/core/runtime/entry_unix.odin
+++ b/core/runtime/entry_unix.odin
@@ -1,5 +1,5 @@
//+private
-//+build linux, darwin, freebsd
+//+build linux, darwin, freebsd, openbsd
package runtime
import "core:intrinsics"
diff --git a/core/sync/channel_unix.odin b/core/sync/channel_unix.odin
index d6bac2d71..47aa46004 100644
--- a/core/sync/channel_unix.odin
+++ b/core/sync/channel_unix.odin
@@ -1,4 +1,4 @@
-// +build linux, darwin, freebsd
+// +build linux, darwin, freebsd, openbsd
package sync
import "core:time"
diff --git a/core/sync/sync2/futex_openbsd.odin b/core/sync/sync2/futex_openbsd.odin
new file mode 100644
index 000000000..dbc80747b
--- /dev/null
+++ b/core/sync/sync2/futex_openbsd.odin
@@ -0,0 +1,78 @@
+//+private
+//+build openbsd
+package sync2
+
+import "core:c"
+import "core:os"
+import "core:time"
+
+FUTEX_WAIT :: 1
+FUTEX_WAKE :: 2
+
+FUTEX_PRIVATE_FLAG :: 128
+
+FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
+FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
+
+foreign import libc "system:c"
+
+foreign libc {
+ @(link_name="futex")
+ _unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
+}
+
+_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
+ res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
+
+ if res != -1 {
+ return true
+ }
+
+ if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
+ return false
+ }
+
+ panic("futex_wait failure")
+}
+
+_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
+ if duration <= 0 {
+ return false
+ }
+
+ timespec_t :: struct {
+ tv_sec: c.long,
+ tv_nsec: c.long,
+ }
+
+ res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, &timespec_t{
+ tv_sec = (c.long)(duration/1e9),
+ tv_nsec = (c.long)(duration%1e9),
+ })
+
+ if res != -1 {
+ return true
+ }
+
+ if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
+ return false
+ }
+
+ panic("futex_wait_with_timeout failure")
+}
+
+_futex_signal :: proc(f: ^Futex) {
+ res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
+
+ if res == -1 {
+ panic("futex_wake_single failure")
+ }
+}
+
+_futex_broadcast :: proc(f: ^Futex) {
+ res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
+
+ if res == -1 {
+ panic("_futex_wake_all failure")
+ }
+}
diff --git a/core/sync/sync2/primitives_openbsd.odin b/core/sync/sync2/primitives_openbsd.odin
new file mode 100644
index 000000000..ef122b02e
--- /dev/null
+++ b/core/sync/sync2/primitives_openbsd.odin
@@ -0,0 +1,9 @@
+//+build openbsd
+//+private
+package sync2
+
+import "core:os"
+
+_current_thread_id :: proc "contextless" () -> int {
+ return os.current_thread_id()
+}
diff --git a/core/sync/sync2/primitives_pthreads.odin b/core/sync/sync2/primitives_pthreads.odin
index 8d2c3986d..28053f9cc 100644
--- a/core/sync/sync2/primitives_pthreads.odin
+++ b/core/sync/sync2/primitives_pthreads.odin
@@ -1,4 +1,4 @@
-//+build linux, freebsd
+//+build linux, freebsd, openbsd
//+private
package sync2
diff --git a/core/sync/sync_openbsd.odin b/core/sync/sync_openbsd.odin
new file mode 100644
index 000000000..926655f5b
--- /dev/null
+++ b/core/sync/sync_openbsd.odin
@@ -0,0 +1,36 @@
+package sync
+
+import "core:sys/unix"
+import "core:os"
+
+current_thread_id :: proc "contextless" () -> int {
+ return os.current_thread_id()
+}
+
+// The Darwin docs say it best:
+// A semaphore is much like a lock, except that a finite number of threads can hold it simultaneously.
+// Semaphores can be thought of as being much like piles of tokens; multiple threads can take these tokens,
+// but when there are none left, a thread must wait until another thread returns one.
+Semaphore :: struct #align 16 {
+ handle: unix.sem_t,
+}
+
+semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
+ assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0)
+}
+
+semaphore_destroy :: proc(s: ^Semaphore) {
+ assert(unix.sem_destroy(&s.handle) == 0)
+ s.handle = {}
+}
+
+semaphore_post :: proc(s: ^Semaphore, count := 1) {
+ // NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop.
+ for in 0..<count {
+ assert(unix.sem_post(&s.handle) == 0)
+ }
+}
+
+semaphore_wait_for :: proc(s: ^Semaphore) {
+ assert(unix.sem_wait(&s.handle) == 0)
+}
diff --git a/core/sync/sync_unix.odin b/core/sync/sync_unix.odin
index 114625483..b8e9d32cc 100644
--- a/core/sync/sync_unix.odin
+++ b/core/sync/sync_unix.odin
@@ -1,4 +1,4 @@
-// +build linux, darwin, freebsd
+// +build linux, darwin, freebsd, openbsd
package sync
import "core:sys/unix"
diff --git a/core/sys/unix/pthread_openbsd.odin b/core/sys/unix/pthread_openbsd.odin
new file mode 100644
index 000000000..c855f95c0
--- /dev/null
+++ b/core/sys/unix/pthread_openbsd.odin
@@ -0,0 +1,65 @@
+//+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
+
+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() ---
+}
diff --git a/core/sys/unix/pthread_unix.odin b/core/sys/unix/pthread_unix.odin
index ccd8f7844..62e3701ab 100644
--- a/core/sys/unix/pthread_unix.odin
+++ b/core/sys/unix/pthread_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd
+//+build linux, darwin, freebsd, openbsd
package unix
foreign import "system:pthread"
diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin
index 6cb91df86..b6679bbc2 100644
--- a/core/thread/thread_unix.odin
+++ b/core/thread/thread_unix.odin
@@ -1,4 +1,4 @@
-// +build linux, darwin, freebsd
+// +build linux, darwin, freebsd, openbsd
// +private
package thread
diff --git a/core/time/time_unix.odin b/core/time/time_unix.odin
index 9c5c5cc35..37fc1fd3e 100644
--- a/core/time/time_unix.odin
+++ b/core/time/time_unix.odin
@@ -1,4 +1,4 @@
-//+build linux, darwin, freebsd
+//+build linux, darwin, freebsd, openbsd
package time
IS_SUPPORTED :: true // NOTE: Times on Darwin are UTC.
@@ -22,16 +22,28 @@ TimeSpec :: struct {
tv_nsec : i64, /* nanoseconds */
}
-CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
-CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
-CLOCK_PROCESS_CPUTIME_ID :: 2
-CLOCK_THREAD_CPUTIME_ID :: 3
-CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
-CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
-CLOCK_MONOTONIC_COARSE :: 6
-CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
-CLOCK_REALTIME_ALARM :: 8
-CLOCK_BOOTTIME_ALARM :: 9
+when ODIN_OS == .OpenBSD {
+ CLOCK_REALTIME :: 0
+ CLOCK_PROCESS_CPUTIME_ID :: 2
+ CLOCK_MONOTONIC :: 3
+ CLOCK_THREAD_CPUTIME_ID :: 4
+ CLOCK_UPTIME :: 5
+ CLOCK_BOOTTIME :: 6
+
+ // CLOCK_MONOTONIC_RAW doesn't exist, use CLOCK_MONOTONIC
+ CLOCK_MONOTONIC_RAW :: CLOCK_MONOTONIC
+} else {
+ CLOCK_REALTIME :: 0 // NOTE(tetra): May jump in time, when user changes the system time.
+ CLOCK_MONOTONIC :: 1 // NOTE(tetra): May stand still while system is asleep.
+ CLOCK_PROCESS_CPUTIME_ID :: 2
+ CLOCK_THREAD_CPUTIME_ID :: 3
+ CLOCK_MONOTONIC_RAW :: 4 // NOTE(tetra): "RAW" means: Not adjusted by NTP.
+ CLOCK_REALTIME_COARSE :: 5 // NOTE(tetra): "COARSE" clocks are apparently much faster, but not "fine-grained."
+ CLOCK_MONOTONIC_COARSE :: 6
+ CLOCK_BOOTTIME :: 7 // NOTE(tetra): Same as MONOTONIC, except also including time system was asleep.
+ CLOCK_REALTIME_ALARM :: 8
+ CLOCK_BOOTTIME_ALARM :: 9
+}
// TODO(tetra, 2019-11-05): The original implementation of this package for Darwin used this constants.
// I do not know if Darwin programmers are used to the existance of these constants or not, so
diff --git a/src/bug_report.cpp b/src/bug_report.cpp
index 4dd251f24..02a2b1ba2 100644
--- a/src/bug_report.cpp
+++ b/src/bug_report.cpp
@@ -17,6 +17,11 @@
#include <sys/sysctl.h>
#endif
+#if defined(GB_SYSTEM_OPENBSD)
+ #include <sys/sysctl.h>
+ #include <sys/utsname.h>
+#endif
+
/*
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
*/
@@ -242,6 +247,14 @@ void report_ram_info() {
if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
}
+ #elif defined(GB_SYSTEM_OPENBSD)
+ uint64_t ram_amount;
+ size_t val_size = sizeof(ram_amount);
+
+ int sysctls[] = { CTL_HW, HW_PHYSMEM64 };
+ if (sysctl(sysctls, 2, &ram_amount, &val_size, NULL, 0) != -1) {
+ gb_printf("%lld MiB\n", ram_amount / gb_megabytes(1));
+ }
#else
gb_printf("Unknown.\n");
#endif
@@ -643,6 +656,14 @@ void print_bug_report_help() {
} else {
gb_printf("macOS: Unknown\n");
}
+ #elif defined(GB_SYSTEM_OPENBSD)
+ struct utsname un;
+
+ if (uname(&un) != -1) {
+ gb_printf("%s %s %s %s\n", un.sysname, un.release, un.version, un.machine);
+ } else {
+ gb_printf("OpenBSD: Unknown\n");
+ }
#else
gb_printf("Unknown\n");
@@ -657,4 +678,4 @@ void print_bug_report_help() {
And RAM info.
*/
report_ram_info();
-} \ No newline at end of file
+}
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 610e4f847..c40a70069 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -1,4 +1,4 @@
-#if defined(GB_SYSTEM_FREEBSD)
+#if defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <sys/types.h>
#include <sys/sysctl.h>
#endif
@@ -16,6 +16,7 @@ enum TargetOsKind {
TargetOs_linux,
TargetOs_essence,
TargetOs_freebsd,
+ TargetOs_openbsd,
TargetOs_wasi,
TargetOs_js,
@@ -53,6 +54,7 @@ String target_os_names[TargetOs_COUNT] = {
str_lit("linux"),
str_lit("essence"),
str_lit("freebsd"),
+ str_lit("openbsd"),
str_lit("wasi"),
str_lit("js"),
@@ -354,6 +356,15 @@ gb_global TargetMetrics target_freebsd_amd64 = {
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
+gb_global TargetMetrics target_openbsd_amd64 = {
+ TargetOs_openbsd,
+ TargetArch_amd64,
+ 8,
+ 16,
+ str_lit("x86_64-unknown-openbsd-elf"),
+ str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
+};
+
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
@@ -417,6 +428,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("windows_amd64"), &target_windows_amd64 },
{ str_lit("freebsd_386"), &target_freebsd_386 },
{ str_lit("freebsd_amd64"), &target_freebsd_amd64 },
+ { str_lit("openbsd_amd64"), &target_openbsd_amd64 },
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
@@ -722,10 +734,38 @@ String internal_odin_root_dir(void) {
len = readlink("/proc/curproc/exe", &path_buf[0], path_buf.count);
#elif defined(GB_SYSTEM_DRAGONFLYBSD)
len = readlink("/proc/curproc/file", &path_buf[0], path_buf.count);
-#else
+#elif defined(GB_SYSTEM_LINUX)
len = readlink("/proc/self/exe", &path_buf[0], path_buf.count);
+#elif defined(GB_SYSTEM_OPENBSD)
+ int error;
+ int mib[] = {
+ CTL_KERN,
+ KERN_PROC_ARGS,
+ getpid(),
+ KERN_PROC_ARGV,
+ };
+ // get argv size
+ error = sysctl(mib, 4, NULL, (size_t *) &len, NULL, 0);
+ if (error == -1) {
+ // sysctl error
+ return make_string(nullptr, 0);
+ }
+ // get argv
+ char **argv = (char **)gb_malloc(len);
+ error = sysctl(mib, 4, argv, (size_t *) &len, NULL, 0);
+ if (error == -1) {
+ // sysctl error
+ gb_mfree(argv);
+ return make_string(nullptr, 0);
+ }
+ // copy argv[0] to path_buf
+ len = gb_strlen(argv[0]);
+ if(len < path_buf.count) {
+ gb_memmove(&path_buf[0], argv[0], len);
+ }
+ gb_mfree(argv);
#endif
- if(len == 0) {
+ if(len == 0 || len == -1) {
return make_string(nullptr, 0);
}
if (len < path_buf.count) {
@@ -922,6 +962,8 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
#elif defined(GB_SYSTEM_FREEBSD)
metrics = &target_freebsd_amd64;
+ #elif defined(GB_SYSTEM_OPENBSD)
+ metrics = &target_openbsd_amd64;
#elif defined(GB_CPU_ARM)
metrics = &target_linux_arm64;
#else
@@ -980,6 +1022,9 @@ void init_build_context(TargetMetrics *cross_target) {
case TargetOs_freebsd:
bc->link_flags = str_lit("-arch x86-64 ");
break;
+ case TargetOs_openbsd:
+ bc->link_flags = str_lit("-arch x86-64 ");
+ break;
}
} else if (bc->metrics.arch == TargetArch_i386) {
switch (bc->metrics.os) {
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index eb9d7f293..69cc40de8 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -3506,6 +3506,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case TargetOs_linux:
case TargetOs_essence:
case TargetOs_freebsd:
+ case TargetOs_openbsd:
switch (build_context.metrics.arch) {
case TargetArch_i386:
case TargetArch_amd64:
diff --git a/src/checker.cpp b/src/checker.cpp
index f440b7c9a..5a7ece263 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -906,6 +906,7 @@ void init_universal(void) {
{"Linux", TargetOs_linux},
{"Essence", TargetOs_essence},
{"FreeBSD", TargetOs_freebsd},
+ {"OpenBSD", TargetOs_openbsd},
{"WASI", TargetOs_wasi},
{"JS", TargetOs_js},
{"Freestanding", TargetOs_freestanding},
diff --git a/src/common.cpp b/src/common.cpp
index d3ee95b76..aaacda04b 100644
--- a/src/common.cpp
+++ b/src/common.cpp
@@ -848,7 +848,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
return ReadDirectory_None;
}
-#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD)
+#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
#include <dirent.h>
diff --git a/src/gb/gb.h b/src/gb/gb.h
index a9d6378c9..b72a893f7 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -79,6 +79,10 @@ extern "C" {
#ifndef GB_SYSTEM_FREEBSD
#define GB_SYSTEM_FREEBSD 1
#endif
+ #elif defined(__OpenBSD__)
+ #ifndef GB_SYSTEM_OPENBSD
+ #define GB_SYSTEM_OPENBSD 1
+ #endif
#else
#error This UNIX operating system is not supported
#endif
@@ -199,7 +203,7 @@ extern "C" {
#endif
#include <stdlib.h> // NOTE(bill): malloc on linux
#include <sys/mman.h>
- #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__)
+ #if !defined(GB_SYSTEM_OSX) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
#include <sys/sendfile.h>
#endif
#include <sys/stat.h>
@@ -235,6 +239,12 @@ extern "C" {
#define sendfile(out, in, offset, count) sendfile(out, in, offset, count, NULL, NULL, 0)
#endif
+#if defined(GB_SYSTEM_OPENBSD)
+ #include <stdio.h>
+ #include <pthread_np.h>
+ #define lseek64 lseek
+#endif
+
#if defined(GB_SYSTEM_UNIX)
#include <semaphore.h>
#endif
@@ -783,6 +793,13 @@ typedef struct gbAffinity {
isize thread_count;
isize threads_per_core;
} gbAffinity;
+#elif defined(GB_SYSTEM_OPENBSD)
+typedef struct gbAffinity {
+ b32 is_accurate;
+ isize core_count;
+ isize thread_count;
+ isize threads_per_core;
+} gbAffinity;
#else
#error TODO(bill): Unknown system
#endif
@@ -3682,6 +3699,30 @@ isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
GB_ASSERT(0 <= core && core < a->core_count);
return a->threads_per_core;
}
+
+#elif defined(GB_SYSTEM_OPENBSD)
+#include <unistd.h>
+
+void gb_affinity_init(gbAffinity *a) {
+ a->core_count = sysconf(_SC_NPROCESSORS_ONLN);
+ a->threads_per_core = 1;
+ a->is_accurate = a->core_count > 0;
+ a->core_count = a->is_accurate ? a->core_count : 1;
+ a->thread_count = a->core_count;
+}
+
+void gb_affinity_destroy(gbAffinity *a) {
+ gb_unused(a);
+}
+
+b32 gb_affinity_set(gbAffinity *a, isize core, isize thread_index) {
+ return true;
+}
+
+isize gb_affinity_thread_count_for_core(gbAffinity *a, isize core) {
+ GB_ASSERT(0 <= core && core < a->core_count);
+ return a->threads_per_core;
+}
#else
#error TODO(bill): Unknown system
#endif
@@ -6025,7 +6066,7 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) {
#if defined(GB_SYSTEM_OSX)
return copyfile(existing_filename, new_filename, NULL, COPYFILE_DATA) == 0;
-#else
+#elif defined(GB_SYSTEM_LINUX) || defined(GB_SYSTEM_FREEBSD)
isize size;
int existing_fd = open(existing_filename, O_RDONLY, 0);
int new_fd = open(new_filename, O_WRONLY|O_CREAT, 0666);
@@ -6042,6 +6083,49 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
close(existing_fd);
return size == stat_existing.st_size;
+#else
+ int new_flags = O_WRONLY | O_CREAT;
+ if (fail_if_exists) {
+ new_flags |= O_EXCL;
+ }
+ int existing_fd = open(existing_filename, O_RDONLY, 0);
+ int new_fd = open(new_filename, new_flags, 0666);
+
+ struct stat stat_existing;
+ if (fstat(existing_fd, &stat_existing) == -1) {
+ return 0;
+ }
+
+ size_t bsize = stat_existing.st_blksize > BUFSIZ ? stat_existing.st_blksize : BUFSIZ;
+ char *buf = (char *)malloc(bsize);
+ if (buf == NULL) {
+ close(new_fd);
+ close(existing_fd);
+ return 0;
+ }
+
+ isize size = 0;
+ ssize_t nread, nwrite, offset;
+ while ((nread = read(existing_fd, buf, bsize)) != -1 && nread != 0) {
+ for (offset = 0; nread; nread -= nwrite, offset += nwrite) {
+ if ((nwrite = write(new_fd, buf + offset, nread)) == -1 || nwrite == 0) {
+ free(buf);
+ close(new_fd);
+ close(existing_fd);
+ return 0;
+ }
+ size += nwrite;
+ }
+ }
+
+ free(buf);
+ close(new_fd);
+ close(existing_fd);
+
+ if (nread == -1) {
+ return 0;
+ }
+ return size == stat_existing.st_size;
#endif
}
diff --git a/src/threading.cpp b/src/threading.cpp
index 50d0dfed1..63e3415b2 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -486,7 +486,7 @@ void thread_set_name(Thread *t, char const *name) {
#elif defined(GB_SYSTEM_OSX)
// TODO(bill): Test if this works
pthread_setname_np(name);
-#elif defined(GB_SYSTEM_FREEBSD)
+#elif defined(GB_SYSTEM_FREEBSD) || defined(GB_SYSTEM_OPENBSD)
pthread_set_name_np(t->posix_handle, name);
#else
// TODO(bill): Test if this works
diff --git a/tests/vendor/Makefile b/tests/vendor/Makefile
index f0a456bae..341067c6e 100644
--- a/tests/vendor/Makefile
+++ b/tests/vendor/Makefile
@@ -1,6 +1,13 @@
ODIN=../../odin
+ODINFLAGS=
+
+OS=$(shell uname)
+
+ifeq ($(OS), OpenBSD)
+ ODINFLAGS:=$(ODINFLAGS) -extra-linker-flags:-L/usr/local/lib
+endif
all: botan_test
botan_test:
- $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check \ No newline at end of file
+ $(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS)
diff --git a/vendor/botan/bindings/botan.odin b/vendor/botan/bindings/botan.odin
index 70311523d..3eaad0bc1 100644
--- a/vendor/botan/bindings/botan.odin
+++ b/vendor/botan/bindings/botan.odin
@@ -146,6 +146,8 @@ when ODIN_OS == .Windows {
foreign import botan_lib "system:botan-2"
} else when ODIN_OS == .Darwin {
foreign import botan_lib "system:botan-2"
+} else when ODIN_OS == .OpenBSD {
+ foreign import botan_lib "system:botan-2"
}
@(default_calling_convention="c")
@@ -471,4 +473,4 @@ foreign botan_lib {
fpe_destroy :: proc(fpe: fpe_t) -> c.int ---
fpe_encrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
fpe_decrypt :: proc(fpe: fpe_t, x: mp_t, tweak: ^c.char, tweak_len: c.size_t) -> c.int ---
-} \ No newline at end of file
+}