Merge pull request #1557 from semarie/openbsd-support

initial OpenBSD support
This commit is contained in:
gingerBill
2022-02-28 14:23:56 +00:00
committed by GitHub
33 changed files with 1250 additions and 36 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package dynlib
import "core:os"

71
core/os/dir_openbsd.odin Normal file
View File

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

706
core/os/os_openbsd.odin Normal file
View File

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

View File

@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package os
import "core:time"

View File

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

View File

@@ -1,5 +1,5 @@
//+private
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package runtime
import "core:intrinsics"

View File

@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package sync
import "core:time"

View File

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

View File

@@ -0,0 +1,9 @@
//+build openbsd
//+private
package sync2
import "core:os"
_current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id()
}

View File

@@ -1,4 +1,4 @@
//+build linux, freebsd
//+build linux, freebsd, openbsd
//+private
package sync2

View File

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

View File

@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
package sync
import "core:sys/unix"

View File

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

View File

@@ -1,4 +1,4 @@
//+build linux, darwin, freebsd
//+build linux, darwin, freebsd, openbsd
package unix
foreign import "system:pthread"

View File

@@ -1,4 +1,4 @@
// +build linux, darwin, freebsd
// +build linux, darwin, freebsd, openbsd
// +private
package thread

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
@@ -3678,6 +3695,30 @@ 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;
}
#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;
@@ -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);
@@ -6041,6 +6082,49 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
close(new_fd);
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
}

View File

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

View File

@@ -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
$(ODIN) run botan -out=botan_hash -o:speed -no-bounds-check $(ODINFLAGS)

View File

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