mq_notify.c 1.7 KB

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