|
| 1 | +/* KallistiOS ##version## |
| 2 | +
|
| 3 | + include/semaphore.h |
| 4 | + Copyright (C) 2026 Falco Girgis |
| 5 | +*/ |
| 6 | + |
| 7 | +/* |
| 8 | + This file is an extremely lightweight wrapper which simply "extends" KOS's |
| 9 | + existing <kos/sem.h> kernel semaphores, which are already partially POSIX- |
| 10 | + compliant, and implements the rest of the missing POSIX functionality as a |
| 11 | + light-weight inline function wrapper API around them. |
| 12 | +*/ |
| 13 | + |
| 14 | +#ifndef __SEMAPHORE_H |
| 15 | +#define __SEMAPHORE_H |
| 16 | + |
| 17 | +#include <kos/cdefs.h> |
| 18 | +#include <kos/sem.h> |
| 19 | +#include <errno.h> |
| 20 | + |
| 21 | +__BEGIN_DECLS |
| 22 | + |
| 23 | +/* POSIX semaphores are type-compatible with kernel semaphores. */ |
| 24 | +typedef semaphore_t sem_t; |
| 25 | + |
| 26 | +/* Selector macro, which implements function overload resolution for 2 and 3 |
| 27 | + argument versions of the same function. Uses a "sliding argument" trick so |
| 28 | + that NAME is selected based on the number of arguments it gets passed. |
| 29 | +*/ |
| 30 | +#define SEM_INIT_SELECTOR(_1, _2, _3, NAME, ...) NAME |
| 31 | + |
| 32 | +/* Due to the fact that KOS's <kos/sem.h> is technically stomping on the POSIX |
| 33 | + symbol, sem_init(), by providing its own two argument version, we must |
| 34 | + implement some crazy macro shenanigans to allow both KOS's 2 argument |
| 35 | + version of sem_init() and POSIX's 3 argument version of sem_init() to |
| 36 | + coexist without causing errors on incompatible function declarations or |
| 37 | + duplicate symbols. |
| 38 | + |
| 39 | + What we do here, is use a macro named "sem_init()" to "hide" the KOS |
| 40 | + declaration with the same name, forwarding the arguments on as __VA_ARGS__ |
| 41 | + into the selector macro, which will return either the identifier |
| 42 | + "sem_init_posix," in the case when 3 arguments are provided, or |
| 43 | + "(sem_init)," in the case when 2 arguments are provided. |
| 44 | +
|
| 45 | + Finally, we simply invoke the return expression of SEM_INIT_SELECTOR() as |
| 46 | + if it were a function name (because it is). In the case of (sem_init)(), |
| 47 | + the parentheses around the identifier name allow us to escape from macro |
| 48 | + expansion, avoided infinite macro recursion and unhiding KOS's version of |
| 49 | + sem_init(), which we will call into. |
| 50 | +*/ |
| 51 | +#define sem_init(...) \ |
| 52 | + SEM_INIT_SELECTOR(__VA_ARGS__, sem_init_posix, (sem_init))(__VA_ARGS__) |
| 53 | + |
| 54 | +/* 3-argument POSIX-compliant implementation of sem_init(). */ |
| 55 | +static inline int sem_init_posix(sem_t *sem, int shared, unsigned int value) { |
| 56 | + if(shared) { /* We don't support shared semaphores. */ |
| 57 | + errno = ENOSYS; |
| 58 | + return -1; |
| 59 | + } |
| 60 | + else |
| 61 | + return sem_init(sem, value); |
| 62 | +} |
| 63 | + |
| 64 | +/* Forward POSIX sem_close() directly on to KOS's sem_destroy(). */ |
| 65 | +static inline int sem_close(sem_t* sem) { |
| 66 | + return sem_destroy(sem); |
| 67 | +} |
| 68 | + |
| 69 | +/* Implement POSIX's sem_getvalue() from KOS's sem_count(). */ |
| 70 | +static inline int sem_getvalue(sem_t *sem, int *value) { |
| 71 | + *value = sem_count(sem); |
| 72 | + return 0; |
| 73 | +} |
| 74 | + |
| 75 | +/* Forward POSIX's sem_post() on to KOS's sem_signal(). */ |
| 76 | +static inline int sem_post(sem_t *sem) { |
| 77 | + return sem_signal(sem); |
| 78 | +} |
| 79 | + |
| 80 | +__END_DECLS |
| 81 | + |
| 82 | +#endif |
0 commit comments