GCC Code Coverage Report


Directory: src/gate/
File: src/gate/platform_posix.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 368 658 55.9%
Functions: 47 61 77.0%
Branches: 114 339 33.6%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28 #include "gate/platforms.h"
29
30 #if defined(GATE_SYS_POSIX) && !defined(GATE_SYS_BEOS)
31
32 #define __USE_GNU
33 #include <unistd.h>
34 #include <sys/time.h>
35 #include <time.h>
36 #if defined(GATE_SYS_ANDROID) || defined(GATE_SYS_BEOS)
37 # define GATE_SYS_USE_POSIX_SEMAPHORE
38 #endif
39
40 #if defined(HAVE_SEMTIMEDOP)
41 # define _GNU_SOURCE
42 # include <sys/sem.h>
43 #endif
44
45 #include <sys/ipc.h>
46 #include <sys/types.h>
47 #include <errno.h>
48 #include <pthread.h>
49 #include <sched.h>
50 #if defined(GATE_SYS_USE_POSIX_SEMAPHORE)
51 # include <fcntl.h>
52 # include <semaphore.h>
53 #else
54 # include <sys/shm.h>
55 # include <sys/sem.h>
56 #endif
57
58 #if defined(GATE_SYS_DARWIN)
59 # include <mach/clock.h>
60 # include <mach/mach.h>
61 #endif
62
63 #include <stdlib.h>
64 #include <stdarg.h>
65 #include <string.h>
66 #include <sys/stat.h>
67 #include <sys/ioctl.h>
68 #include <sys/wait.h>
69 #include <sys/file.h>
70 #include <fcntl.h>
71 #include <pwd.h>
72 #include <grp.h>
73 #include <signal.h>
74 #include <sys/select.h>
75 #include <dlfcn.h>
76
77 #include "gate/results.h"
78 #include "gate/atomics.h"
79 #include "gate/debugging.h"
80 #include "gate/strings.h"
81
82 #if defined(GATE_SYS_ANDROID)
83 # define GATE_SYS_POSIX_HAS_FLOCK
84 #else
85 # define GATE_SYS_POSIX_HAS_FLOCK
86 # define GATE_SYS_POSIX_HAS_LOCKF
87 #endif
88
89 static gate_atomic_int_t global_platform_mutex_usable = 0;
90 static gate_atomic_lock_t global_platform_mutex_init_lock = GATE_ATOMIC_LOCK_INIT;
91
92 static gate_atomic_flag_t global_platform_mutex_init_done = GATE_ATOMIC_FLAG_INIT;
93 static pthread_mutex_t global_platform_mutex;
94
95 667 static gate_result_t global_platform_mutex_init()
96 {
97 667 gate_result_t ret = GATE_RESULT_OK;
98 667 const gate_int32_t init_state = gate_atomic_int_get(&global_platform_mutex_usable);
99
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 634 times.
667 if (0 == init_state)
100 {
101 33 gate_atomic_lock_acquire(&global_platform_mutex_init_lock);
102 {
103
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 if (!gate_atomic_flag_set(&global_platform_mutex_init_done))
104 {
105
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
33 if (0 != pthread_mutex_init(&global_platform_mutex, NULL))
106 {
107 ret = GATE_RESULT_FAILED;
108 gate_atomic_flag_clear(&global_platform_mutex_init_done);
109 }
110 else
111 {
112 33 gate_atomic_int_set(&global_platform_mutex_usable, 1);
113 }
114 }
115 }
116 33 gate_atomic_lock_release(&global_platform_mutex_init_lock);
117 }
118 667 return ret;
119 }
120
121 33 gate_result_t gate_platform_init(void)
122 {
123 33 gate_result_t ret = GATE_RESULT_OK;
124
125 33 global_platform_mutex_init();
126
127 33 return ret;
128 }
129
130 2 void gate_platform_exit(int exit_code)
131 {
132 2 exit(exit_code);
133 }
134
135 17 void gate_platform_atexit(void(*func)(void))
136 {
137 17 atexit(func);
138 17 }
139
140 317 gate_result_t gate_platform_lock()
141 {
142 317 gate_result_t ret = global_platform_mutex_init();
143
1/2
✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
317 if (GATE_SUCCEEDED(ret))
144 {
145
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 317 times.
317 if (0 != pthread_mutex_lock(&global_platform_mutex))
146 {
147 ret = GATE_RESULT_FAILED;
148 }
149 }
150 317 return ret;
151 }
152 317 gate_result_t gate_platform_unlock()
153 {
154 317 gate_result_t ret = global_platform_mutex_init();
155
1/2
✓ Branch 0 taken 317 times.
✗ Branch 1 not taken.
317 if (GATE_SUCCEEDED(ret))
156 {
157
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 317 times.
317 if (0 != pthread_mutex_unlock(&global_platform_mutex))
158 {
159 ret = GATE_RESULT_FAILED;
160 }
161 }
162 317 return ret;
163 }
164 1741650 gate_int32_t gate_platform_get_last_error()
165 {
166 1741650 return (gate_int32_t)errno;
167 }
168 gate_result_t gate_platform_set_last_error(gate_int32_t platform_error_code)
169 {
170 gate_result_t ret = GATE_RESULT_OK;
171 errno = (int)platform_error_code;
172 return ret;
173 }
174
175 151 static gate_result_t gate_posix_convert_errno(int error_code)
176 {
177 151 gate_result_t ret = GATE_RESULT_FAILED;
178
179
5/75
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✓ Branch 27 taken 1 times.
✓ Branch 28 taken 2 times.
✗ Branch 29 not taken.
✗ Branch 30 not taken.
✗ Branch 31 not taken.
✗ Branch 32 not taken.
✗ Branch 33 not taken.
✗ Branch 34 not taken.
✗ Branch 35 not taken.
✗ Branch 36 not taken.
✗ Branch 37 not taken.
✗ Branch 38 not taken.
✗ Branch 39 not taken.
✗ Branch 40 not taken.
✗ Branch 41 not taken.
✗ Branch 42 not taken.
✓ Branch 43 taken 145 times.
✗ Branch 44 not taken.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✗ Branch 49 not taken.
✗ Branch 50 not taken.
✗ Branch 51 not taken.
✗ Branch 52 not taken.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
✗ Branch 59 not taken.
✗ Branch 60 not taken.
✗ Branch 61 not taken.
✗ Branch 62 not taken.
✗ Branch 63 not taken.
✗ Branch 64 not taken.
✗ Branch 65 not taken.
✗ Branch 66 not taken.
✗ Branch 67 not taken.
✗ Branch 68 not taken.
✗ Branch 69 not taken.
✗ Branch 70 not taken.
✗ Branch 71 not taken.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
151 switch (error_code)
180 {
181 1 case 0: ret = GATE_RESULT_OK; break;
182 case E2BIG: ret = GATE_RESULT_OUTOFBOUNDS; break;
183 case EACCES: ret = GATE_RESULT_ACCESSDENIED; break;
184 case EADDRINUSE: ret = GATE_RESULT_NOTREADY; break;
185 case EADDRNOTAVAIL: ret = GATE_RESULT_NOTAVAILABLE; break;
186 case EAFNOSUPPORT: ret = GATE_RESULT_NOTSUPPORTED; break;
187 /*case EWOULDBLOCK: ret = GATE_RESULT_BLOCKED; break;*/
188 case EAGAIN: ret = GATE_RESULT_BLOCKED; break;
189 case EALREADY: ret = GATE_RESULT_ALREADYEXISTS; break;
190 2 case EBADF: ret = GATE_RESULT_INVALIDDATA; break;
191 case EBADMSG: ret = GATE_RESULT_INVALIDCONTENT; break;
192 case EBUSY: ret = GATE_RESULT_NOTREADY; break;
193 case ECANCELED: ret = GATE_RESULT_CANCELED; break;
194 case ECHILD: ret = GATE_RESULT_EXECUTIONFAILED; break;
195 case ECONNABORTED: ret = GATE_RESULT_CANCELED; break;
196 case ECONNREFUSED: ret = GATE_RESULT_ACCESSDENIED; break;
197 case ECONNRESET: ret = GATE_RESULT_INVALIDSTATE; break;
198 case EDEADLK: ret = GATE_RESULT_LOCKED; break;
199 case EDESTADDRREQ: ret = GATE_RESULT_INVALIDDATA; break;
200 case EDOM: ret = GATE_RESULT_ARITHMETICERROR; break;
201 /*case EDQUOT: ret = GATE_RESULT_FAILED; break;*/
202 case EEXIST: ret = GATE_RESULT_ALREADYEXISTS; break;
203 case EFAULT: ret = GATE_RESULT_BADADDRESS; break;
204 case EFBIG: ret = GATE_RESULT_OUTOFBOUNDS; break;
205 case EHOSTUNREACH: ret = GATE_RESULT_NOTAVAILABLE; break;
206 case EIDRM: ret = GATE_RESULT_NOTAVAILABLE; break;
207 case EILSEQ: ret = GATE_RESULT_INVALIDDATA; break;
208 case EINPROGRESS: ret = GATE_RESULT_LOCKED; break;
209 case EINTR: ret = GATE_RESULT_EXECUTIONINTERRUPTED; break;
210 1 case EINVAL: ret = GATE_RESULT_INVALIDARG; break;
211 2 case EIO: ret = GATE_RESULT_INVALIDDATA; break;
212 case EISCONN: ret = GATE_RESULT_INVALIDSTATE; break;
213 case EISDIR: ret = GATE_RESULT_INVALIDSTATE; break;
214 case ELOOP: ret = GATE_RESULT_OUTOFRESOURCES; break;
215 case EMFILE: ret = GATE_RESULT_OUTOFRESOURCES; break;
216 case EMLINK: ret = GATE_RESULT_OUTOFRESOURCES; break;
217 case EMSGSIZE: ret = GATE_RESULT_OUTOFBOUNDS; break;
218 /*case EMULTIHOP: ret = GATE_RESULT_FAILED; break;*/
219 case ENAMETOOLONG: ret = GATE_RESULT_OUTOFBOUNDS; break;
220 case ENETDOWN: ret = GATE_RESULT_NOTAVAILABLE; break;
221 case ENETRESET: ret = GATE_RESULT_CANCELED; break;
222 case ENETUNREACH: ret = GATE_RESULT_NOTAVAILABLE; break;
223 case ENFILE: ret = GATE_RESULT_OUTOFRESOURCES; break;
224 case ENOBUFS: ret = GATE_RESULT_OUTOFMEMORY; break;
225 #ifdef ENODATA
226 case ENODATA: ret = GATE_RESULT_INVALIDCONTENT; break;
227 #endif
228 case ENODEV: ret = GATE_RESULT_NOTAVAILABLE; break;
229 145 case ENOENT: ret = GATE_RESULT_NOTAVAILABLE; break;
230 case ENOEXEC: ret = GATE_RESULT_INVALIDHEADER; break;
231 case ENOLCK: ret = GATE_RESULT_NOTAVAILABLE; break;
232 /*case ENOLINK: ret = GATE_RESULT_; break;*/
233 case ENOMEM: ret = GATE_RESULT_OUTOFMEMORY; break;
234 case ENOMSG: ret = GATE_RESULT_OUTOFRESOURCES; break;
235 case ENOPROTOOPT: ret = GATE_RESULT_NOTAVAILABLE; break;
236 case ENOSPC: ret = GATE_RESULT_OUTOFRESOURCES; break;
237 #ifdef ENOSR
238 case ENOSR: ret = GATE_RESULT_NOTAVAILABLE; break;
239 #endif
240 #ifdef ENOSTR
241 case ENOSTR: ret = GATE_RESULT_NOTAVAILABLE; break;
242 #endif
243 case ENOSYS: ret = GATE_RESULT_NOTSUPPORTED; break;
244 case ENOTCONN: ret = GATE_RESULT_INVALIDSTATE; break;
245 case ENOTDIR: ret = GATE_RESULT_INVALIDSTATE; break;
246 case ENOTEMPTY: ret = GATE_RESULT_INVALIDSTATE; break;
247 case ENOTSOCK: ret = GATE_RESULT_INCORRECTTYPE; break;
248 case ENOTSUP: ret = GATE_RESULT_NOTSUPPORTED; break;
249 case ENOTTY: ret = GATE_RESULT_INCORRECTTYPE; break;
250 case ENXIO: ret = GATE_RESULT_NOTAVAILABLE; break;
251 case EOVERFLOW: ret = GATE_RESULT_OVERFLOW; break;
252 case EPERM: ret = GATE_RESULT_PERMISSIONDENIED; break;
253 case EPIPE: ret = GATE_RESULT_NOTREADY; break;
254 case EPROTO: ret = GATE_RESULT_INVALIDDATA; break;
255 case EPROTONOSUPPORT: ret = GATE_RESULT_NOTSUPPORTED; break;
256 case EPROTOTYPE: ret = GATE_RESULT_INCORRECTTYPE; break;
257 case ERANGE: ret = GATE_RESULT_OUTOFBOUNDS; break;
258 case EROFS: ret = GATE_RESULT_LOCKED; break;
259 case ESPIPE: ret = GATE_RESULT_INVALIDARG; break;
260 case ESRCH: ret = GATE_RESULT_NOMATCH; break;
261 /*case ESTALE: ret = GATE_RESULT_FAILED; break;*/
262 #ifdef ETIME
263 case ETIME: ret = GATE_RESULT_TIMEOUT; break;
264 #endif
265 case ETIMEDOUT: ret = GATE_RESULT_TIMEOUT; break;
266 case ETXTBSY: ret = GATE_RESULT_NOTREADY; break;
267 case EXDEV: ret = GATE_RESULT_NOTSUPPORTED; break;
268 default: ret = GATE_RESULT_FAILED; break;
269 }
270 151 return ret;
271 }
272
273 4 gate_result_t gate_platform_print_error(gate_int32_t platform_error_code, char* buffer, gate_size_t buffer_len)
274 {
275 gate_result_t result;
276 4 char* error_text = NULL;
277
278
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
4 if ((buffer != NULL) && (buffer_len != 0))
279 {
280 1 result = gate_platform_lock();
281
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (GATE_SUCCEEDED(result))
282 {
283 1 error_text = strerror((int)platform_error_code);
284 1 gate_str_print_text(buffer, buffer_len, error_text, gate_str_length(error_text));
285 1 gate_platform_unlock();
286 }
287 }
288 4 return gate_posix_convert_errno(platform_error_code);
289 }
290
291 149 int gate_posix_errno(gate_result_t* result)
292 {
293 149 int ret = errno;
294
295
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 2 times.
149 if (result != NULL)
296 {
297 147 *result = gate_posix_convert_errno(ret);
298 }
299 149 return ret;
300 }
301 void gate_posix_set_errno(int code)
302 {
303 errno = code;
304 }
305
306
307 54 void gate_posix_block_signals(gate_posix_sigblocker_t* blocker, int sig1, int sig2, ...)
308 {
309 int arg;
310 va_list args;
311
312 54 gate_mem_clear(blocker, sizeof(gate_posix_sigblocker_t));
313 54 sigemptyset(&blocker->signals);
314 54 sigaddset(&blocker->signals, sig1);
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (sig2 != 0)
317 {
318 sigaddset(&blocker->signals, sig2);
319 va_start(args, sig2);
320 while (0 != (arg = va_arg(args, int)))
321 {
322 sigaddset(&blocker->signals, arg);
323 }
324 va_end(args);
325 }
326 54 blocker->unblock_required = (pthread_sigmask(SIG_BLOCK, &blocker->signals, &blocker->signals) == 0);
327 54 }
328
329 54 void gate_posix_unblock_signals(gate_posix_sigblocker_t* blocker)
330 {
331
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 if (blocker->unblock_required)
332 {
333 54 pthread_sigmask(SIG_SETMASK, &blocker->signals, 0);
334 }
335 54 gate_mem_clear(blocker, sizeof(gate_posix_sigblocker_t));
336 54 }
337
338 static int gate_posix_inheritable_fds[1024];
339 static gate_size_t gate_posix_inheritable_fd_count = 0;
340 static gate_atomic_lock_t gate_posix_inheritable_lock = GATE_ATOMIC_LOCK_INIT;
341
342 gate_result_t gate_posix_register_inheritable_fd(int fd)
343 {
344 gate_size_t ndx;
345 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
346
347 for (ndx = 0; ndx != gate_posix_inheritable_fd_count; ++ndx)
348 {
349 if (gate_posix_inheritable_fds[ndx] == fd)
350 {
351 --gate_posix_inheritable_fd_count;
352 break;
353 }
354 }
355 gate_posix_inheritable_fds[ndx] = fd;
356 ++gate_posix_inheritable_fd_count;
357
358 gate_atomic_lock_release(&gate_posix_inheritable_lock);
359 return GATE_RESULT_OK;
360 }
361 gate_result_t gate_posix_unregister_inheritable_fd(int fd)
362 {
363 gate_result_t ret = GATE_RESULT_NOMATCH;
364 gate_size_t ndx;
365
366 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
367 if (gate_posix_inheritable_fd_count != 0)
368 {
369 for (ndx = 0; ndx < gate_posix_inheritable_fd_count; ++ndx)
370 {
371 if (gate_posix_inheritable_fds[ndx] == fd)
372 {
373 gate_posix_inheritable_fds[ndx] = gate_posix_inheritable_fds[gate_posix_inheritable_fd_count - 1];
374 --gate_posix_inheritable_fd_count;
375 ret = GATE_RESULT_OK;
376 break;
377 }
378 }
379 }
380 gate_atomic_lock_release(&gate_posix_inheritable_lock);
381
382 return ret;
383 }
384 10 gate_size_t gate_posix_get_inheritable_fds(int* fdbuffer, gate_size_t fdbuffer_length)
385 {
386 10 gate_size_t used = 0;
387 10 gate_size_t ndx = 0;
388
389 10 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
390 10 used = fdbuffer_length < gate_posix_inheritable_fd_count ? fdbuffer_length : gate_posix_inheritable_fd_count;
391
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 for (ndx = 0; ndx != used; ++ndx)
392 {
393 *fdbuffer = gate_posix_inheritable_fds[ndx];
394 ++fdbuffer;
395 }
396
397 10 gate_atomic_lock_release(&gate_posix_inheritable_lock);
398 10 return used;
399 }
400
401
402 6 int gate_posix_open(char const* path, int oflag, int mode)
403 {
404 6 return open(path, oflag, (mode_t)mode);
405 }
406 17825744 int gate_posix_close(int fd)
407 {
408 17825744 return close(fd);
409 }
410 1741634 ptrdiff_t gate_posix_read(int fd, void* buf, size_t nbyte)
411 {
412 ptrdiff_t result;
413 do
414 {
415 1741634 result = (ptrdiff_t)read(fd, buf, nbyte);
416
3/4
✓ Branch 0 taken 1741590 times.
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1741590 times.
1741634 } while ((result == -1) && (errno == EINTR));
417 1741634 return result;
418 }
419 42 ptrdiff_t gate_posix_write(int fd, void const* buf, size_t nbyte)
420 {
421 ptrdiff_t result;
422 do
423 {
424 42 result = (ptrdiff_t)write(fd, buf, nbyte);
425
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 } while ((result == -1) && (errno == EINTR));
426 42 return result;
427 }
428 5 gate_result_t gate_posix_await_read(int fd, gate_uint32_t timeout_ms)
429 {
430 fd_set read_set;
431 struct timeval timeout;
432
433
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
5 if (timeout_ms != 0xffffffff)
434 {
435 3 timeout.tv_sec = timeout_ms / 1000;
436 3 timeout.tv_usec = (timeout_ms % 1000) * 1000;
437 }
438 else
439 {
440 2 timeout.tv_sec = 0x7fffffff;
441 2 timeout.tv_usec = 0;
442 }
443
444 5 FD_ZERO(&read_set);
445 5 FD_SET(fd, &read_set);
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (-1 == select(fd + 1, &read_set, NULL, NULL, &timeout))
447 {
448 return GATE_RESULT_FAILED;
449 }
450
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!FD_ISSET(fd, &read_set))
452 {
453 return GATE_RESULT_TIMEOUT;
454 }
455 else
456 {
457 5 return GATE_RESULT_OK;
458 }
459 }
460
461
462 14 int gate_posix_flock(int fd, gate_posix_flock_operation operation)
463 {
464 #if defined(GATE_SYS_POSIX_HAS_FLOCK)
465 /* standard flock implemenation: */
466 int result;
467 int op;
468
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
✗ Branch 4 not taken.
14 switch (operation)
469 {
470 case gate_posix_flock_shared: op = LOCK_SH; break;
471 7 case gate_posix_flock_exclusive: op = LOCK_EX; break;
472 case gate_posix_flock_exclusive_test: op = (LOCK_EX | LOCK_NB); break;
473 7 case gate_posix_flock_unlock: op = LOCK_UN; break;
474 default:
475 gate_posix_set_errno(EINVAL);
476 return -1;
477 }
478
479 do
480 {
481 14 result = flock(fd, op);
482
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
14 } while ((result == -1) && (errno == EINTR));
483 14 return result;
484 #elif defined(GATE_SYS_POSIX_HAS_LOCKF)
485 /* flock emulation using lockf for the whole file */
486 int result;
487 gate_posix_lockf_cmd op;
488
489 switch (operation)
490 {
491 case gate_posix_flock_exclusive: op = gate_posix_lockf_lock; break;
492 case gate_posix_flock_exclusive_test: op = gate_posix_lockf_test; break;
493 case gate_posix_flock_unlock: op = gate_posix_lockf_unlock; break;
494 default:
495 gate_posix_set_errno(EINVAL);
496 return -1;
497 }
498
499 do
500 {
501 result = gate_posix_lockf(fd, op, 0, 0);
502 } while ((result == -1) && (errno == EINTR));
503 return result;
504 #else
505 /* no flock support at all */
506 gate_posix_set_errno(EACCES);
507 return -1;
508 #endif
509 }
510
511
512 int gate_posix_lockf(int fd, gate_posix_lockf_cmd cmd, gate_int64_t start_from, gate_int64_t length)
513 {
514 #if defined(GATE_SYS_POSIX_HAS_LOCKF)
515 /* standard lockf implementation */
516 int ret;
517 off_t current_pos;
518 int lock_cmd;
519 int stored_error;
520
521 do
522 {
523 switch (cmd)
524 {
525 case gate_posix_lockf_lock: lock_cmd = F_LOCK; break;
526 case gate_posix_lockf_testlock: lock_cmd = F_TLOCK; break;
527 case gate_posix_lockf_unlock: lock_cmd = F_ULOCK; break;
528 case gate_posix_lockf_test: lock_cmd = F_TEST; break;
529 default:
530 {
531 gate_posix_set_errno(EINVAL);
532 return -1;
533 }
534 }
535
536 current_pos = lseek(fd, 0, SEEK_CUR);
537 if (current_pos == (off_t)-1)
538 {
539 ret = -1;
540 break;
541 }
542 if (lseek(fd, (off_t)start_from, SEEK_SET) == (off_t)-1)
543 {
544 ret = -1;
545 break;
546 }
547
548 ret = lockf(fd, lock_cmd, (off_t)length);
549 stored_error = errno;
550
551 lseek(fd, (off_t)current_pos, SEEK_SET);
552 errno = stored_error;
553 } while (0);
554 return ret;
555 #elif defined(GATE_SYS_POSIX_HAS_FLOCK)
556 /* partially simulate lockf by locking the whole file with flock */
557 int ret = -1;
558 do
559 {
560 switch (cmd)
561 {
562 case gate_posix_lockf_lock:
563 {
564 ret = gate_posix_flock(fd, gate_posix_flock_exclusive);
565 break;
566 }
567 case gate_posix_lockf_unlock:
568 {
569 ret = gate_posix_flock(fd, gate_posix_flock_unlock);
570 break;
571 }
572 case gate_posix_lockf_testlock:
573 /* TODO: LOCK_NB implementation */
574 default:
575 {
576 gate_posix_set_errno(EINVAL);
577 return -1;
578 }
579 }
580 } while (0);
581 return ret;
582 #else
583 /* no lockf support at all */
584 gate_posix_set_errno(EACCES);
585 return -1;
586 #endif
587 }
588
589
590 int gate_posix_ioctl(int fd, unsigned long request, void* param)
591 {
592 return ioctl(fd, request, param);
593 }
594 30 gate_bool_t gate_posix_path_exists(char const* path)
595 {
596 struct stat filestat;
597
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 if (0 == stat(path, &filestat))
598 {
599 30 return true;
600 }
601 return false;
602 }
603
604 #if defined(GATE_SYS_ANDROID)
605 gate_size_t gate_posix_enum_users(uid_t* uids, gate_size_t max_uids)
606 {
607 return 0;
608 }
609 gate_result_t gate_posix_get_user_info(uid_t uid, gate_posix_user_info_t* info)
610 {
611 return GATE_RESULT_NOMATCH;
612 }
613 gate_result_t gate_posix_resolve_user_info(char const* user_name, gate_posix_user_info_t* info)
614 {
615 return GATE_RESULT_NOMATCH;
616 }
617 gate_size_t gate_posix_enum_groups(gid_t* gids, gate_size_t max_gids)
618 {
619 return 0;
620 }
621 gate_result_t gate_posix_get_usergroup_info(gid_t gid, gate_posix_group_info_t* info)
622 {
623 return GATE_RESULT_NOMATCH;
624 }
625 gate_result_t gate_posix_resolve_usergroup_info(char const* group_name, gate_posix_group_info_t* info)
626 {
627 return GATE_RESULT_NOMATCH;
628 }
629 #else
630
631
632 2 gate_size_t gate_posix_enum_users(uid_t* uids, gate_size_t max_uids)
633 {
634 struct passwd* entry;
635 2 gate_size_t index = 0;
636 gate_result_t result;
637
638 do
639 {
640 2 result = gate_platform_lock();
641
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(result);
642 2 setpwent();
643
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 2 times.
44 while (NULL != (entry = getpwent()))
644 {
645
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 if (index < max_uids)
646 {
647 42 uids[index] = entry->pw_uid;
648 42 ++index;
649 }
650 }
651 2 endpwent();
652 2 gate_platform_unlock();
653 } while (0);
654 2 return index;
655 }
656
657
658
659 97 static void gate_posix_load_user_info(struct passwd const* entry, gate_posix_user_info_t* info)
660 {
661 97 info->uid = entry->pw_uid;
662 97 info->gid = entry->pw_gid;
663 97 gate_str_print_text(info->name, sizeof(info->name), entry->pw_name, gate_str_length(entry->pw_name));
664 97 gate_str_print_text(info->gecos, sizeof(info->gecos), entry->pw_gecos, gate_str_length(entry->pw_gecos));
665 97 gate_str_print_text(info->home, sizeof(info->home), entry->pw_dir, gate_str_length(entry->pw_dir));
666 97 gate_str_print_text(info->shell, sizeof(info->shell), entry->pw_shell, gate_str_length(entry->pw_shell));
667 97 }
668 95 gate_result_t gate_posix_get_user_info(uid_t uid, gate_posix_user_info_t* info)
669 {
670 95 gate_result_t ret = GATE_RESULT_NOMATCH;
671 struct passwd* entry;
672
673 do
674 {
675 95 gate_mem_clear(info, sizeof(gate_posix_user_info_t));
676 95 ret = gate_platform_lock();
677
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 GATE_BREAK_IF_FAILED(ret);
678
679 do
680 {
681 95 entry = getpwuid(uid);
682
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 if (!entry)
683 {
684 ret = GATE_RESULT_NOMATCH;
685 break;
686 }
687
688 95 gate_posix_load_user_info(entry, info);
689 95 ret = GATE_RESULT_OK;
690 } while (0);
691
692 95 gate_platform_unlock();
693 } while (0);
694 95 return ret;
695 }
696 2 gate_result_t gate_posix_resolve_user_info(char const* user_name, gate_posix_user_info_t* info)
697 {
698 2 gate_result_t ret = GATE_RESULT_NOMATCH;
699 struct passwd* entry;
700
701 do
702 {
703 2 gate_mem_clear(info, sizeof(gate_posix_user_info_t));
704
705 2 ret = gate_platform_lock();
706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
707
708 do
709 {
710 2 entry = getpwnam(user_name);
711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!entry)
712 {
713 ret = GATE_RESULT_NOMATCH;
714 break;
715 }
716
717 2 gate_posix_load_user_info(entry, info);
718 2 ret = GATE_RESULT_OK;
719 } while (0);
720
721 2 gate_platform_unlock();
722 } while (0);
723 2 return ret;
724 }
725 2 gate_size_t gate_posix_enum_groups(gid_t* gids, gate_size_t max_gids)
726 {
727 struct group* entry;
728 2 gate_size_t index = 0;
729 gate_result_t result;
730
731 do
732 {
733 2 result = gate_platform_lock();
734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(result);
735
736 2 setgrent();
737
2/2
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 2 times.
84 while (NULL != (entry = getgrent()))
738 {
739
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (index < max_gids)
740 {
741 82 gids[index] = entry->gr_gid;
742 82 ++index;
743 }
744 }
745 2 endgrent();
746 2 gate_platform_unlock();
747 } while (0);
748 2 return index;
749 }
750
751 211 static void gate_posix_load_group_info(struct group const* entry, gate_posix_group_info_t* info)
752 {
753 struct passwd const* user_entry;
754 char** ptr;
755 211 gate_size_t max_members = sizeof(info->members) / sizeof(info->members[0]);
756
757 211 info->gid = entry->gr_gid;
758 211 gate_str_print_text(info->name, sizeof(info->name), entry->gr_name, gate_str_length(entry->gr_name));
759 211 ptr = entry->gr_mem;
760
1/2
✓ Branch 0 taken 211 times.
✗ Branch 1 not taken.
211 if (ptr)
761 {
762
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 211 times.
211 while (*ptr)
763 {
764 if (info->members_count >= max_members)
765 {
766 break;
767 }
768 user_entry = getpwnam(*ptr);
769 if (user_entry)
770 {
771 info->members[info->members_count] = user_entry->pw_uid;
772 ++info->members_count;
773 }
774 ++ptr;
775 }
776 }
777 211 }
778
779 209 gate_result_t gate_posix_get_usergroup_info(gid_t gid, gate_posix_group_info_t* info)
780 {
781 209 gate_result_t ret = GATE_RESULT_NOMATCH;
782 struct group const* entry;
783
784 do
785 {
786 209 gate_mem_clear(info, sizeof(gate_posix_group_info_t));
787 209 ret = gate_platform_lock();
788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 GATE_BREAK_IF_FAILED(ret);
789
790 do
791 {
792 209 entry = getgrgid(gid);
793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!entry)
794 {
795 ret = GATE_RESULT_NOMATCH;
796 break;
797 }
798
799 209 gate_posix_load_group_info(entry, info);
800 209 ret = GATE_RESULT_OK;
801 } while (0);
802
803 209 gate_platform_unlock();
804 } while (0);
805 209 return ret;
806 }
807 2 gate_result_t gate_posix_resolve_usergroup_info(char const* group_name, gate_posix_group_info_t* info)
808 {
809 2 gate_result_t ret = GATE_RESULT_NOMATCH;
810 struct group const* entry;
811 struct passwd const* user_entry;
812 char const** ptr;
813 gate_size_t index;
814 2 gate_size_t max_members = sizeof(info->members) / sizeof(info->members[0]);
815
816 do
817 {
818 2 gate_mem_clear(info, sizeof(gate_posix_group_info_t));
819
820 2 ret = gate_platform_lock();
821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 GATE_BREAK_IF_FAILED(ret);
822
823 do
824 {
825 2 entry = getgrnam(group_name);
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!entry)
827 {
828 ret = GATE_RESULT_NOMATCH;
829 break;
830 }
831
832 2 gate_posix_load_group_info(entry, info);
833 2 ret = GATE_RESULT_OK;
834 } while (0);
835
836 2 gate_platform_unlock();
837 } while (0);
838 2 return ret;
839 }
840 #endif /* POSIX account info */
841
842
843
844 gate_bool_t gate_platform_stream_valid(gate_platform_stream_t strm)
845 {
846 int fd = (int)(gate_intptr_t)strm;
847 return (fd >= 0);
848 }
849 void gate_platform_stream_set_invalid(gate_platform_stream_t* ptr_strm)
850 {
851 *ptr_strm = (gate_platform_stream_t)(gate_intptr_t)(-1);
852 }
853
854
855 2 gate_result_t gate_platform_stream_open(char const* path, int open_flags, int native_flags, gate_platform_stream_t* strm)
856 {
857 2 int openflags = 0;
858 int fd;
859 2 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
860
861
2/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 switch (open_flags)
862 {
863 1 case GATE_PLATFORM_STREAM_OPEN_READ:
864 {
865 1 openflags = (O_RDONLY);
866 1 break;
867 }
868 1 case GATE_PLATFORM_STREAM_OPEN_WRITE:
869 {
870 1 openflags = (O_CREAT | O_WRONLY | O_TRUNC);
871 1 break;
872 }
873 case GATE_PLATFORM_STREAM_OPEN_READWRITE:
874 {
875 openflags = (O_CREAT | O_RDWR);
876 break;
877 }
878 }
879 #ifdef O_CLOEXEC
880 2 openflags |= O_CLOEXEC;
881 #endif
882
883 2 fd = open(path, openflags, mode);
884
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (fd < 0)
885 {
886 1 return gate_platform_print_last_error(NULL, 0);
887 }
888
889 1 *strm = (gate_platform_stream_t)(gate_intptr_t)fd;
890 1 return GATE_RESULT_OK;
891 }
892
893 gate_result_t gate_platform_stream_read(gate_platform_stream_t strm, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
894 {
895 gate_result_t ret = GATE_RESULT_FAILED;
896 int fd = (int)(gate_intptr_t)strm;
897 gate_int32_t error_code;
898
899 ptrdiff_t result = gate_posix_read(fd, buffer, bufferlength);
900
901
902 if (result == -1)
903 {
904 error_code = gate_platform_get_last_error();
905 ret = gate_platform_print_error(error_code, NULL, 0);
906 }
907 else
908 {
909 if (returned != NULL)
910 {
911 *returned = (gate_size_t)result;
912 }
913 ret = GATE_RESULT_OK;
914 }
915 return ret;
916 }
917 1 gate_result_t gate_platform_stream_write(gate_platform_stream_t strm, char const* buffer, gate_size_t bufferlength, gate_size_t* written)
918 {
919 1 gate_result_t ret = GATE_RESULT_FAILED;
920 1 int fd = (int)(gate_intptr_t)strm;
921 gate_int32_t error_code;
922
923 1 ptrdiff_t result = gate_posix_write(fd, buffer, bufferlength);
924
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (result == -1)
926 {
927 error_code = gate_platform_get_last_error();
928 ret = gate_platform_print_error(error_code, NULL, 0);
929 }
930 else
931 {
932
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (written != NULL)
933 {
934 1 *written = (gate_size_t)result;
935 }
936 1 ret = GATE_RESULT_OK;
937 }
938 1 return ret;
939 }
940 gate_result_t gate_platform_stream_seek(gate_platform_stream_t strm, gate_int64_t position, int origin, gate_int64_t* final_position)
941 {
942 gate_result_t ret = GATE_RESULT_FAILED;
943 int fd = (int)(gate_intptr_t)strm;
944 gate_int32_t error_code;
945 int whence;
946 off_t result;
947
948 switch (origin)
949 {
950 case GATE_PLATFORM_STREAM_ORIGIN_BEGIN:
951 whence = SEEK_SET;
952 break;
953 case GATE_PLATFORM_STREAM_ORIGIN_CURRENT:
954 whence = SEEK_CUR;
955 break;
956 case GATE_PLATFORM_STREAM_ORIGIN_END:
957 whence = SEEK_END;
958 break;
959 default:
960 return GATE_RESULT_INVALIDARG;
961 }
962
963 result = lseek(fd, (off_t)position, whence);
964 if (result == (off_t)-1)
965 {
966 error_code = gate_platform_get_last_error();
967 ret = gate_platform_print_error(error_code, NULL, 0);
968 }
969 else
970 {
971 if (final_position != NULL)
972 {
973 *final_position = (gate_int64_t)result;
974 }
975 ret = GATE_RESULT_OK;
976 }
977 return ret;
978 }
979
980 1 gate_result_t gate_platform_stream_close(gate_platform_stream_t* strm)
981 {
982 1 gate_result_t ret = GATE_RESULT_OK;
983
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (strm != NULL)
984 {
985
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((int)(gate_intptr_t)*strm != -1)
986 {
987 1 close((int)(gate_intptr_t)*strm);
988 1 *strm = (gate_platform_stream_t)(gate_intptr_t)-1;
989 }
990 }
991 1 return ret;
992 }
993
994 21 int gate_platform_convert_gate_signal(int gate_platform_signal)
995 {
996
1/7
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 21 times.
21 switch (gate_platform_signal)
997 {
998 case GATE_PLATFORM_SIGNAL_ABRT: return SIGABRT;
999 case GATE_PLATFORM_SIGNAL_FPE: return SIGFPE;
1000 case GATE_PLATFORM_SIGNAL_ILL: return SIGILL;
1001 case GATE_PLATFORM_SIGNAL_INT: return SIGINT;
1002 case GATE_PLATFORM_SIGNAL_SEGV: return SIGSEGV;
1003 case GATE_PLATFORM_SIGNAL_TERM: return SIGTERM;
1004 21 default: return gate_platform_signal;
1005 }
1006 }
1007 int gate_platform_convert_native_signal(int native_signal)
1008 {
1009 switch (native_signal)
1010 {
1011 case SIGABRT: return GATE_PLATFORM_SIGNAL_ABRT;
1012 case SIGFPE: return GATE_PLATFORM_SIGNAL_FPE;
1013 case SIGILL: return GATE_PLATFORM_SIGNAL_ILL;
1014 case SIGINT: return GATE_PLATFORM_SIGNAL_INT;
1015 case SIGSEGV: return GATE_PLATFORM_SIGNAL_SEGV;
1016 case SIGTERM: return GATE_PLATFORM_SIGNAL_TERM;
1017 default: return native_signal;
1018 }
1019 }
1020
1021
1022 21 gate_result_t gate_platform_set_signal_handler(int sig,
1023 gate_platform_signal_handler_t new_handler,
1024 gate_platform_signal_handler_t* ptr_old_handler)
1025 {
1026 gate_platform_signal_handler_t ret;
1027 21 int native_signal = gate_platform_convert_gate_signal(sig);
1028
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (native_signal == 0)
1029 {
1030 return GATE_RESULT_NOTSUPPORTED;
1031 }
1032 21 ret = signal(native_signal, new_handler);
1033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (SIG_ERR == ret)
1034 {
1035 return GATE_RESULT_FAILED;
1036 }
1037 else
1038 {
1039
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (ptr_old_handler)
1040 {
1041 *ptr_old_handler = ret;
1042 }
1043 21 return GATE_RESULT_OK;
1044 }
1045 }
1046
1047 gate_result_t gate_platform_raise_signal(int sig)
1048 {
1049 gate_result_t ret = GATE_RESULT_FAILED;
1050 int result;
1051 int native_signal = gate_platform_convert_gate_signal(sig);
1052 if (native_signal == 0)
1053 {
1054 return GATE_RESULT_NOTSUPPORTED;
1055 }
1056
1057 result = raise(native_signal);
1058 if (result == 0)
1059 {
1060 ret = GATE_RESULT_OK;
1061 }
1062 else
1063 {
1064 gate_posix_errno(&ret);
1065 }
1066 return ret;
1067 }
1068
1069 1 gate_result_t gate_posix_daemonize(pid_t* ptr_pid)
1070 {
1071 pid_t child_pid;
1072 pid_t daemon_pid;
1073 int fd[2];
1074 int result;
1075 ssize_t transferred;
1076 int daemon_fd;
1077
1078 1 result = pipe(fd);
1079
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (result < 0)
1080 {
1081 /* failed to create communication pipe */
1082 GATE_DEBUG_TRACE("daemonize: failed to create pipes");
1083 return GATE_RESULT_OUTOFRESOURCES;
1084 }
1085
1086 1 child_pid = fork();
1087
1088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (child_pid < 0)
1089 {
1090 GATE_DEBUG_TRACE("daemonize: initial fork() failed");
1091 return GATE_RESULT_FAILED;
1092 }
1093
1094
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (child_pid > 0)
1095 {
1096 /* caller branch hosting the dispatcher */
1097 close(fd[1]); /* close the remote write-end */
1098 transferred = read(fd[0], &daemon_pid, sizeof(daemon_pid));
1099 close(fd[0]); /* close the local read-end */
1100 waitpid(child_pid, NULL, 0);
1101 if (transferred != sizeof(daemon_pid))
1102 {
1103 /* could not retrieve daemon-PID -> failed to create daemon */
1104 GATE_DEBUG_TRACE("daemonize: waitpid() completed - NO PID - failed");
1105 return GATE_RESULT_FAILED;
1106 }
1107
1108 GATE_DEBUG_TRACE("daemonize: waitpid() completed - PID received");
1109 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1110 if (ptr_pid)
1111 {
1112 *ptr_pid = daemon_pid;
1113 }
1114 /* notify the caller, that the daemon process is running */
1115 return GATE_RESULT_OK;
1116 }
1117
1118 /* dispatcher child process */
1119 1 close(fd[0]); /* close read side of pipe*/
1120
1121 1 result = setsid();
1122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (result < 0)
1123 {
1124 GATE_DEBUG_TRACE("daemonize: setsid() failed");
1125 _exit(1);
1126 }
1127
1128 1 signal(SIGHUP, SIG_IGN);
1129
1130 /* 2nd fork: */
1131 1 daemon_pid = fork();
1132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (daemon_pid < 0)
1133 {
1134 GATE_DEBUG_TRACE("daemonize: final fork() failed");
1135 _exit(2);
1136 }
1137
1138
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (daemon_pid > 0)
1139 {
1140 /* dispatcher has retrieved the final daemon child PID: */
1141
1142 /* send daemon-PID to parent process */
1143 GATE_DEBUG_TRACE("daemonize: send daemon PID back to parent process");
1144 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1145 transferred = write(fd[1], &daemon_pid, sizeof(daemon_pid));
1146 close(fd[1]); /* close write end */
1147 if (transferred == sizeof(daemon_pid))
1148 {
1149 GATE_DEBUG_TRACE("daemonize: dispatcher process succeeded");
1150 _exit(0); /* terminate dispatcher with success state */
1151 }
1152 else
1153 {
1154 GATE_DEBUG_TRACE("daemonize: dispatcher process failed");
1155 _exit(3); /* terminate dispatcher with error state*/
1156 }
1157 return GATE_RESULT_CRITICALERROR; /* this point should never be reached */
1158 }
1159
1160 /* this is the daemonized branch */
1161 1 GATE_DEBUG_TRACE("daemonize: daemon branch reached");
1162
1163 1 close(fd[1]); /* close write end */
1164
1165 /* prepare daemon environment */
1166 1 result = chdir("/");
1167 1 umask(0);
1168
1169 /* assign STDIN/OUT/ERR to null device: */
1170 1 daemon_fd = open("/dev/null", O_RDONLY);
1171
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if ((daemon_fd != -1) && (daemon_fd != STDIN_FILENO))
1172 {
1173 1 dup2(daemon_fd, STDIN_FILENO);
1174 1 close(daemon_fd);
1175 }
1176
1177 1 daemon_fd = open("/dev/null", O_WRONLY);
1178
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != -1)
1179 {
1180
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != STDOUT_FILENO)
1181 {
1182 1 dup2(daemon_fd, STDOUT_FILENO);
1183 }
1184
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != STDERR_FILENO)
1185 {
1186 1 dup2(daemon_fd, STDERR_FILENO);
1187 }
1188 1 close(daemon_fd);
1189 }
1190
1191
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_pid)
1192 {
1193 1 *ptr_pid = 0; /* mark as daemon-branch */
1194 }
1195 1 return GATE_RESULT_OK;
1196 }
1197
1198 13 void* gate_posix_dlopen(char const* libpath, int flags)
1199 {
1200 void* ret;
1201 13 dlerror(); /* clear previous error state */
1202 13 ret = dlopen(libpath, flags);
1203
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (NULL == ret)
1204 {
1205 3 char* last_errmsg = dlerror();
1206 3 GATE_DEBUG_TRACE("dlopen() failed");
1207
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (libpath)
1208 {
1209 3 GATE_DEBUG_TRACE(libpath);
1210 }
1211
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (last_errmsg)
1212 {
1213 3 GATE_DEBUG_TRACE(last_errmsg);
1214 }
1215 }
1216 13 return ret;
1217 }
1218
1219 10 int gate_posix_dlclose(void* handle)
1220 {
1221 10 int ret = dlclose(handle);
1222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret != 0)
1223 {
1224 char* last_errmsg = dlerror();
1225 GATE_DEBUG_TRACE("dlclose() failed");
1226 if (last_errmsg)
1227 {
1228 GATE_DEBUG_TRACE(last_errmsg);
1229 }
1230 }
1231 10 return ret;
1232 }
1233
1234 42 void* gate_posix_dlsym(void* handle, char const* symbol)
1235 {
1236 void* ret;
1237
1238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!symbol)
1239 {
1240 GATE_DEBUG_TRACE("Invalid arg for dlsym()");
1241 return NULL;
1242 }
1243
1244 42 dlerror();
1245 42 ret = dlsym(handle, symbol);
1246
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 38 times.
42 if (NULL == ret)
1247 {
1248 4 char* last_errmsg = dlerror();
1249 4 GATE_DEBUG_TRACE("dlsym() failed:");
1250 4 GATE_DEBUG_TRACE(symbol);
1251
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (last_errmsg)
1252 {
1253 4 GATE_DEBUG_TRACE(last_errmsg);
1254 }
1255 }
1256 42 return ret;
1257 }
1258
1259
1260 static void* volatile dl_global = NULL;
1261
1262 7 static void close_global_dlhandle_atexit()
1263 {
1264
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (NULL != dl_global)
1265 {
1266 7 void* handle = dl_global;
1267 7 dl_global = NULL;
1268 7 dlclose(handle);
1269 }
1270 7 }
1271
1272 24 void* gate_posix_global_sym(char const* symbol)
1273 {
1274 void* ret;
1275
1276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (NULL == symbol)
1277 {
1278 return NULL;
1279 }
1280
1281 24 dlerror();
1282
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 17 times.
24 if (dl_global == NULL)
1283 {
1284 7 dl_global = dlopen(NULL, RTLD_GLOBAL | RTLD_NOW);
1285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (NULL == dl_global)
1286 {
1287 char* last_errmsg = dlerror();
1288 if (last_errmsg)
1289 {
1290 GATE_DEBUG_TRACE(last_errmsg);
1291 }
1292 }
1293 else
1294 {
1295 7 gate_platform_atexit(&close_global_dlhandle_atexit);
1296 }
1297 }
1298
1299 24 ret = dlsym(dl_global, symbol);
1300
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 if (NULL == ret)
1301 {
1302 12 char* last_errmsg = dlerror();
1303 12 GATE_DEBUG_TRACE("dlsym() failed to load global symbol");
1304 12 GATE_DEBUG_TRACE(symbol);
1305
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (last_errmsg)
1306 {
1307 12 GATE_DEBUG_TRACE(last_errmsg);
1308 }
1309 }
1310 24 return ret;
1311 }
1312
1313 #if defined(GATE_SYS_DARWIN)
1314
1315 gate_bool_t gate_posix_clock_gettime(long* ptr_seconds, long* ptr_nanoseconds)
1316 {
1317 clock_serv_t cclock;
1318 mach_timespec_t mts;
1319 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
1320 clock_get_time(cclock, &mts);
1321 mach_port_deallocate(mach_task_self(), cclock);
1322 if (ptr_seconds) *ptr_seconds = mts.tv_sec;
1323 if (ptr_nanoseconds) *ptr_nanoseconds = mts.tv_nsec;
1324 return true;
1325 }
1326 gate_bool_t gate_posix_clock_gettime_monotonic(long* ptr_seconds, long* ptr_nanoseconds)
1327 {
1328 return gate_posix_clock_gettime(ptr_seconds, ptr_nanoseconds);
1329 }
1330
1331 #else
1332
1333 gate_bool_t gate_posix_clock_gettime(long* ptr_seconds, long* ptr_nanoseconds)
1334 {
1335 struct timespec ts;
1336 if (0 == clock_gettime(CLOCK_REALTIME, &ts))
1337 {
1338 if (ptr_seconds) *ptr_seconds = ts.tv_sec;
1339 if (ptr_nanoseconds) *ptr_nanoseconds = ts.tv_nsec;
1340 return true;
1341 }
1342 return false;
1343 }
1344 6414685 gate_bool_t gate_posix_clock_gettime_monotonic(long* ptr_seconds, long* ptr_nanoseconds)
1345 {
1346 struct timespec ts;
1347
1/2
✓ Branch 1 taken 6414685 times.
✗ Branch 2 not taken.
6414685 if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
1348 {
1349
1/2
✓ Branch 0 taken 6414685 times.
✗ Branch 1 not taken.
6414685 if (ptr_seconds) *ptr_seconds = ts.tv_sec;
1350
1/2
✓ Branch 0 taken 6414685 times.
✗ Branch 1 not taken.
6414685 if (ptr_nanoseconds) *ptr_nanoseconds = ts.tv_nsec;
1351 6414685 return true;
1352 }
1353 return false;
1354 }
1355
1356 #endif
1357
1358 4 static void create_semaphore_timeout(struct timespec* ptr_timeout, gate_uint32_t timeout_ms, gate_bool_t use_clocktime)
1359 {
1360
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (use_clocktime)
1361 {
1362 long seconds, nanoseconds;
1363 gate_posix_clock_gettime(&seconds, &nanoseconds);
1364 ptr_timeout->tv_sec = seconds;
1365 ptr_timeout->tv_nsec = nanoseconds;
1366 }
1367 else
1368 {
1369 4 ptr_timeout->tv_sec = 0;
1370 4 ptr_timeout->tv_nsec = 0;
1371 }
1372 4 ptr_timeout->tv_sec += timeout_ms / 1000;
1373 4 ptr_timeout->tv_nsec += (timeout_ms % 1000) * 1000000;
1374 4 ptr_timeout->tv_sec += ptr_timeout->tv_nsec / 1000000000;
1375 4 ptr_timeout->tv_nsec %= 1000000000;
1376 4 }
1377
1378 #if defined(GATE_SYS_USE_POSIX_SEMAPHORE)
1379
1380 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1381 {
1382 sem_t* s = NULL;
1383 int result;
1384
1385 if (!ptr_sem || (count == 0))
1386 {
1387 return GATE_RESULT_INVALIDARG;
1388 }
1389
1390 s = (sem_t*)gate_mem_alloc(sizeof(sem_t));
1391 if (!s)
1392 {
1393 return GATE_RESULT_OUTOFMEMORY;
1394 }
1395 result = sem_init(s, 0, (unsigned int)count);
1396 if (result != 0)
1397 {
1398 gate_mem_dealloc(s);
1399 return GATE_RESULT_FAILED;
1400 }
1401 else
1402 {
1403 *ptr_sem = (gate_platform_semaphore_t)s;
1404 return GATE_RESULT_OK;
1405 }
1406 }
1407 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1408 {
1409 sem_t** pps = (sem_t**)ptr_sem;
1410 if (!pps || !*pps)
1411 {
1412 return GATE_RESULT_INVALIDARG;
1413 }
1414
1415 if (!ptr_timeout_ms)
1416 {
1417 if (0 == sem_wait(*pps))
1418 {
1419 /* success case */
1420 return GATE_RESULT_OK;
1421 }
1422 }
1423 else
1424 {
1425 struct timespec timeout;
1426 int last_error;
1427
1428 create_semaphore_timeout(&timeout, *ptr_timeout_ms, true);
1429
1430 if (0 == sem_timedwait(*pps, &timeout))
1431 {
1432 /* success case */
1433 return GATE_RESULT_OK;
1434 }
1435 last_error = gate_posix_errno(NULL);
1436 if (last_error == ETIMEDOUT)
1437 {
1438 return GATE_RESULT_TIMEOUT;
1439 }
1440 }
1441
1442 /* generic error case */
1443 return GATE_RESULT_FAILED;
1444 }
1445 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1446 {
1447 sem_t** pps = (sem_t**)ptr_sem;
1448 if (!pps || !*pps)
1449 {
1450 return GATE_RESULT_INVALIDARG;
1451 }
1452
1453 if (0 == sem_post(*pps))
1454 {
1455 return GATE_RESULT_OK;
1456 }
1457 return GATE_RESULT_FAILED;
1458 }
1459 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1460 {
1461 sem_t** pps = (sem_t**)ptr_sem;
1462 if (!pps || !*pps)
1463 {
1464 return GATE_RESULT_INVALIDARG;
1465 }
1466 if (0 == sem_close(*pps))
1467 {
1468 gate_mem_dealloc(*pps);
1469 *pps = NULL;
1470 return GATE_RESULT_OK;
1471 }
1472 else
1473 {
1474 return GATE_RESULT_FAILED;
1475 }
1476 }
1477
1478 #else /* GATE_SYS_USE_POSIX_SEMAPHORE */
1479
1480 #if defined(GATE_SYS_LINUX) || defined(GATE_SYS_NETBSD) || defined(GATE_SYS_FREEBSD)
1481 union semun
1482 {
1483 int val;
1484 struct semid_ds* buf;
1485 unsigned short* array;
1486 };
1487 #endif
1488
1489 3 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1490 {
1491 3 int* s = (int*)ptr_sem;
1492 union semun arg;
1493
1494
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!s || (count == 0))
1495 {
1496 return GATE_RESULT_INVALIDARG;
1497 }
1498
1499 3 *s = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | SHM_R | SHM_W);
1500
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (*s == -1)
1501 {
1502 return GATE_RESULT_OUTOFRESOURCES;
1503 }
1504
1505 3 arg.val = (int)count;
1506 3 semctl(*s, 0, SETVAL, arg);
1507 3 return GATE_RESULT_OK;
1508 }
1509
1510 typedef int(*semtimedop_func_ptr)(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout);
1511
1512 #if defined(HAVE_SEMTIMEDOP)
1513
1514 4 static int semtimedop_wrapper(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1515 {
1516 4 return semtimedop(semid, sops, nsops, timeout);
1517 }
1518
1519 4 static semtimedop_func_ptr get_semtimedop()
1520 {
1521 4 return &semtimedop_wrapper;
1522 }
1523
1524 #else
1525
1526 static int fallback_semtimedop(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1527 {
1528 int ret = -1;
1529 struct sembuf op[1024];
1530 unsigned index;
1531 struct timespec now;
1532 long seconds = 0;
1533 long nanoseconds = 0;
1534
1535 gate_posix_clock_gettime_monotonic(&seconds, &nanoseconds);
1536 now.tv_sec = seconds;
1537 now.tv_nsec = nanoseconds;
1538 do
1539 {
1540 int errcode = 0;
1541 const long nsec = (now.tv_nsec + timeout->tv_nsec);
1542 struct timespec end;
1543 struct timespec sleep_timeout;
1544 end.tv_sec = (now.tv_sec + timeout->tv_sec) + (nsec) / 1000000000;
1545 end.tv_nsec = nsec % 1000000000;
1546
1547 if (nsops > sizeof(op) / sizeof(op[0]))
1548 {
1549 nsops = sizeof(op) / sizeof(op[0]);
1550 }
1551
1552 for (index = 0; index != nsops; ++index)
1553 {
1554 op[index].sem_num = sops[index].sem_num;
1555 op[index].sem_op = sops[index].sem_op;
1556 op[index].sem_flg = sops[index].sem_flg | IPC_NOWAIT;
1557 }
1558
1559 sleep_timeout.tv_sec = 0;
1560 sleep_timeout.tv_nsec = 10;
1561 do
1562 {
1563 ret = semop(semid, &op[0], nsops);
1564 if (ret == 0)
1565 {
1566 /* operation succeeded, we are done (ret == 0) */
1567 break;
1568 }
1569 errcode = gate_posix_errno(NULL);
1570
1571
1572 if(!gate_posix_clock_gettime_monotonic(&seconds, &nanoseconds))
1573 {
1574 break;
1575 }
1576 now.tv_sec = seconds;
1577 now.tv_nsec = nanoseconds;
1578
1579 if ((now.tv_sec > end.tv_sec) || ((now.tv_sec == end.tv_sec) && (now.tv_nsec > end.tv_nsec)))
1580 {
1581 /* timeout reached, (ret == -1) */
1582 gate_posix_set_errno(EAGAIN);
1583 break;
1584 }
1585 nanosleep(&sleep_timeout, NULL);
1586 if (sleep_timeout.tv_nsec < 50000000)
1587 {
1588 sleep_timeout.tv_nsec *= 2;
1589 }
1590 } while (errcode == EAGAIN);
1591 } while (0);
1592 return ret;
1593 }
1594
1595 static semtimedop_func_ptr get_semtimedop()
1596 {
1597 static semtimedop_func_ptr semtimedop_func = NULL;
1598 if (!semtimedop_func)
1599 {
1600 semtimedop_func = (semtimedop_func_ptr)gate_posix_global_sym("semtimedop");
1601 if (!semtimedop_func)
1602 {
1603 semtimedop_func = &fallback_semtimedop;
1604 }
1605 }
1606 return semtimedop_func;
1607 }
1608
1609 #endif
1610
1611 8 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1612 {
1613 8 int* s = (int*)ptr_sem;
1614 struct sembuf op;
1615
1616
2/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if (!s || (*s == -1))
1617 {
1618 return GATE_RESULT_INVALIDARG;
1619 }
1620
1621 8 op.sem_num = 0;
1622 8 op.sem_op = -1;
1623 8 op.sem_flg = SEM_UNDO;
1624
1625
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (!ptr_timeout_ms)
1626 {
1627
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (-1 == semop(*s, &op, 1))
1628 {
1629 return GATE_RESULT_FAILED;
1630 }
1631 }
1632 else
1633 {
1634 struct timespec timeout;
1635 4 semtimedop_func_ptr semtimedop_func = get_semtimedop();
1636
1637
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (semtimedop_func == NULL)
1638 {
1639 2 return GATE_RESULT_NOTSUPPORTED;
1640 }
1641
1642 4 create_semaphore_timeout(&timeout, *ptr_timeout_ms, false);
1643
1644
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (-1 == semtimedop_func(*s, &op, 1, &timeout))
1645 {
1646
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (gate_posix_errno(NULL) == EAGAIN)
1647 {
1648 2 return GATE_RESULT_TIMEOUT;
1649 }
1650 else
1651 {
1652 return GATE_RESULT_FAILED;
1653 }
1654 }
1655 }
1656
1657 /* generic success case */
1658 6 return GATE_RESULT_OK;
1659 }
1660
1661 6 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1662 {
1663 6 int* s = (int*)ptr_sem;
1664 struct sembuf op;
1665
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (!s || (*s == -1))
1666 {
1667 return GATE_RESULT_INVALIDARG;
1668 }
1669
1670 6 op.sem_num = 0;
1671 6 op.sem_op = 1;
1672 6 op.sem_flg = SEM_UNDO;
1673
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (-1 == semop(*s, &op, 1))
1674 {
1675 return GATE_RESULT_FAILED;
1676 }
1677 6 return GATE_RESULT_OK;
1678 }
1679 3 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1680 {
1681 3 int* s = (int*)ptr_sem;
1682
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (!s || (*s == -1))
1683 {
1684 return GATE_RESULT_INVALIDARG;
1685 }
1686
1687 3 semctl(*s, 0, IPC_RMID, NULL);
1688 3 *s = -1;
1689 3 return GATE_RESULT_OK;
1690 }
1691
1692 #endif /* GATE_SYS_USE_POSIX_SEMAPHORE*/
1693
1694 gate_bool_t gate_platform_yield()
1695 {
1696 sched_yield();
1697 return true;
1698 }
1699
1700 #endif /* GATE_SYS_POSIX */
1701