mq_notify.c raw

   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  }
  74