[352] | 1 | #include <mqueue.h>
|
---|
| 2 | #include <pthread.h>
|
---|
| 3 | #include <errno.h>
|
---|
| 4 | #include <sys/socket.h>
|
---|
| 5 | #include <signal.h>
|
---|
| 6 | #include <unistd.h>
|
---|
| 7 | #include "syscall.h"
|
---|
| 8 |
|
---|
| 9 | struct args {
|
---|
| 10 | pthread_barrier_t barrier;
|
---|
| 11 | int sock;
|
---|
| 12 | const struct sigevent *sev;
|
---|
| 13 | };
|
---|
| 14 |
|
---|
| 15 | static void *start(void *p)
|
---|
| 16 | {
|
---|
| 17 | struct args *args = p;
|
---|
| 18 | char buf[32];
|
---|
| 19 | ssize_t n;
|
---|
| 20 | int s = args->sock;
|
---|
| 21 | void (*func)(union sigval) = args->sev->sigev_notify_function;
|
---|
| 22 | union sigval val = args->sev->sigev_value;
|
---|
| 23 |
|
---|
| 24 | pthread_barrier_wait(&args->barrier);
|
---|
| 25 | n = recv(s, buf, sizeof(buf), MSG_NOSIGNAL|MSG_WAITALL);
|
---|
| 26 | close(s);
|
---|
| 27 | if (n==sizeof buf && buf[sizeof buf - 1] == 1)
|
---|
| 28 | func(val);
|
---|
| 29 | return 0;
|
---|
| 30 | }
|
---|
| 31 |
|
---|
| 32 | int mq_notify(mqd_t mqd, const struct sigevent *sev)
|
---|
| 33 | {
|
---|
| 34 | struct args args = { .sev = sev };
|
---|
| 35 | pthread_attr_t attr;
|
---|
| 36 | pthread_t td;
|
---|
| 37 | int s;
|
---|
| 38 | struct sigevent sev2;
|
---|
| 39 | static const char zeros[32];
|
---|
| 40 |
|
---|
| 41 | if (!sev || sev->sigev_notify != SIGEV_THREAD)
|
---|
| 42 | return syscall(SYS_mq_notify, mqd, sev);
|
---|
| 43 |
|
---|
| 44 | s = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, 0);
|
---|
| 45 | if (s < 0) return -1;
|
---|
| 46 | args.sock = s;
|
---|
| 47 |
|
---|
| 48 | if (sev->sigev_notify_attributes) attr = *sev->sigev_notify_attributes;
|
---|
| 49 | else pthread_attr_init(&attr);
|
---|
| 50 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
---|
| 51 | pthread_barrier_init(&args.barrier, 0, 2);
|
---|
| 52 |
|
---|
| 53 | if (pthread_create(&td, &attr, start, &args)) {
|
---|
| 54 | __syscall(SYS_close, s);
|
---|
| 55 | errno = EAGAIN;
|
---|
| 56 | return -1;
|
---|
| 57 | }
|
---|
| 58 |
|
---|
| 59 | pthread_barrier_wait(&args.barrier);
|
---|
| 60 | pthread_barrier_destroy(&args.barrier);
|
---|
| 61 |
|
---|
| 62 | sev2.sigev_notify = SIGEV_THREAD;
|
---|
| 63 | sev2.sigev_signo = s;
|
---|
| 64 | sev2.sigev_value.sival_ptr = (void *)&zeros;
|
---|
| 65 |
|
---|
| 66 | if (syscall(SYS_mq_notify, mqd, &sev2) < 0) {
|
---|
| 67 | pthread_cancel(td);
|
---|
| 68 | __syscall(SYS_close, s);
|
---|
| 69 | return -1;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | return 0;
|
---|
| 73 | }
|
---|