github.com/afumu/libc@v0.0.6/musl/src/mq/mq_notify.c (about)

     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  }