• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
start(void * p)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 
mq_notify(mqd_t mqd,const struct sigevent * sev)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 }
74