diff options
author | Vladimir Azarov <avm@intermediate-node.net> | 2024-10-01 15:47:05 +0200 |
---|---|---|
committer | Vladimir Azarov <avm@intermediate-node.net> | 2024-10-01 15:47:05 +0200 |
commit | 4abab5ad6c8465a7528ccdd5f49367da05f78bbd (patch) | |
tree | ebf009bf1376a5a223a915bc27cbbd791a1316bc /src/mq |
Initial version
Diffstat (limited to 'src/mq')
-rw-r--r-- | src/mq/mq_close.c | 7 | ||||
-rw-r--r-- | src/mq/mq_getattr.c | 7 | ||||
-rw-r--r-- | src/mq/mq_notify.c | 92 | ||||
-rw-r--r-- | src/mq/mq_open.c | 19 | ||||
-rw-r--r-- | src/mq/mq_receive.c | 6 | ||||
-rw-r--r-- | src/mq/mq_send.c | 6 | ||||
-rw-r--r-- | src/mq/mq_setattr.c | 7 | ||||
-rw-r--r-- | src/mq/mq_timedreceive.c | 24 | ||||
-rw-r--r-- | src/mq/mq_timedsend.c | 24 | ||||
-rw-r--r-- | src/mq/mq_unlink.c | 16 |
10 files changed, 208 insertions, 0 deletions
diff --git a/src/mq/mq_close.c b/src/mq/mq_close.c new file mode 100644 index 0000000..a61f094 --- /dev/null +++ b/src/mq/mq_close.c @@ -0,0 +1,7 @@ +#include <mqueue.h> +#include "syscall.h" + +int mq_close(mqd_t mqd) +{ + return syscall(SYS_close, mqd); +} diff --git a/src/mq/mq_getattr.c b/src/mq/mq_getattr.c new file mode 100644 index 0000000..dce1806 --- /dev/null +++ b/src/mq/mq_getattr.c @@ -0,0 +1,7 @@ +#include <mqueue.h> +#include "syscall.h" + +int mq_getattr(mqd_t mqd, struct mq_attr *attr) +{ + return mq_setattr(mqd, 0, attr); +} diff --git a/src/mq/mq_notify.c b/src/mq/mq_notify.c new file mode 100644 index 0000000..0e1e6c7 --- /dev/null +++ b/src/mq/mq_notify.c @@ -0,0 +1,92 @@ +#include <mqueue.h> +#include <pthread.h> +#include <errno.h> +#include <sys/socket.h> +#include <signal.h> +#include <unistd.h> +#include <semaphore.h> +#include "syscall.h" + +struct args { + sem_t sem; + int sock; + mqd_t mqd; + int err; + const struct sigevent *sev; +}; + +static void *start(void *p) +{ + struct args *args = p; + char buf[32]; + ssize_t n; + int s = args->sock; + void (*func)(union sigval) = args->sev->sigev_notify_function; + union sigval val = args->sev->sigev_value; + struct sigevent sev2; + static const char zeros[32]; + int err; + + sev2.sigev_notify = SIGEV_THREAD; + sev2.sigev_signo = s; + sev2.sigev_value.sival_ptr = (void *)&zeros; + + args->err = err = -__syscall(SYS_mq_notify, args->mqd, &sev2); + sem_post(&args->sem); + if (err) return 0; + + pthread_detach(pthread_self()); + n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL); + close(s); + if (n==sizeof buf && buf[sizeof buf - 1] == 1) + func(val); + return 0; +} + +int mq_notify(mqd_t mqd, const struct sigevent *sev) +{ + struct args args = { .sev = sev }; + pthread_attr_t attr; + pthread_t td; + int s; + int cs; + sigset_t allmask, origmask; + + if (!sev || sev->sigev_notify != SIGEV_THREAD) + return syscall(SYS_mq_notify, mqd, sev); + + s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0); + if (s < 0) return -1; + args.sock = s; + args.mqd = mqd; + + if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes; + else pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + sem_init(&args.sem, 0, 0); + + sigfillset(&allmask); + pthread_sigmask(SIG_BLOCK, &allmask, &origmask); + if (pthread_create(&td, &attr, start, &args)) { + __syscall(SYS_close, s); + pthread_sigmask(SIG_SETMASK, &origmask, 0); + errno = EAGAIN; + return -1; + } + pthread_sigmask(SIG_SETMASK, &origmask, 0); + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs); + sem_wait(&args.sem); + sem_destroy(&args.sem); + + if (args.err) { + __syscall(SYS_close, s); + pthread_join(td, 0); + pthread_setcancelstate(cs, 0); + errno = args.err; + return -1; + } + + pthread_setcancelstate(cs, 0); + return 0; +} diff --git a/src/mq/mq_open.c b/src/mq/mq_open.c new file mode 100644 index 0000000..aa91d58 --- /dev/null +++ b/src/mq/mq_open.c @@ -0,0 +1,19 @@ +#include <mqueue.h> +#include <fcntl.h> +#include <stdarg.h> +#include "syscall.h" + +mqd_t mq_open(const char *name, int flags, ...) +{ + mode_t mode = 0; + struct mq_attr *attr = 0; + if (*name == '/') name++; + if (flags & O_CREAT) { + va_list ap; + va_start(ap, flags); + mode = va_arg(ap, mode_t); + attr = va_arg(ap, struct mq_attr *); + va_end(ap); + } + return syscall(SYS_mq_open, name, flags, mode, attr); +} diff --git a/src/mq/mq_receive.c b/src/mq/mq_receive.c new file mode 100644 index 0000000..0b1bb4e --- /dev/null +++ b/src/mq/mq_receive.c @@ -0,0 +1,6 @@ +#include <mqueue.h> + +ssize_t mq_receive(mqd_t mqd, char *msg, size_t len, unsigned *prio) +{ + return mq_timedreceive(mqd, msg, len, prio, 0); +} diff --git a/src/mq/mq_send.c b/src/mq/mq_send.c new file mode 100644 index 0000000..1acb1b7 --- /dev/null +++ b/src/mq/mq_send.c @@ -0,0 +1,6 @@ +#include <mqueue.h> + +int mq_send(mqd_t mqd, const char *msg, size_t len, unsigned prio) +{ + return mq_timedsend(mqd, msg, len, prio, 0); +} diff --git a/src/mq/mq_setattr.c b/src/mq/mq_setattr.c new file mode 100644 index 0000000..eae022e --- /dev/null +++ b/src/mq/mq_setattr.c @@ -0,0 +1,7 @@ +#include <mqueue.h> +#include "syscall.h" + +int mq_setattr(mqd_t mqd, const struct mq_attr *restrict new, struct mq_attr *restrict old) +{ + return syscall(SYS_mq_getsetattr, mqd, new, old); +} diff --git a/src/mq/mq_timedreceive.c b/src/mq/mq_timedreceive.c new file mode 100644 index 0000000..f41b664 --- /dev/null +++ b/src/mq/mq_timedreceive.c @@ -0,0 +1,24 @@ +#include <mqueue.h> +#include <errno.h> +#include "syscall.h" + +#define IS32BIT(x) !((x)+0x80000000ULL>>32) +#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) + +ssize_t mq_timedreceive(mqd_t mqd, char *restrict msg, size_t len, unsigned *restrict prio, const struct timespec *restrict at) +{ +#ifdef SYS_mq_timedreceive_time64 + time_t s = at ? at->tv_sec : 0; + long ns = at ? at->tv_nsec : 0; + long r = -ENOSYS; + if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || !IS32BIT(s)) + r = __syscall_cp(SYS_mq_timedreceive_time64, mqd, msg, len, prio, + at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); + if (SYS_mq_timedreceive == SYS_mq_timedreceive_time64 || r != -ENOSYS) + return __syscall_ret(r); + return syscall_cp(SYS_mq_timedreceive, mqd, msg, len, prio, + at ? ((long[]){CLAMP(s), ns}) : 0); +#else + return syscall_cp(SYS_mq_timedreceive, mqd, msg, len, prio, at); +#endif +} diff --git a/src/mq/mq_timedsend.c b/src/mq/mq_timedsend.c new file mode 100644 index 0000000..56cfcbb --- /dev/null +++ b/src/mq/mq_timedsend.c @@ -0,0 +1,24 @@ +#include <mqueue.h> +#include <errno.h> +#include "syscall.h" + +#define IS32BIT(x) !((x)+0x80000000ULL>>32) +#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63)) + +int mq_timedsend(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec *at) +{ +#ifdef SYS_mq_timedsend_time64 + time_t s = at ? at->tv_sec : 0; + long ns = at ? at->tv_nsec : 0; + long r = -ENOSYS; + if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || !IS32BIT(s)) + r = __syscall_cp(SYS_mq_timedsend_time64, mqd, msg, len, prio, + at ? ((long long []){at->tv_sec, at->tv_nsec}) : 0); + if (SYS_mq_timedsend == SYS_mq_timedsend_time64 || r != -ENOSYS) + return __syscall_ret(r); + return syscall_cp(SYS_mq_timedsend, mqd, msg, len, prio, + at ? ((long[]){CLAMP(s), ns}) : 0); +#else + return syscall_cp(SYS_mq_timedsend, mqd, msg, len, prio, at); +#endif +} diff --git a/src/mq/mq_unlink.c b/src/mq/mq_unlink.c new file mode 100644 index 0000000..6a08a4c --- /dev/null +++ b/src/mq/mq_unlink.c @@ -0,0 +1,16 @@ +#include <mqueue.h> +#include <errno.h> +#include "syscall.h" + +int mq_unlink(const char *name) +{ + int ret; + if (*name == '/') name++; + ret = __syscall(SYS_mq_unlink, name); + if (ret < 0) { + if (ret == -EPERM) ret = -EACCES; + errno = -ret; + return -1; + } + return ret; +} |