os_linux.c (3871B)
1 /* See LICENSE for license details. */ 2 3 /* NOTE(rnp): provides the platform layer for the beamformer. This code must 4 * be provided by any platform the beamformer is ported to. */ 5 6 #define OS_SHARED_MEMORY_NAME "/ogl_beamformer_shared_memory" 7 8 #define OS_PATH_SEPARATOR_CHAR '/' 9 #define OS_PATH_SEPARATOR "/" 10 11 #include "util.h" 12 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <linux/futex.h> 16 #include <poll.h> 17 #include <pthread.h> 18 #include <sys/auxv.h> 19 #include <sys/inotify.h> 20 #include <sys/mman.h> 21 #include <sys/stat.h> 22 #include <sys/syscall.h> 23 #include <sys/sysinfo.h> 24 #include <unistd.h> 25 26 function b32 27 os_write_file(i32 file, void *data, i64 length) 28 { 29 i64 offset = 0; 30 while (offset < length) { 31 iz r = write(file, (u8 *)data + offset, length - offset); 32 if (r < 0 && errno != EINTR) break; 33 if (r >= 0) offset += r; 34 } 35 return offset == length; 36 } 37 38 function no_return void 39 os_exit(i32 code) 40 { 41 _exit(code); 42 unreachable(); 43 } 44 45 function u64 46 os_get_timer_frequency(void) 47 { 48 return 1000000000ULL; 49 } 50 51 function u64 52 os_get_timer_counter(void) 53 { 54 struct timespec time = {0}; 55 clock_gettime(CLOCK_MONOTONIC, &time); 56 u64 result = (u64)time.tv_sec * 1000000000ULL + (u64)time.tv_nsec; 57 return result; 58 } 59 60 function u64 61 os_number_of_processors(void) 62 { 63 u64 set[128 / sizeof(u64)] = {0}; 64 syscall(SYS_sched_getaffinity, 0, sizeof(set), set); 65 66 u64 result = 0; 67 for EachElement(set, it) 68 result += popcount_u64(set[it]); 69 return result > 0 ? result : 1; 70 } 71 72 function OS_ALLOC_ARENA_FN(os_alloc_arena) 73 { 74 Arena result = {0}; 75 capacity = round_up_to(capacity, ARCH_X64? KB(4) : getauxval(AT_PAGESZ)); 76 void *memory = mmap(0, (uz)capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 77 if (memory != MAP_FAILED) { 78 result.beg = memory; 79 result.end = result.beg + capacity; 80 asan_poison_region(result.beg, result.end - result.beg); 81 } 82 return result; 83 } 84 85 BEAMFORMER_IMPORT OS_READ_ENTIRE_FILE_FN(os_read_entire_file) 86 { 87 i64 result = 0; 88 struct stat sb; 89 i32 fd = open(file, O_RDONLY); 90 if (fd >= 0 && fstat(fd, &sb) >= 0) { 91 if (buffer_capacity >= sb.st_size) { 92 do { 93 i64 rlen = read(fd, (u8 *)buffer + result, sb.st_size - result); 94 if (rlen > 0) result += rlen; 95 } while (result != sb.st_size && errno != EINTR); 96 if (result != sb.st_size) result = 0; 97 } 98 } 99 if (fd >= 0) close(fd); 100 101 return result; 102 } 103 104 function OS_WRITE_NEW_FILE_FN(os_write_new_file) 105 { 106 b32 result = 0; 107 i32 fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600); 108 if (fd != INVALID_FILE) { 109 result = os_write_file(fd, raw.data, raw.len); 110 close(fd); 111 } 112 return result; 113 } 114 115 function b32 116 os_file_exists(char *path) 117 { 118 struct stat st; 119 b32 result = stat(path, &st) == 0; 120 return result; 121 } 122 123 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */ 124 function b32 125 os_copy_file(char *name, char *new) 126 { 127 b32 result = 0; 128 struct stat sb; 129 if (stat(name, &sb) == 0) { 130 i32 fd_old = open(name, O_RDONLY); 131 i32 fd_new = open(new, O_WRONLY|O_CREAT, sb.st_mode); 132 if (fd_old >= 0 && fd_new >= 0) { 133 u8 buf[4096]; 134 iz copied = 0; 135 while (copied != sb.st_size) { 136 iz r = read(fd_old, buf, countof(buf)); 137 if (r < 0) break; 138 iz w = write(fd_new, buf, (uz)r); 139 if (w < 0) break; 140 copied += w; 141 } 142 result = copied == sb.st_size; 143 } 144 if (fd_old != -1) close(fd_old); 145 if (fd_new != -1) close(fd_new); 146 } 147 return result; 148 } 149 150 BEAMFORMER_IMPORT OS_WAIT_ON_ADDRESS_FN(os_wait_on_address) 151 { 152 struct timespec *timeout = 0, timeout_value; 153 if (timeout_ms != (u32)-1) { 154 timeout_value.tv_sec = timeout_ms / 1000; 155 timeout_value.tv_nsec = (timeout_ms % 1000) * 1000000; 156 timeout = &timeout_value; 157 } 158 return syscall(SYS_futex, value, FUTEX_WAIT, current, timeout, 0, 0) == 0; 159 } 160 161 BEAMFORMER_IMPORT OS_WAKE_ALL_WAITERS_FN(os_wake_all_waiters) 162 { 163 if (sync) { 164 atomic_store_u32(sync, 0); 165 syscall(SYS_futex, sync, FUTEX_WAKE, I32_MAX, 0, 0, 0); 166 } 167 }