os_unix.c (4503B)
1 #include <dlfcn.h> 2 #include <fcntl.h> 3 #include <poll.h> 4 #include <sys/mman.h> 5 #include <sys/stat.h> 6 #include <unistd.h> 7 8 #define OS_INVALID_FILE (-1) 9 typedef i32 os_file; 10 typedef struct { 11 os_file file; 12 char *name; 13 } os_pipe; 14 15 typedef struct timespec os_filetime; 16 17 typedef void *os_library_handle; 18 19 #define ERROR_FILE_STATS (os_file_stats){.timestamp = (os_filetime){0}, .filesize = -1} 20 typedef struct { 21 size filesize; 22 os_filetime timestamp; 23 } os_file_stats; 24 25 static Arena 26 os_alloc_arena(Arena a, size capacity) 27 { 28 size pagesize = sysconf(_SC_PAGESIZE); 29 if (capacity % pagesize != 0) 30 capacity += pagesize - capacity % pagesize; 31 32 size oldsize = a.end - a.beg; 33 if (oldsize > capacity) 34 return a; 35 36 if (a.beg) 37 munmap(a.beg, oldsize); 38 39 a.beg = mmap(0, capacity, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); 40 if (a.beg == MAP_FAILED) 41 die("os_alloc_arena: couldn't allocate memory\n"); 42 a.end = a.beg + capacity; 43 return a; 44 } 45 46 static s8 47 os_read_file(Arena *a, char *fname, size fsize) 48 { 49 i32 fd = open(fname, O_RDONLY); 50 if (fd < 0) 51 die("os_read_file: couldn't open file: %s\n", fname); 52 53 s8 ret = s8alloc(a, fsize); 54 55 size rlen = read(fd, ret.data, ret.len); 56 close(fd); 57 58 if (rlen != ret.len) 59 die("os_read_file: couldn't read file: %s\n", fname); 60 61 return ret; 62 } 63 64 static b32 65 os_write_file(char *fname, s8 raw) 66 { 67 i32 fd = open(fname, O_WRONLY|O_TRUNC|O_CREAT, 0600); 68 if (fd < 0) 69 return 0; 70 size wlen = write(fd, raw.data, raw.len); 71 close(fd); 72 return wlen == raw.len; 73 } 74 75 static os_file_stats 76 os_get_file_stats(char *fname) 77 { 78 struct stat st; 79 80 if (stat(fname, &st) < 0) { 81 return ERROR_FILE_STATS; 82 } 83 84 return (os_file_stats){ 85 .filesize = st.st_size, 86 .timestamp = st.st_mtim, 87 }; 88 } 89 90 static os_pipe 91 os_open_named_pipe(char *name) 92 { 93 mkfifo(name, 0660); 94 return (os_pipe){.file = open(name, O_RDONLY|O_NONBLOCK), .name = name}; 95 } 96 97 static void 98 os_close_named_pipe(os_pipe p) 99 { 100 close(p.file); 101 unlink(p.name); 102 } 103 104 static b32 105 os_poll_pipe(os_pipe p) 106 { 107 struct pollfd pfd = {.fd = p.file, .events = POLLIN}; 108 poll(&pfd, 1, 0); 109 return !!(pfd.revents & POLLIN); 110 } 111 112 static size 113 os_read_pipe_data(os_pipe p, void *buf, size len) 114 { 115 size r = 0, total_read = 0; 116 do { 117 if (r != -1) 118 total_read += r; 119 r = read(p.file, buf + total_read, len - total_read); 120 } while (r); 121 return total_read; 122 } 123 124 static BeamformerParametersFull * 125 os_open_shared_memory_area(char *name) 126 { 127 i32 fd = shm_open(name, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); 128 if (fd == -1) 129 return NULL; 130 131 if (ftruncate(fd, sizeof(BeamformerParametersFull)) == -1) { 132 close(fd); 133 return NULL; 134 } 135 136 BeamformerParametersFull *new; 137 new = mmap(NULL, sizeof(*new), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 138 close(fd); 139 140 if (new == MAP_FAILED) 141 return NULL; 142 143 return new; 144 } 145 146 static void 147 os_remove_shared_memory(char *name) 148 { 149 shm_unlink(name); 150 } 151 152 /* NOTE: complete garbage because there is no standarized copyfile() in POSix */ 153 static b32 154 os_copy_file(char *name, char *new) 155 { 156 b32 result = 0; 157 struct stat sb; 158 if (stat(name, &sb) < 0) 159 return 0; 160 161 i32 fd_old = open(name, O_RDONLY); 162 i32 fd_new = open(new, O_WRONLY|O_TRUNC, sb.st_mode); 163 164 if (fd_old < 0 || fd_new < 0) 165 goto ret; 166 u8 buf[4096]; 167 size copied = 0; 168 while (copied != sb.st_size) { 169 size r = read(fd_old, buf, ARRAY_COUNT(buf)); 170 if (r < 0) goto ret; 171 size w = write(fd_new, buf, r); 172 if (w < 0) goto ret; 173 copied += w; 174 } 175 result = 1; 176 ret: 177 if (fd_old != -1) close(fd_old); 178 if (fd_new != -1) close(fd_new); 179 return result; 180 } 181 182 static os_library_handle 183 os_load_library(char *name, char *temp_name) 184 { 185 if (temp_name) { 186 if (os_copy_file(name, temp_name)) 187 name = temp_name; 188 } 189 os_library_handle res = dlopen(name, RTLD_NOW|RTLD_LOCAL); 190 if (!res) 191 TraceLog(LOG_WARNING, "os_load_library(%s): %s\n", name, dlerror()); 192 193 if (temp_name) 194 unlink(temp_name); 195 196 return res; 197 } 198 199 static void * 200 os_lookup_dynamic_symbol(os_library_handle h, char *name) 201 { 202 if (!h) 203 return 0; 204 void *res = dlsym(h, name); 205 if (!res) 206 TraceLog(LOG_WARNING, "os_lookup_dynamic_symbol(%s): %s\n", name, dlerror()); 207 return res; 208 } 209 210 static void 211 os_unload_library(os_library_handle h) 212 { 213 /* NOTE: glibc is buggy gnuware so we need to check this */ 214 if (h) 215 dlclose(h); 216 } 217 218 static b32 219 os_filetime_is_newer(os_filetime a, os_filetime b) 220 { 221 os_filetime result; 222 result.tv_sec = a.tv_sec - b.tv_sec; 223 result.tv_nsec = a.tv_nsec - b.tv_nsec; 224 if (result.tv_nsec < 0) { 225 result.tv_sec--; 226 result.tv_nsec += 1000000000L; 227 } 228 return result.tv_sec + result.tv_nsec > 0; 229 }