compatfd.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * signalfd/eventfd compatibility
  3. *
  4. * Copyright IBM, Corp. 2008
  5. *
  6. * Authors:
  7. * Anthony Liguori <aliguori@us.ibm.com>
  8. *
  9. * This work is licensed under the terms of the GNU GPL, version 2. See
  10. * the COPYING file in the top-level directory.
  11. *
  12. */
  13. #include "qemu-common.h"
  14. #include "compatfd.h"
  15. #include <sys/syscall.h>
  16. #include <pthread.h>
  17. struct sigfd_compat_info
  18. {
  19. sigset_t mask;
  20. int fd;
  21. };
  22. static void *sigwait_compat(void *opaque)
  23. {
  24. struct sigfd_compat_info *info = opaque;
  25. sigset_t all;
  26. sigfillset(&all);
  27. pthread_sigmask(SIG_BLOCK, &all, NULL);
  28. while (1) {
  29. int sig;
  30. int err;
  31. err = sigwait(&info->mask, &sig);
  32. if (err != 0) {
  33. if (errno == EINTR) {
  34. continue;
  35. } else {
  36. return NULL;
  37. }
  38. } else {
  39. struct qemu_signalfd_siginfo buffer;
  40. size_t offset = 0;
  41. memset(&buffer, 0, sizeof(buffer));
  42. buffer.ssi_signo = sig;
  43. while (offset < sizeof(buffer)) {
  44. ssize_t len;
  45. len = write(info->fd, (char *)&buffer + offset,
  46. sizeof(buffer) - offset);
  47. if (len == -1 && errno == EINTR)
  48. continue;
  49. if (len <= 0) {
  50. return NULL;
  51. }
  52. offset += len;
  53. }
  54. }
  55. }
  56. }
  57. static int qemu_signalfd_compat(const sigset_t *mask)
  58. {
  59. pthread_attr_t attr;
  60. pthread_t tid;
  61. struct sigfd_compat_info *info;
  62. int fds[2];
  63. info = malloc(sizeof(*info));
  64. if (info == NULL) {
  65. errno = ENOMEM;
  66. return -1;
  67. }
  68. if (pipe(fds) == -1) {
  69. free(info);
  70. return -1;
  71. }
  72. qemu_set_cloexec(fds[0]);
  73. qemu_set_cloexec(fds[1]);
  74. memcpy(&info->mask, mask, sizeof(*mask));
  75. info->fd = fds[1];
  76. pthread_attr_init(&attr);
  77. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  78. pthread_create(&tid, &attr, sigwait_compat, info);
  79. pthread_attr_destroy(&attr);
  80. return fds[0];
  81. }
  82. int qemu_signalfd(const sigset_t *mask)
  83. {
  84. #if defined(CONFIG_SIGNALFD)
  85. int ret;
  86. ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
  87. if (ret != -1) {
  88. qemu_set_cloexec(ret);
  89. return ret;
  90. }
  91. #endif
  92. return qemu_signalfd_compat(mask);
  93. }
  94. bool qemu_signalfd_available(void)
  95. {
  96. #ifdef CONFIG_SIGNALFD
  97. errno = 0;
  98. syscall(SYS_signalfd, -1, NULL, _NSIG / 8);
  99. return errno != ENOSYS;
  100. #else
  101. return false;
  102. #endif
  103. }