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 9struct args { 10 pthread_barrier_t barrier; 11 int sock; 12 const struct sigevent *sev; 13}; 14 15static 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 32int 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} 74