GCC Code Coverage Report


Directory: src/gate/
File: src/gate/platform_posix.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 416 660 63.0%
Functions: 53 61 86.9%
Branches: 128 341 37.5%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, 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 680 static gate_result_t global_platform_mutex_init()
96 {
97 680 gate_result_t ret = GATE_RESULT_OK;
98 680 const gate_int32_t init_state = gate_atomic_int_get(&global_platform_mutex_usable);
99
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 640 times.
680 if (0 == init_state)
100 {
101 40 gate_atomic_lock_acquire(&global_platform_mutex_init_lock);
102 {
103
1/2
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
40 if (!gate_atomic_flag_set(&global_platform_mutex_init_done))
104 {
105
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 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 40 gate_atomic_int_set(&global_platform_mutex_usable, 1);
113 }
114 }
115 }
116 40 gate_atomic_lock_release(&global_platform_mutex_init_lock);
117 }
118 680 return ret;
119 }
120
121 40 gate_result_t gate_platform_init(void)
122 {
123 40 gate_result_t ret = GATE_RESULT_OK;
124
125 40 global_platform_mutex_init();
126
127 40 return ret;
128 }
129
130 2 void gate_platform_exit(int exit_code)
131 {
132 2 exit(exit_code);
133 }
134
135 20 void gate_platform_atexit(void(*func)(void))
136 {
137 20 atexit(func);
138 20 }
139
140 320 gate_result_t gate_platform_lock()
141 {
142 320 gate_result_t ret = global_platform_mutex_init();
143
1/2
✓ Branch 0 taken 320 times.
✗ Branch 1 not taken.
320 if (GATE_SUCCEEDED(ret))
144 {
145
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 320 times.
320 if (0 != pthread_mutex_lock(&global_platform_mutex))
146 {
147 ret = GATE_RESULT_FAILED;
148 }
149 }
150 320 return ret;
151 }
152 320 gate_result_t gate_platform_unlock()
153 {
154 320 gate_result_t ret = global_platform_mutex_init();
155
1/2
✓ Branch 0 taken 320 times.
✗ Branch 1 not taken.
320 if (GATE_SUCCEEDED(ret))
156 {
157
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 320 times.
320 if (0 != pthread_mutex_unlock(&global_platform_mutex))
158 {
159 ret = GATE_RESULT_FAILED;
160 }
161 }
162 320 return ret;
163 }
164 1309891 gate_int32_t gate_platform_get_last_error()
165 {
166 1309891 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 245 static gate_result_t gate_posix_convert_errno(int error_code)
176 {
177 245 gate_result_t ret = GATE_RESULT_FAILED;
178
179
6/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 235 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 taken 4 times.
✗ 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.
245 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 235 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 4 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 245 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 243 int gate_posix_errno(gate_result_t* result)
292 {
293 243 int ret = errno;
294
295
2/2
✓ Branch 0 taken 241 times.
✓ Branch 1 taken 2 times.
243 if (result != NULL)
296 {
297 241 *result = gate_posix_convert_errno(ret);
298 }
299 243 return ret;
300 }
301 void gate_posix_set_errno(int code)
302 {
303 errno = code;
304 }
305
306
307 76 void gate_posix_block_signals(gate_posix_sigblocker_t* blocker, int sig1, int sig2, ...)
308 {
309 int arg;
310 va_list args;
311
312 76 gate_mem_clear(blocker, sizeof(gate_posix_sigblocker_t));
313 76 sigemptyset(&blocker->signals);
314 76 sigaddset(&blocker->signals, sig1);
315
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 76 times.
76 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 76 blocker->unblock_required = (pthread_sigmask(SIG_BLOCK, &blocker->signals, &blocker->signals) == 0);
327 76 }
328
329 76 void gate_posix_unblock_signals(gate_posix_sigblocker_t* blocker)
330 {
331
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 if (blocker->unblock_required)
332 {
333 76 pthread_sigmask(SIG_SETMASK, &blocker->signals, 0);
334 }
335 76 gate_mem_clear(blocker, sizeof(gate_posix_sigblocker_t));
336 76 }
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 11 gate_size_t gate_posix_get_inheritable_fds(int* fdbuffer, gate_size_t fdbuffer_length)
385 {
386 11 gate_size_t used = 0;
387 11 gate_size_t ndx = 0;
388
389 11 gate_atomic_lock_acquire(&gate_posix_inheritable_lock);
390 11 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 11 times.
11 for (ndx = 0; ndx != used; ++ndx)
392 {
393 *fdbuffer = gate_posix_inheritable_fds[ndx];
394 ++fdbuffer;
395 }
396
397 11 gate_atomic_lock_release(&gate_posix_inheritable_lock);
398 11 return used;
399 }
400
401
402 9 int gate_posix_open(char const* path, int oflag, int mode)
403 {
404 9 return open(path, oflag, (mode_t)mode);
405 }
406 20437 int gate_posix_close(int fd)
407 {
408 20437 return close(fd);
409 }
410 1309848 ptrdiff_t gate_posix_read(int fd, void* buf, size_t nbyte)
411 {
412 ptrdiff_t result;
413 do
414 {
415 1309848 result = (ptrdiff_t)read(fd, buf, nbyte);
416
3/4
✓ Branch 0 taken 1309791 times.
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1309791 times.
1309848 } while ((result == -1) && (errno == EINTR));
417 1309848 return result;
418 }
419 61 ptrdiff_t gate_posix_write(int fd, void const* buf, size_t nbyte)
420 {
421 ptrdiff_t result;
422 do
423 {
424 61 result = (ptrdiff_t)write(fd, buf, nbyte);
425
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
61 } while ((result == -1) && (errno == EINTR));
426 61 return result;
427 }
428 7 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 4 times.
✓ Branch 1 taken 3 times.
7 if (timeout_ms != 0xffffffff)
434 {
435 4 timeout.tv_sec = timeout_ms / 1000;
436 4 timeout.tv_usec = (timeout_ms % 1000) * 1000;
437 }
438 else
439 {
440 3 timeout.tv_sec = 0x7fffffff;
441 3 timeout.tv_usec = 0;
442 }
443
444 7 FD_ZERO(&read_set);
445 7 FD_SET(fd, &read_set);
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 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 7 times.
7 if (!FD_ISSET(fd, &read_set))
452 {
453 return GATE_RESULT_TIMEOUT;
454 }
455 else
456 {
457 7 return GATE_RESULT_OK;
458 }
459 }
460
461
462 31 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
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
31 switch (operation)
469 {
470 case gate_posix_flock_shared: op = LOCK_SH; break;
471 14 case gate_posix_flock_exclusive: op = LOCK_EX; break;
472 2 case gate_posix_flock_exclusive_test: op = (LOCK_EX | LOCK_NB); break;
473 15 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 31 result = flock(fd, op);
482
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
31 } while ((result == -1) && (errno == EINTR));
483 31 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 35 gate_bool_t gate_posix_path_exists(char const* path)
595 {
596 struct stat filestat;
597
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 if (0 == stat(path, &filestat))
598 {
599 35 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 3 gate_bool_t gate_platform_stream_valid(gate_platform_stream_t strm)
845 {
846 3 int fd = (int)(gate_intptr_t)strm;
847 3 return (fd >= 0);
848 }
849 1 void gate_platform_stream_set_invalid(gate_platform_stream_t* ptr_strm)
850 {
851 1 *ptr_strm = (gate_platform_stream_t)(gate_intptr_t)(-1);
852 1 }
853
854
855 4 gate_result_t gate_platform_stream_open(char const* path, int open_flags, int native_flags, gate_platform_stream_t* strm)
856 {
857 4 int openflags = 0;
858 int fd;
859 4 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH;
860
861
2/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4 switch (open_flags)
862 {
863 2 case GATE_PLATFORM_STREAM_OPEN_READ:
864 {
865 2 openflags = (O_RDONLY);
866 2 break;
867 }
868 2 case GATE_PLATFORM_STREAM_OPEN_WRITE:
869 {
870 2 openflags = (O_CREAT | O_WRONLY | O_TRUNC);
871 2 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 4 openflags |= O_CLOEXEC;
881 #endif
882
883 4 fd = open(path, openflags, mode);
884
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (fd < 0)
885 {
886 1 return gate_platform_print_last_error(NULL, 0);
887 }
888
889 3 *strm = (gate_platform_stream_t)(gate_intptr_t)fd;
890 3 return GATE_RESULT_OK;
891 }
892
893 1 gate_result_t gate_platform_stream_read(gate_platform_stream_t strm, char* buffer, gate_size_t bufferlength, gate_size_t* returned)
894 {
895 1 gate_result_t ret = GATE_RESULT_FAILED;
896 1 int fd = (int)(gate_intptr_t)strm;
897 gate_int32_t error_code;
898
899 1 ptrdiff_t result = gate_posix_read(fd, buffer, bufferlength);
900
901
902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 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
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (returned != NULL)
910 {
911 1 *returned = (gate_size_t)result;
912 }
913 1 ret = GATE_RESULT_OK;
914 }
915 1 return ret;
916 }
917 2 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 2 gate_result_t ret = GATE_RESULT_FAILED;
920 2 int fd = (int)(gate_intptr_t)strm;
921 gate_int32_t error_code;
922
923 2 ptrdiff_t result = gate_posix_write(fd, buffer, bufferlength);
924
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 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 2 times.
✗ Branch 1 not taken.
2 if (written != NULL)
933 {
934 2 *written = (gate_size_t)result;
935 }
936 2 ret = GATE_RESULT_OK;
937 }
938 2 return ret;
939 }
940 3 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 3 gate_result_t ret = GATE_RESULT_FAILED;
943 3 int fd = (int)(gate_intptr_t)strm;
944 gate_int32_t error_code;
945 int whence;
946 off_t result;
947
948
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
3 switch (origin)
949 {
950 1 case GATE_PLATFORM_STREAM_ORIGIN_BEGIN:
951 1 whence = SEEK_SET;
952 1 break;
953 1 case GATE_PLATFORM_STREAM_ORIGIN_CURRENT:
954 1 whence = SEEK_CUR;
955 1 break;
956 1 case GATE_PLATFORM_STREAM_ORIGIN_END:
957 1 whence = SEEK_END;
958 1 break;
959 default:
960 return GATE_RESULT_INVALIDARG;
961 }
962
963 3 result = lseek(fd, (off_t)position, whence);
964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 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
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (final_position != NULL)
972 {
973 3 *final_position = (gate_int64_t)result;
974 }
975 3 ret = GATE_RESULT_OK;
976 }
977 3 return ret;
978 }
979
980 3 gate_result_t gate_platform_stream_close(gate_platform_stream_t* strm)
981 {
982 3 gate_result_t ret = GATE_RESULT_OK;
983
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (strm != NULL)
984 {
985
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if ((int)(gate_intptr_t)*strm != -1)
986 {
987 3 close((int)(gate_intptr_t)*strm);
988 3 *strm = (gate_platform_stream_t)(gate_intptr_t)-1;
989 }
990 }
991 3 return ret;
992 }
993
994 43 int gate_platform_convert_gate_signal(int gate_platform_signal)
995 {
996
2/8
✗ 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 1 times.
✓ Branch 7 taken 42 times.
43 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 1 case GATE_PLATFORM_SIGNAL_CONTINUE: return SIGCONT;
1005 42 default: return gate_platform_signal;
1006 }
1007 }
1008 int gate_platform_convert_native_signal(int native_signal)
1009 {
1010 switch (native_signal)
1011 {
1012 case SIGABRT: return GATE_PLATFORM_SIGNAL_ABRT;
1013 case SIGFPE: return GATE_PLATFORM_SIGNAL_FPE;
1014 case SIGILL: return GATE_PLATFORM_SIGNAL_ILL;
1015 case SIGINT: return GATE_PLATFORM_SIGNAL_INT;
1016 case SIGSEGV: return GATE_PLATFORM_SIGNAL_SEGV;
1017 case SIGTERM: return GATE_PLATFORM_SIGNAL_TERM;
1018 case SIGCONT: return GATE_PLATFORM_SIGNAL_CONTINUE;
1019 default: return native_signal;
1020 }
1021 }
1022
1023
1024 42 gate_result_t gate_platform_set_signal_handler(int sig,
1025 gate_platform_signal_handler_t new_handler,
1026 gate_platform_signal_handler_t* ptr_old_handler)
1027 {
1028 gate_platform_signal_handler_t ret;
1029 42 int native_signal = gate_platform_convert_gate_signal(sig);
1030
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (native_signal == 0)
1031 {
1032 return GATE_RESULT_NOTSUPPORTED;
1033 }
1034 42 ret = signal(native_signal, new_handler);
1035
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (SIG_ERR == ret)
1036 {
1037 return GATE_RESULT_FAILED;
1038 }
1039 else
1040 {
1041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (ptr_old_handler)
1042 {
1043 *ptr_old_handler = ret;
1044 }
1045 42 return GATE_RESULT_OK;
1046 }
1047 }
1048
1049 1 gate_result_t gate_platform_raise_signal(int sig)
1050 {
1051 1 gate_result_t ret = GATE_RESULT_FAILED;
1052 int result;
1053 1 int native_signal = gate_platform_convert_gate_signal(sig);
1054
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (native_signal == 0)
1055 {
1056 return GATE_RESULT_NOTSUPPORTED;
1057 }
1058
1059 1 result = raise(native_signal);
1060
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (result == 0)
1061 {
1062 1 ret = GATE_RESULT_OK;
1063 }
1064 else
1065 {
1066 gate_posix_errno(&ret);
1067 }
1068 1 return ret;
1069 }
1070
1071 1 gate_result_t gate_posix_daemonize(pid_t* ptr_pid)
1072 {
1073 pid_t child_pid;
1074 pid_t daemon_pid;
1075 int fd[2];
1076 int result;
1077 ssize_t transferred;
1078 int daemon_fd;
1079
1080 1 result = pipe(fd);
1081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (result < 0)
1082 {
1083 /* failed to create communication pipe */
1084 GATE_DEBUG_TRACE("daemonize: failed to create pipes");
1085 return GATE_RESULT_OUTOFRESOURCES;
1086 }
1087
1088 1 child_pid = fork();
1089
1090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (child_pid < 0)
1091 {
1092 GATE_DEBUG_TRACE("daemonize: initial fork() failed");
1093 return GATE_RESULT_FAILED;
1094 }
1095
1096
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (child_pid > 0)
1097 {
1098 /* caller branch hosting the dispatcher */
1099 close(fd[1]); /* close the remote write-end */
1100 transferred = read(fd[0], &daemon_pid, sizeof(daemon_pid));
1101 close(fd[0]); /* close the local read-end */
1102 waitpid(child_pid, NULL, 0);
1103 if (transferred != sizeof(daemon_pid))
1104 {
1105 /* could not retrieve daemon-PID -> failed to create daemon */
1106 GATE_DEBUG_TRACE("daemonize: waitpid() completed - NO PID - failed");
1107 return GATE_RESULT_FAILED;
1108 }
1109
1110 GATE_DEBUG_TRACE("daemonize: waitpid() completed - PID received");
1111 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1112 if (ptr_pid)
1113 {
1114 *ptr_pid = daemon_pid;
1115 }
1116 /* notify the caller, that the daemon process is running */
1117 return GATE_RESULT_OK;
1118 }
1119
1120 /* dispatcher child process */
1121 1 close(fd[0]); /* close read side of pipe*/
1122
1123 1 result = setsid();
1124
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (result < 0)
1125 {
1126 GATE_DEBUG_TRACE("daemonize: setsid() failed");
1127 _exit(1);
1128 }
1129
1130 1 signal(SIGHUP, SIG_IGN);
1131
1132 /* 2nd fork: */
1133 1 daemon_pid = fork();
1134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (daemon_pid < 0)
1135 {
1136 GATE_DEBUG_TRACE("daemonize: final fork() failed");
1137 _exit(2);
1138 }
1139
1140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (daemon_pid > 0)
1141 {
1142 /* dispatcher has retrieved the final daemon child PID: */
1143
1144 /* send daemon-PID to parent process */
1145 GATE_DEBUG_TRACE("daemonize: send daemon PID back to parent process");
1146 GATE_DEBUG_TRACE_VALUE(daemon_pid);
1147 transferred = write(fd[1], &daemon_pid, sizeof(daemon_pid));
1148 close(fd[1]); /* close write end */
1149 if (transferred == sizeof(daemon_pid))
1150 {
1151 GATE_DEBUG_TRACE("daemonize: dispatcher process succeeded");
1152 _exit(0); /* terminate dispatcher with success state */
1153 }
1154 else
1155 {
1156 GATE_DEBUG_TRACE("daemonize: dispatcher process failed");
1157 _exit(3); /* terminate dispatcher with error state*/
1158 }
1159 return GATE_RESULT_CRITICALERROR; /* this point should never be reached */
1160 }
1161
1162 /* this is the daemonized branch */
1163 1 GATE_DEBUG_TRACE("daemonize: daemon branch reached");
1164
1165 1 close(fd[1]); /* close write end */
1166
1167 /* prepare daemon environment */
1168 1 result = chdir("/");
1169 1 umask(0);
1170
1171 /* assign STDIN/OUT/ERR to null device: */
1172 1 daemon_fd = open("/dev/null", O_RDONLY);
1173
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))
1174 {
1175 1 dup2(daemon_fd, STDIN_FILENO);
1176 1 close(daemon_fd);
1177 }
1178
1179 1 daemon_fd = open("/dev/null", O_WRONLY);
1180
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != -1)
1181 {
1182
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != STDOUT_FILENO)
1183 {
1184 1 dup2(daemon_fd, STDOUT_FILENO);
1185 }
1186
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (daemon_fd != STDERR_FILENO)
1187 {
1188 1 dup2(daemon_fd, STDERR_FILENO);
1189 }
1190 1 close(daemon_fd);
1191 }
1192
1193
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (ptr_pid)
1194 {
1195 1 *ptr_pid = 0; /* mark as daemon-branch */
1196 }
1197 1 return GATE_RESULT_OK;
1198 }
1199
1200 24 void* gate_posix_dlopen(char const* libpath, int flags)
1201 {
1202 void* ret;
1203 24 dlerror(); /* clear previous error state */
1204 24 ret = dlopen(libpath, flags);
1205
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 19 times.
24 if (NULL == ret)
1206 {
1207 5 char* last_errmsg = dlerror();
1208 5 GATE_DEBUG_TRACE("dlopen() failed");
1209
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (libpath)
1210 {
1211 5 GATE_DEBUG_TRACE(libpath);
1212 }
1213
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (last_errmsg)
1214 {
1215 5 GATE_DEBUG_TRACE(last_errmsg);
1216 }
1217 }
1218 24 return ret;
1219 }
1220
1221 12 int gate_posix_dlclose(void* handle)
1222 {
1223 12 int ret = dlclose(handle);
1224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (ret != 0)
1225 {
1226 char* last_errmsg = dlerror();
1227 GATE_DEBUG_TRACE("dlclose() failed");
1228 if (last_errmsg)
1229 {
1230 GATE_DEBUG_TRACE(last_errmsg);
1231 }
1232 }
1233 12 return ret;
1234 }
1235
1236 342 void* gate_posix_dlsym(void* handle, char const* symbol)
1237 {
1238 void* ret;
1239
1240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 342 times.
342 if (!symbol)
1241 {
1242 GATE_DEBUG_TRACE("Invalid arg for dlsym()");
1243 return NULL;
1244 }
1245
1246 342 dlerror();
1247 342 ret = dlsym(handle, symbol);
1248
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 338 times.
342 if (NULL == ret)
1249 {
1250 4 char* last_errmsg = dlerror();
1251 4 GATE_DEBUG_TRACE("dlsym() failed:");
1252 4 GATE_DEBUG_TRACE(symbol);
1253
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (last_errmsg)
1254 {
1255 4 GATE_DEBUG_TRACE(last_errmsg);
1256 }
1257 }
1258 342 return ret;
1259 }
1260
1261
1262 static void* volatile dl_global = NULL;
1263
1264 8 static void close_global_dlhandle_atexit()
1265 {
1266
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (NULL != dl_global)
1267 {
1268 8 void* handle = dl_global;
1269 8 dl_global = NULL;
1270 8 dlclose(handle);
1271 }
1272 8 }
1273
1274 26 void* gate_posix_global_sym(char const* symbol)
1275 {
1276 void* ret;
1277
1278
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (NULL == symbol)
1279 {
1280 return NULL;
1281 }
1282
1283 26 dlerror();
1284
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 18 times.
26 if (dl_global == NULL)
1285 {
1286 8 dl_global = dlopen(NULL, RTLD_GLOBAL | RTLD_NOW);
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (NULL == dl_global)
1288 {
1289 char* last_errmsg = dlerror();
1290 if (last_errmsg)
1291 {
1292 GATE_DEBUG_TRACE(last_errmsg);
1293 }
1294 }
1295 else
1296 {
1297 8 gate_platform_atexit(&close_global_dlhandle_atexit);
1298 }
1299 }
1300
1301 26 ret = dlsym(dl_global, symbol);
1302
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 12 times.
26 if (NULL == ret)
1303 {
1304 14 char* last_errmsg = dlerror();
1305 14 GATE_DEBUG_TRACE("dlsym() failed to load global symbol");
1306 14 GATE_DEBUG_TRACE(symbol);
1307
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (last_errmsg)
1308 {
1309 14 GATE_DEBUG_TRACE(last_errmsg);
1310 }
1311 }
1312 26 return ret;
1313 }
1314
1315 #if defined(GATE_SYS_DARWIN)
1316
1317 gate_bool_t gate_posix_clock_gettime(long* ptr_seconds, long* ptr_nanoseconds)
1318 {
1319 clock_serv_t cclock;
1320 mach_timespec_t mts;
1321 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
1322 clock_get_time(cclock, &mts);
1323 mach_port_deallocate(mach_task_self(), cclock);
1324 if (ptr_seconds) *ptr_seconds = mts.tv_sec;
1325 if (ptr_nanoseconds) *ptr_nanoseconds = mts.tv_nsec;
1326 return true;
1327 }
1328 gate_bool_t gate_posix_clock_gettime_monotonic(long* ptr_seconds, long* ptr_nanoseconds)
1329 {
1330 return gate_posix_clock_gettime(ptr_seconds, ptr_nanoseconds);
1331 }
1332
1333 #else
1334
1335 gate_bool_t gate_posix_clock_gettime(long* ptr_seconds, long* ptr_nanoseconds)
1336 {
1337 struct timespec ts;
1338 if (0 == clock_gettime(CLOCK_REALTIME, &ts))
1339 {
1340 if (ptr_seconds) *ptr_seconds = ts.tv_sec;
1341 if (ptr_nanoseconds) *ptr_nanoseconds = ts.tv_nsec;
1342 return true;
1343 }
1344 return false;
1345 }
1346 9310323 gate_bool_t gate_posix_clock_gettime_monotonic(long* ptr_seconds, long* ptr_nanoseconds)
1347 {
1348 struct timespec ts;
1349
1/2
✓ Branch 1 taken 9310323 times.
✗ Branch 2 not taken.
9310323 if (0 == clock_gettime(CLOCK_MONOTONIC, &ts))
1350 {
1351
1/2
✓ Branch 0 taken 9310323 times.
✗ Branch 1 not taken.
9310323 if (ptr_seconds) *ptr_seconds = ts.tv_sec;
1352
1/2
✓ Branch 0 taken 9310323 times.
✗ Branch 1 not taken.
9310323 if (ptr_nanoseconds) *ptr_nanoseconds = ts.tv_nsec;
1353 9310323 return true;
1354 }
1355 return false;
1356 }
1357
1358 #endif
1359
1360 4 static void create_semaphore_timeout(struct timespec* ptr_timeout, gate_uint32_t timeout_ms, gate_bool_t use_clocktime)
1361 {
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (use_clocktime)
1363 {
1364 long seconds, nanoseconds;
1365 gate_posix_clock_gettime(&seconds, &nanoseconds);
1366 ptr_timeout->tv_sec = seconds;
1367 ptr_timeout->tv_nsec = nanoseconds;
1368 }
1369 else
1370 {
1371 4 ptr_timeout->tv_sec = 0;
1372 4 ptr_timeout->tv_nsec = 0;
1373 }
1374 4 ptr_timeout->tv_sec += timeout_ms / 1000;
1375 4 ptr_timeout->tv_nsec += (timeout_ms % 1000) * 1000000;
1376 4 ptr_timeout->tv_sec += ptr_timeout->tv_nsec / 1000000000;
1377 4 ptr_timeout->tv_nsec %= 1000000000;
1378 4 }
1379
1380 #if defined(GATE_SYS_USE_POSIX_SEMAPHORE)
1381
1382 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1383 {
1384 sem_t* s = NULL;
1385 int result;
1386
1387 if (!ptr_sem || (count == 0))
1388 {
1389 return GATE_RESULT_INVALIDARG;
1390 }
1391
1392 s = (sem_t*)gate_mem_alloc(sizeof(sem_t));
1393 if (!s)
1394 {
1395 return GATE_RESULT_OUTOFMEMORY;
1396 }
1397 result = sem_init(s, 0, (unsigned int)count);
1398 if (result != 0)
1399 {
1400 gate_mem_dealloc(s);
1401 return GATE_RESULT_FAILED;
1402 }
1403 else
1404 {
1405 *ptr_sem = (gate_platform_semaphore_t)s;
1406 return GATE_RESULT_OK;
1407 }
1408 }
1409 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1410 {
1411 sem_t** pps = (sem_t**)ptr_sem;
1412 if (!pps || !*pps)
1413 {
1414 return GATE_RESULT_INVALIDARG;
1415 }
1416
1417 if (!ptr_timeout_ms)
1418 {
1419 if (0 == sem_wait(*pps))
1420 {
1421 /* success case */
1422 return GATE_RESULT_OK;
1423 }
1424 }
1425 else
1426 {
1427 struct timespec timeout;
1428 int last_error;
1429
1430 create_semaphore_timeout(&timeout, *ptr_timeout_ms, true);
1431
1432 if (0 == sem_timedwait(*pps, &timeout))
1433 {
1434 /* success case */
1435 return GATE_RESULT_OK;
1436 }
1437 last_error = gate_posix_errno(NULL);
1438 if (last_error == ETIMEDOUT)
1439 {
1440 return GATE_RESULT_TIMEOUT;
1441 }
1442 }
1443
1444 /* generic error case */
1445 return GATE_RESULT_FAILED;
1446 }
1447 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1448 {
1449 sem_t** pps = (sem_t**)ptr_sem;
1450 if (!pps || !*pps)
1451 {
1452 return GATE_RESULT_INVALIDARG;
1453 }
1454
1455 if (0 == sem_post(*pps))
1456 {
1457 return GATE_RESULT_OK;
1458 }
1459 return GATE_RESULT_FAILED;
1460 }
1461 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1462 {
1463 sem_t** pps = (sem_t**)ptr_sem;
1464 if (!pps || !*pps)
1465 {
1466 return GATE_RESULT_INVALIDARG;
1467 }
1468 if (0 == sem_close(*pps))
1469 {
1470 gate_mem_dealloc(*pps);
1471 *pps = NULL;
1472 return GATE_RESULT_OK;
1473 }
1474 else
1475 {
1476 return GATE_RESULT_FAILED;
1477 }
1478 }
1479
1480 #else /* GATE_SYS_USE_POSIX_SEMAPHORE */
1481
1482 #if defined(GATE_SYS_LINUX) || defined(GATE_SYS_NETBSD) || defined(GATE_SYS_FREEBSD)
1483 union semun
1484 {
1485 int val;
1486 struct semid_ds* buf;
1487 unsigned short* array;
1488 };
1489 #endif
1490
1491 3 gate_result_t gate_platform_semaphore_create(gate_platform_semaphore_t* ptr_sem, unsigned int count)
1492 {
1493 3 int* s = (int*)ptr_sem;
1494 union semun arg;
1495
1496
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))
1497 {
1498 return GATE_RESULT_INVALIDARG;
1499 }
1500
1501 3 *s = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | SHM_R | SHM_W);
1502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (*s == -1)
1503 {
1504 return GATE_RESULT_OUTOFRESOURCES;
1505 }
1506
1507 3 arg.val = (int)count;
1508 3 semctl(*s, 0, SETVAL, arg);
1509 3 return GATE_RESULT_OK;
1510 }
1511
1512 typedef int(*semtimedop_func_ptr)(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout);
1513
1514 #if defined(HAVE_SEMTIMEDOP)
1515
1516 4 static int semtimedop_wrapper(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1517 {
1518 4 return semtimedop(semid, sops, nsops, timeout);
1519 }
1520
1521 4 static semtimedop_func_ptr get_semtimedop()
1522 {
1523 4 return &semtimedop_wrapper;
1524 }
1525
1526 #else
1527
1528 static int fallback_semtimedop(int semid, struct sembuf* sops, unsigned nsops, struct timespec* timeout)
1529 {
1530 int ret = -1;
1531 struct sembuf op[1024];
1532 unsigned index;
1533 struct timespec now;
1534 long seconds = 0;
1535 long nanoseconds = 0;
1536
1537 gate_posix_clock_gettime_monotonic(&seconds, &nanoseconds);
1538 now.tv_sec = seconds;
1539 now.tv_nsec = nanoseconds;
1540 do
1541 {
1542 int errcode = 0;
1543 const long nsec = (now.tv_nsec + timeout->tv_nsec);
1544 struct timespec end;
1545 struct timespec sleep_timeout;
1546 end.tv_sec = (now.tv_sec + timeout->tv_sec) + (nsec) / 1000000000;
1547 end.tv_nsec = nsec % 1000000000;
1548
1549 if (nsops > sizeof(op) / sizeof(op[0]))
1550 {
1551 nsops = sizeof(op) / sizeof(op[0]);
1552 }
1553
1554 for (index = 0; index != nsops; ++index)
1555 {
1556 op[index].sem_num = sops[index].sem_num;
1557 op[index].sem_op = sops[index].sem_op;
1558 op[index].sem_flg = sops[index].sem_flg | IPC_NOWAIT;
1559 }
1560
1561 sleep_timeout.tv_sec = 0;
1562 sleep_timeout.tv_nsec = 10;
1563 do
1564 {
1565 ret = semop(semid, &op[0], nsops);
1566 if (ret == 0)
1567 {
1568 /* operation succeeded, we are done (ret == 0) */
1569 break;
1570 }
1571 errcode = gate_posix_errno(NULL);
1572
1573
1574 if (!gate_posix_clock_gettime_monotonic(&seconds, &nanoseconds))
1575 {
1576 break;
1577 }
1578 now.tv_sec = seconds;
1579 now.tv_nsec = nanoseconds;
1580
1581 if ((now.tv_sec > end.tv_sec) || ((now.tv_sec == end.tv_sec) && (now.tv_nsec > end.tv_nsec)))
1582 {
1583 /* timeout reached, (ret == -1) */
1584 gate_posix_set_errno(EAGAIN);
1585 break;
1586 }
1587 nanosleep(&sleep_timeout, NULL);
1588 if (sleep_timeout.tv_nsec < 50000000)
1589 {
1590 sleep_timeout.tv_nsec *= 2;
1591 }
1592 } while (errcode == EAGAIN);
1593 } while (0);
1594 return ret;
1595 }
1596
1597 static semtimedop_func_ptr get_semtimedop()
1598 {
1599 static semtimedop_func_ptr semtimedop_func = NULL;
1600 if (!semtimedop_func)
1601 {
1602 semtimedop_func = (semtimedop_func_ptr)gate_posix_global_sym("semtimedop");
1603 if (!semtimedop_func)
1604 {
1605 semtimedop_func = &fallback_semtimedop;
1606 }
1607 }
1608 return semtimedop_func;
1609 }
1610
1611 #endif
1612
1613 8 gate_result_t gate_platform_semaphore_acquire(gate_platform_semaphore_t* ptr_sem, gate_uint32_t const* ptr_timeout_ms)
1614 {
1615 8 int* s = (int*)ptr_sem;
1616 struct sembuf op;
1617
1618
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))
1619 {
1620 return GATE_RESULT_INVALIDARG;
1621 }
1622
1623 8 op.sem_num = 0;
1624 8 op.sem_op = -1;
1625 8 op.sem_flg = SEM_UNDO;
1626
1627
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (!ptr_timeout_ms)
1628 {
1629
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (-1 == semop(*s, &op, 1))
1630 {
1631 return GATE_RESULT_FAILED;
1632 }
1633 }
1634 else
1635 {
1636 struct timespec timeout;
1637 4 semtimedop_func_ptr semtimedop_func = get_semtimedop();
1638
1639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (semtimedop_func == NULL)
1640 {
1641 2 return GATE_RESULT_NOTSUPPORTED;
1642 }
1643
1644 4 create_semaphore_timeout(&timeout, *ptr_timeout_ms, false);
1645
1646
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (-1 == semtimedop_func(*s, &op, 1, &timeout))
1647 {
1648
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (gate_posix_errno(NULL) == EAGAIN)
1649 {
1650 2 return GATE_RESULT_TIMEOUT;
1651 }
1652 else
1653 {
1654 return GATE_RESULT_FAILED;
1655 }
1656 }
1657 }
1658
1659 /* generic success case */
1660 6 return GATE_RESULT_OK;
1661 }
1662
1663 6 gate_result_t gate_platform_semaphore_release(gate_platform_semaphore_t* ptr_sem)
1664 {
1665 6 int* s = (int*)ptr_sem;
1666 struct sembuf op;
1667
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))
1668 {
1669 return GATE_RESULT_INVALIDARG;
1670 }
1671
1672 6 op.sem_num = 0;
1673 6 op.sem_op = 1;
1674 6 op.sem_flg = SEM_UNDO;
1675
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (-1 == semop(*s, &op, 1))
1676 {
1677 return GATE_RESULT_FAILED;
1678 }
1679 6 return GATE_RESULT_OK;
1680 }
1681 3 gate_result_t gate_platform_semaphore_destroy(gate_platform_semaphore_t* ptr_sem)
1682 {
1683 3 int* s = (int*)ptr_sem;
1684
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))
1685 {
1686 return GATE_RESULT_INVALIDARG;
1687 }
1688
1689 3 semctl(*s, 0, IPC_RMID, NULL);
1690 3 *s = -1;
1691 3 return GATE_RESULT_OK;
1692 }
1693
1694 #endif /* GATE_SYS_USE_POSIX_SEMAPHORE*/
1695
1696 20 gate_bool_t gate_platform_yield()
1697 {
1698 20 sched_yield();
1699 20 return true;
1700 }
1701
1702 #endif /* GATE_SYS_POSIX */
1703