From 99121d6ff2b02f3d16b791eb103bb9f9e8b96475 Mon Sep 17 00:00:00 2001 From: Tetralux Date: Sat, 26 Oct 2019 22:35:36 +0000 Subject: Implement core:thread and core:sync on Unix using pthreads Also do some cleanup and refactoring of the thread, sync and time APIs. - remove 'semaphore_release' because 'post' and 'wait' is easier to understand - change 'semaphore_wait' to '*_wait_for' to match Condition - pthreads can be given a stack, but doing so requires the user to set up the guard pages manually. BE WARNED. The alignment requirements of the stack are also platform-dependant; it may need to be page size aligned on some systems. Unclear which systems, however. See 'os.get_page_size', and 'mem.make_aligned'. HOWEVER: I was unable to get custom stacks with guard pages working reliably, so while you can do it, the API does not support it. - add 'os.get_page_size', 'mem.make_aligned', and 'mem.new_aligned'. - removed thread return values because windows and linux are not consistent; windows returns 'i32' and pthreads return 'void*'; besides which, if you really wanted to communicate how the thread exited, you probably wouldn't do it with the thread's exit code. - fixed 'thread.is_done' on Windows; it didn't report true immediately after calling 'thread.join'. - moved time related stuff out of 'core:os' to 'core:time'. - add 'mem.align_backward' - fixed default allocator alignment The heap on Windows, and calloc on Linux, both have no facility to request alignment. It's a bit of hack, but the heap_allocator now overallocates; `size + alignment` bytes, and aligns things to at least 2. It does both of these things to ensure that there is at least two bytes before the payload, which it uses to store how much padding it needed to insert in order to fulfil the alignment requested. - make conditions more sane by matching the Windows behaviour. The fact that they were signalled now lingers until a thread tries to wait, causing them to just pass by uninterrupted, without sleeping or locking the underlying mutex, as it would otherwise need to do. This means that a thread no longer has to be waiting in order to be signalled, which avoids timing bugs that causes deadlocks that are hard to debug and fix. See the comment on the `sync.Condition.flag` field. - add thread priority: `thread.create(worker_proc, .High)` --- core/os/os.odin | 51 ++++++++++-- core/os/os_darwin.odin | 147 +++++++++++++++++++++++++++++++++ core/os/os_linux.odin | 213 ++++++++++++++++++++++++++++++++---------------- core/os/os_windows.odin | 13 ++- 4 files changed, 347 insertions(+), 77 deletions(-) (limited to 'core/os') diff --git a/core/os/os.odin b/core/os/os.odin index d9bb318c4..7d6f4451d 100644 --- a/core/os/os.odin +++ b/core/os/os.odin @@ -119,16 +119,54 @@ read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) { return read(fd, s); } - heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr { + // + // NOTE(tetra, 2019-11-10): The heap doesn't respect alignment. + // HACK: Overallocate, align forwards, and then use the two bytes immediately before + // the address we return, to store the padding we inserted. + // This allows us to pass the original pointer we got back from the heap to `free` later. + // + + align_and_store_padding :: proc(ptr: rawptr, alignment: int) -> rawptr { + ptr := mem.ptr_offset(cast(^u8) ptr, 2); + new_ptr := cast(^u8) mem.align_forward(ptr, uintptr(alignment)); + offset := mem.ptr_sub(new_ptr, cast(^u8) ptr) + 2; + assert(offset < int(max(u16))); + (^[2]u8)(mem.ptr_offset(new_ptr, -2))^ = transmute([2]u8) u16(offset); + return new_ptr; + } + + recover_original_pointer :: proc(ptr: rawptr) -> rawptr { + ptr := cast(^u8) ptr; + offset := transmute(u16) (^[2]u8)(mem.ptr_offset(ptr, -2))^; + ptr = mem.ptr_offset(ptr, -int(offset)); + return ptr; + } + + aligned_heap_alloc :: proc(size: int, alignment: int) -> rawptr { + // NOTE(tetra): Alignment 1 will mean we only have one extra byte. + // This is not enough for a u16 - so we ensure there is at least two bytes extra. + // This also means that the pointer is always aligned to at least 2. + extra := alignment; + if extra <= 1 do extra = 2; + + orig := cast(^u8) heap_alloc(size + extra); + if orig == nil do return nil; + ptr := align_and_store_padding(orig, alignment); + assert(recover_original_pointer(ptr) == orig); + return ptr; + } + switch mode { case .Alloc: - return heap_alloc(size); + return aligned_heap_alloc(size, alignment); case .Free: - heap_free(old_memory); + assert(old_memory != nil); + ptr := recover_original_pointer(old_memory); + heap_free(ptr); return nil; case .Free_All: @@ -136,11 +174,12 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode, case .Resize: if old_memory == nil { - return heap_alloc(size); + return aligned_heap_alloc(size, alignment); } - ptr := heap_resize(old_memory, size); + ptr := recover_original_pointer(old_memory); + ptr = heap_resize(ptr, size); assert(ptr != nil); - return ptr; + return align_and_store_padding(ptr, alignment); } return nil; diff --git a/core/os/os_darwin.odin b/core/os/os_darwin.odin index c252cf05c..3bca732ec 100644 --- a/core/os/os_darwin.odin +++ b/core/os/os_darwin.odin @@ -14,6 +14,142 @@ Errno :: distinct int; INVALID_HANDLE :: ~Handle(0); +ERROR_NONE: Errno : 0; +EPERM: Errno : 1; /* Operation not permitted */ +ENOENT: Errno : 2; /* No such file or directory */ +ESRCH: Errno : 3; /* No such process */ +EINTR: Errno : 4; /* Interrupted system call */ +EIO: Errno : 5; /* Input/output error */ +ENXIO: Errno : 6; /* Device not configured */ +E2BIG: Errno : 7; /* Argument list too long */ +ENOEXEC: Errno : 8; /* Exec format error */ +EBADF: Errno : 9; /* Bad file descriptor */ +ECHILD: Errno : 10; /* No child processes */ +EDEADLK: Errno : 11; /* Resource deadlock avoided */ +ENOMEM: Errno : 12; /* Cannot allocate memory */ +EACCES: Errno : 13; /* Permission denied */ +EFAULT: Errno : 14; /* Bad address */ +ENOTBLK: Errno : 15; /* Block device required */ +EBUSY: Errno : 16; /* Device / Resource busy */ +EEXIST: Errno : 17; /* File exists */ +EXDEV: Errno : 18; /* Cross-device link */ +ENODEV: Errno : 19; /* Operation not supported by device */ +ENOTDIR: Errno : 20; /* Not a directory */ +EISDIR: Errno : 21; /* Is a directory */ +EINVAL: Errno : 22; /* Invalid argument */ +ENFILE: Errno : 23; /* Too many open files in system */ +EMFILE: Errno : 24; /* Too many open files */ +ENOTTY: Errno : 25; /* Inappropriate ioctl for device */ +ETXTBSY: Errno : 26; /* Text file busy */ +EFBIG: Errno : 27; /* File too large */ +ENOSPC: Errno : 28; /* No space left on device */ +ESPIPE: Errno : 29; /* Illegal seek */ +EROFS: Errno : 30; /* Read-only file system */ +EMLINK: Errno : 31; /* Too many links */ +EPIPE: Errno : 32; /* Broken pipe */ + +/* math software */ +EDOM: Errno : 33; /* Numerical argument out of domain */ +ERANGE: Errno : 34; /* Result too large */ + +/* non-blocking and interrupt i/o */ +EAGAIN: Errno : 35; /* Resource temporarily unavailable */ +EWOULDBLOCK: Errno : EAGAIN; /* Operation would block */ +EINPROGRESS: Errno : 36; /* Operation now in progress */ +EALREADY: Errno : 37; /* Operation already in progress */ + +/* ipc/network software -- argument errors */ +ENOTSOCK: Errno : 38; /* Socket operation on non-socket */ +EDESTADDRREQ: Errno : 39; /* Destination address required */ +EMSGSIZE: Errno : 40; /* Message too long */ +EPROTOTYPE: Errno : 41; /* Protocol wrong type for socket */ +ENOPROTOOPT: Errno : 42; /* Protocol not available */ +EPROTONOSUPPORT: Errno : 43; /* Protocol not supported */ +ESOCKTNOSUPPORT: Errno : 44; /* Socket type not supported */ +ENOTSUP: Errno : 45; /* Operation not supported */ +EPFNOSUPPORT: Errno : 46; /* Protocol family not supported */ +EAFNOSUPPORT: Errno : 47; /* Address family not supported by protocol family */ +EADDRINUSE: Errno : 48; /* Address already in use */ +EADDRNOTAVAIL: Errno : 49; /* Can't assign requested address */ + +/* ipc/network software -- operational errors */ +ENETDOWN: Errno : 50; /* Network is down */ +ENETUNREACH: Errno : 51; /* Network is unreachable */ +ENETRESET: Errno : 52; /* Network dropped connection on reset */ +ECONNABORTED: Errno : 53; /* Software caused connection abort */ +ECONNRESET: Errno : 54; /* Connection reset by peer */ +ENOBUFS: Errno : 55; /* No buffer space available */ +EISCONN: Errno : 56; /* Socket is already connected */ +ENOTCONN: Errno : 57; /* Socket is not connected */ +ESHUTDOWN: Errno : 58; /* Can't send after socket shutdown */ +ETOOMANYREFS: Errno : 59; /* Too many references: can't splice */ +ETIMEDOUT: Errno : 60; /* Operation timed out */ +ECONNREFUSED: Errno : 61; /* Connection refused */ + +ELOOP: Errno : 62; /* Too many levels of symbolic links */ +ENAMETOOLONG: Errno : 63; /* File name too long */ + +/* should be rearranged */ +EHOSTDOWN: Errno : 64; /* Host is down */ +EHOSTUNREACH: Errno : 65; /* No route to host */ +ENOTEMPTY: Errno : 66; /* Directory not empty */ + +/* quotas & mush */ +EPROCLIM: Errno : 67; /* Too many processes */ +EUSERS: Errno : 68; /* Too many users */ +EDQUOT: Errno : 69; /* Disc quota exceeded */ + +/* Network File System */ +ESTALE: Errno : 70; /* Stale NFS file handle */ +EREMOTE: Errno : 71; /* Too many levels of remote in path */ +EBADRPC: Errno : 72; /* RPC struct is bad */ +ERPCMISMATCH: Errno : 73; /* RPC version wrong */ +EPROGUNAVAIL: Errno : 74; /* RPC prog. not avail */ +EPROGMISMATCH: Errno : 75; /* Program version wrong */ +EPROCUNAVAIL: Errno : 76; /* Bad procedure for program */ + +ENOLCK: Errno : 77; /* No locks available */ +ENOSYS: Errno : 78; /* Function not implemented */ + +EFTYPE: Errno : 79; /* Inappropriate file type or format */ +EAUTH: Errno : 80; /* Authentication error */ +ENEEDAUTH: Errno : 81; /* Need authenticator */ + +/* Intelligent device errors */ +EPWROFF: Errno : 82; /* Device power is off */ +EDEVERR: Errno : 83; /* Device error, e.g. paper out */ +EOVERFLOW: Errno : 84; /* Value too large to be stored in data type */ + +/* Program loading errors */ +EBADEXEC: Errno : 85; /* Bad executable */ +EBADARCH: Errno : 86; /* Bad CPU type in executable */ +ESHLIBVERS: Errno : 87; /* Shared library version mismatch */ +EBADMACHO: Errno : 88; /* Malformed Macho file */ + +ECANCELED: Errno : 89; /* Operation canceled */ + +EIDRM: Errno : 90; /* Identifier removed */ +ENOMSG: Errno : 91; /* No message of desired type */ +EILSEQ: Errno : 92; /* Illegal byte sequence */ +ENOATTR: Errno : 93; /* Attribute not found */ + +EBADMSG: Errno : 94; /* Bad message */ +EMULTIHOP: Errno : 95; /* Reserved */ +ENODATA: Errno : 96; /* No message available on STREAM */ +ENOLINK: Errno : 97; /* Reserved */ +ENOSR: Errno : 98; /* No STREAM resources */ +ENOSTR: Errno : 99; /* Not a STREAM */ +EPROTO: Errno : 100; /* Protocol error */ +ETIME: Errno : 101; /* STREAM ioctl timeout */ + +ENOPOLICY: Errno : 103; /* No such policy registered */ + +ENOTRECOVERABLE: Errno : 104; /* State not recoverable */ +EOWNERDEAD: Errno : 105; /* Previous owner died */ + +EQFULL: Errno : 106; /* Interface output queue is full */ +ELAST: Errno : 106; /* Must be equal largest errno */ + O_RDONLY :: 0x00000; O_WRONLY :: 0x00001; O_RDWR :: 0x00002; @@ -133,6 +269,7 @@ foreign libc { @(link_name="write") _unix_write :: proc(handle: Handle, buffer: rawptr, count: int) -> int ---; @(link_name="lseek") _unix_lseek :: proc(fs: Handle, offset: int, whence: int) -> int ---; @(link_name="gettid") _unix_gettid :: proc() -> u64 ---; + @(link_name="getpagesize") _unix_getpagesize :: proc() -> i32 ---; @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---; @(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---; @@ -287,6 +424,16 @@ 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 do return page_size; + + page_size = int(_unix_getpagesize()); + return page_size; +} + _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)); diff --git a/core/os/os_linux.odin b/core/os/os_linux.odin index dc3cdde93..cf03dac71 100644 --- a/core/os/os_linux.odin +++ b/core/os/os_linux.odin @@ -15,37 +15,138 @@ Syscall :: distinct int; INVALID_HANDLE :: ~Handle(0); -ERROR_NONE: Errno : 0; -EPERM: Errno : 1; -ENOENT: Errno : 2; -EINTR: Errno : 4; -EIO: Errno : 5; -ENXIO: Errno : 6; -EBADF: Errno : 9; -EAGAIN: Errno : 11; -EWOULDBLOCK: Errno : EAGAIN; -ENOMEM: Errno : 12; -EACCES: Errno : 13; -EFAULT: Errno : 14; -EEXIST: Errno : 17; -ENODEV: Errno : 19; -ENOTDIR: Errno : 20; -EISDIR: Errno : 21; -EINVAL: Errno : 22; -ENFILE: Errno : 23; -EMFILE: Errno : 24; -ETXTBSY: Errno : 26; -EFBIG: Errno : 27; -ENOSPC: Errno : 28; -ESPIPE: Errno : 29; -EROFS: Errno : 30; -EPIPE: Errno : 32; -ENAMETOOLONG: Errno : 36; -ELOOP: Errno : 40; -EOVERFLOW: Errno : 75; -EDESTADDRREQ: Errno : 89; -EOPNOTSUPP: Errno : 95; -EDQUOT: Errno : 122; +ERROR_NONE: Errno : 0; +EPERM: Errno : 1; +ENOENT: Errno : 2; +ESRCH: Errno : 3; +EINTR: Errno : 4; +EIO: Errno : 5; +ENXIO: Errno : 6; +EBADF: Errno : 9; +EAGAIN: Errno : 11; +ENOMEM: Errno : 12; +EACCES: Errno : 13; +EFAULT: Errno : 14; +EEXIST: Errno : 17; +ENODEV: Errno : 19; +ENOTDIR: Errno : 20; +EISDIR: Errno : 21; +EINVAL: Errno : 22; +ENFILE: Errno : 23; +EMFILE: Errno : 24; +ETXTBSY: Errno : 26; +EFBIG: Errno : 27; +ENOSPC: Errno : 28; +ESPIPE: Errno : 29; +EROFS: Errno : 30; +EPIPE: Errno : 32; + +EDEADLK: Errno : 35; /* Resource deadlock would occur */ +ENAMETOOLONG: Errno : 36; /* File name too long */ +ENOLCK: Errno : 37; /* No record locks available */ + +ENOSYS: Errno : 38; /* Invalid system call number */ + +ENOTEMPTY: Errno : 39; /* Directory not empty */ +ELOOP: Errno : 40; /* Too many symbolic links encountered */ +EWOULDBLOCK: Errno : EAGAIN; /* Operation would block */ +ENOMSG: Errno : 42; /* No message of desired type */ +EIDRM: Errno : 43; /* Identifier removed */ +ECHRNG: Errno : 44; /* Channel number out of range */ +EL2NSYNC: Errno : 45; /* Level 2 not synchronized */ +EL3HLT: Errno : 46; /* Level 3 halted */ +EL3RST: Errno : 47; /* Level 3 reset */ +ELNRNG: Errno : 48; /* Link number out of range */ +EUNATCH: Errno : 49; /* Protocol driver not attached */ +ENOCSI: Errno : 50; /* No CSI structure available */ +EL2HLT: Errno : 51; /* Level 2 halted */ +EBADE: Errno : 52; /* Invalid exchange */ +EBADR: Errno : 53; /* Invalid request descriptor */ +EXFULL: Errno : 54; /* Exchange full */ +ENOANO: Errno : 55; /* No anode */ +EBADRQC: Errno : 56; /* Invalid request code */ +EBADSLT: Errno : 57; /* Invalid slot */ +EDEADLOCK: Errno : EDEADLK; +EBFONT: Errno : 59; /* Bad font file format */ +ENOSTR: Errno : 60; /* Device not a stream */ +ENODATA: Errno : 61; /* No data available */ +ETIME: Errno : 62; /* Timer expired */ +ENOSR: Errno : 63; /* Out of streams resources */ +ENONET: Errno : 64; /* Machine is not on the network */ +ENOPKG: Errno : 65; /* Package not installed */ +EREMOTE: Errno : 66; /* Object is remote */ +ENOLINK: Errno : 67; /* Link has been severed */ +EADV: Errno : 68; /* Advertise error */ +ESRMNT: Errno : 69; /* Srmount error */ +ECOMM: Errno : 70; /* Communication error on send */ +EPROTO: Errno : 71; /* Protocol error */ +EMULTIHOP: Errno : 72; /* Multihop attempted */ +EDOTDOT: Errno : 73; /* RFS specific error */ +EBADMSG: Errno : 74; /* Not a data message */ +EOVERFLOW: Errno : 75; /* Value too large for defined data type */ +ENOTUNIQ: Errno : 76; /* Name not unique on network */ +EBADFD: Errno : 77; /* File descriptor in bad state */ +EREMCHG: Errno : 78; /* Remote address changed */ +ELIBACC: Errno : 79; /* Can not access a needed shared library */ +ELIBBAD: Errno : 80; /* Accessing a corrupted shared library */ +ELIBSCN: Errno : 81; /* .lib section in a.out corrupted */ +ELIBMAX: Errno : 82; /* Attempting to link in too many shared libraries */ +ELIBEXEC: Errno : 83; /* Cannot exec a shared library directly */ +EILSEQ: Errno : 84; /* Illegal byte sequence */ +ERESTART: Errno : 85; /* Interrupted system call should be restarted */ +ESTRPIPE: Errno : 86; /* Streams pipe error */ +EUSERS: Errno : 87; /* Too many users */ +ENOTSOCK: Errno : 88; /* Socket operation on non-socket */ +EDESTADDRREQ: Errno : 89; /* Destination address required */ +EMSGSIZE: Errno : 90; /* Message too long */ +EPROTOTYPE: Errno : 91; /* Protocol wrong type for socket */ +ENOPROTOOPT: Errno : 92; /* Protocol not available */ +EPROTONOSUPPORT: Errno : 93; /* Protocol not supported */ +ESOCKTNOSUPPORT: Errno : 94; /* Socket type not supported */ +EOPNOTSUPP: Errno : 95; /* Operation not supported on transport endpoint */ +EPFNOSUPPORT: Errno : 96; /* Protocol family not supported */ +EAFNOSUPPORT: Errno : 97; /* Address family not supported by protocol */ +EADDRINUSE: Errno : 98; /* Address already in use */ +EADDRNOTAVAIL: Errno : 99; /* Cannot assign requested address */ +ENETDOWN: Errno : 100; /* Network is down */ +ENETUNREACH: Errno : 101; /* Network is unreachable */ +ENETRESET: Errno : 102; /* Network dropped connection because of reset */ +ECONNABORTED: Errno : 103; /* Software caused connection abort */ +ECONNRESET: Errno : 104; /* Connection reset by peer */ +ENOBUFS: Errno : 105; /* No buffer space available */ +EISCONN: Errno : 106; /* Transport endpoint is already connected */ +ENOTCONN: Errno : 107; /* Transport endpoint is not connected */ +ESHUTDOWN: Errno : 108; /* Cannot send after transport endpoint shutdown */ +ETOOMANYREFS: Errno : 109; /* Too many references: cannot splice */ +ETIMEDOUT: Errno : 110; /* Connection timed out */ +ECONNREFUSED: Errno : 111; /* Connection refused */ +EHOSTDOWN: Errno : 112; /* Host is down */ +EHOSTUNREACH: Errno : 113; /* No route to host */ +EALREADY: Errno : 114; /* Operation already in progress */ +EINPROGRESS: Errno : 115; /* Operation now in progress */ +ESTALE: Errno : 116; /* Stale file handle */ +EUCLEAN: Errno : 117; /* Structure needs cleaning */ +ENOTNAM: Errno : 118; /* Not a XENIX named type file */ +ENAVAIL: Errno : 119; /* No XENIX semaphores available */ +EISNAM: Errno : 120; /* Is a named type file */ +EREMOTEIO: Errno : 121; /* Remote I/O error */ +EDQUOT: Errno : 122; /* Quota exceeded */ + +ENOMEDIUM: Errno : 123; /* No medium found */ +EMEDIUMTYPE: Errno : 124; /* Wrong medium type */ +ECANCELED: Errno : 125; /* Operation Canceled */ +ENOKEY: Errno : 126; /* Required key not available */ +EKEYEXPIRED: Errno : 127; /* Key has expired */ +EKEYREVOKED: Errno : 128; /* Key has been revoked */ +EKEYREJECTED: Errno : 129; /* Key was rejected by service */ + +/* for robust mutexes */ +EOWNERDEAD: Errno : 130; /* Owner died */ +ENOTRECOVERABLE: Errno : 131; /* State not recoverable */ + +ERFKILL: Errno : 132; /* Operation not possible due to RF-kill */ + +EHWPOISON: Errno : 133; /* Memory page has hardware error */ O_RDONLY :: 0x00000; O_WRONLY :: 0x00001; @@ -152,22 +253,6 @@ X_OK :: 1; // Test for execute permission W_OK :: 2; // Test for write permission R_OK :: 4; // Test for read permission -TimeSpec :: struct { - tv_sec : i64, /* seconds */ - tv_nsec : i64, /* nanoseconds */ -}; - -CLOCK_REALTIME :: 0; -CLOCK_MONOTONIC :: 1; -CLOCK_PROCESS_CPUTIME_ID :: 2; -CLOCK_THREAD_CPUTIME_ID :: 3; -CLOCK_MONOTONIC_RAW :: 4; -CLOCK_REALTIME_COARSE :: 5; -CLOCK_MONOTONIC_COARSE :: 6; -CLOCK_BOOTTIME :: 7; -CLOCK_REALTIME_ALARM :: 8; -CLOCK_BOOTTIME_ALARM :: 9; - SYS_GETTID: Syscall : 186; foreign libc { @@ -180,6 +265,7 @@ foreign libc { @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int ---; @(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 ---; @(link_name="gettid") _unix_gettid :: proc() -> u64 ---; + @(link_name="getpagesize") _unix_getpagesize :: proc() -> i32 ---; @(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^Stat) -> int ---; @(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^Stat) -> int ---; @(link_name="access") _unix_access :: proc(path: cstring, mask: int) -> int ---; @@ -190,10 +276,6 @@ foreign libc { @(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr ---; @(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---; - @(link_name="clock_gettime") _unix_clock_gettime :: proc(clock_id: u64, timespec: ^TimeSpec) ---; - @(link_name="nanosleep") _unix_nanosleep :: proc(requested: ^TimeSpec, remaining: ^TimeSpec) -> int ---; - @(link_name="sleep") _unix_sleep :: proc(seconds: u64) -> int ---; - @(link_name="exit") _unix_exit :: proc(status: int) -> ! ---; } foreign dl { @@ -349,25 +431,6 @@ exit :: proc(code: int) -> ! { _unix_exit(code); } -clock_gettime :: proc(clock_id: u64) -> TimeSpec { - ts : TimeSpec; - _unix_clock_gettime(clock_id, &ts); - return ts; -} - -sleep :: proc(seconds: u64) -> int { - - return _unix_sleep(seconds); -} - -nanosleep :: proc(nanoseconds: i64) -> int { - assert(nanoseconds <= 999999999); - requested, remaining : TimeSpec; - requested = TimeSpec{tv_nsec = nanoseconds}; - - return _unix_nanosleep(&requested, &remaining); -} - current_thread_id :: proc "contextless" () -> int { return syscall(SYS_GETTID); } @@ -393,6 +456,16 @@ 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 do return page_size; + + page_size = int(_unix_getpagesize()); + return page_size; +} + _alloc_command_line_arguments :: proc() -> []string { res := make([]string, len(runtime.args__)); diff --git a/core/os/os_windows.odin b/core/os/os_windows.odin index e45cf9f5f..f433a2517 100644 --- a/core/os/os_windows.odin +++ b/core/os/os_windows.odin @@ -210,7 +210,6 @@ get_std_handle :: proc(h: int) -> Handle { - last_write_time :: proc(fd: Handle) -> (File_Time, Errno) { file_info: win32.By_Handle_File_Information; if !win32.get_file_information_by_handle(win32.Handle(fd), &file_info) { @@ -253,6 +252,18 @@ heap_free :: proc(ptr: rawptr) { win32.heap_free(win32.get_process_heap(), 0, ptr); } +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 do return page_size; + + info: win32.System_Info; + win32.get_system_info(&info); + page_size = int(info.page_size); + return page_size; +} + exit :: proc(code: int) -> ! { win32.exit_process(u32(code)); -- cgit v1.2.3