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