aio_notify.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /* Notify initiator of AIO request.
  2. Copyright (C) 1997-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <errno.h>
  16. #include <pthreadP.h>
  17. #include <stdlib.h>
  18. #include <unistd.h>
  19. #include <aio_misc.h>
  20. #include <signal.h>
  21. #if !PTHREAD_IN_LIBC
  22. # define __pthread_attr_init pthread_attr_init
  23. # define __pthread_attr_setdetachstate pthread_attr_setdetachstate
  24. #endif
  25. #ifndef aio_start_notify_thread
  26. # define aio_start_notify_thread() do { } while (0)
  27. #endif
  28. struct notify_func
  29. {
  30. void (*func) (sigval_t);
  31. sigval_t value;
  32. };
  33. static void *
  34. notify_func_wrapper (void *arg)
  35. {
  36. aio_start_notify_thread ();
  37. struct notify_func *const n = arg;
  38. void (*func) (sigval_t) = n->func;
  39. sigval_t value = n->value;
  40. free (n);
  41. (*func) (value);
  42. return NULL;
  43. }
  44. int
  45. __aio_notify_only (struct sigevent *sigev)
  46. {
  47. int result = 0;
  48. /* Send the signal to notify about finished processing of the request. */
  49. if (__glibc_unlikely (sigev->sigev_notify == SIGEV_THREAD))
  50. {
  51. /* We have to start a thread. */
  52. pthread_t tid;
  53. pthread_attr_t attr, *pattr;
  54. pattr = (pthread_attr_t *) sigev->sigev_notify_attributes;
  55. if (pattr == NULL)
  56. {
  57. __pthread_attr_init (&attr);
  58. __pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
  59. pattr = &attr;
  60. }
  61. /* SIGEV may be freed as soon as we return, so we cannot let the
  62. notification thread use that pointer. Even though a sigval_t is
  63. only one word and the same size as a void *, we cannot just pass
  64. the value through pthread_create as the argument and have the new
  65. thread run the user's function directly, because on some machines
  66. the calling convention for a union like sigval_t is different from
  67. that for a pointer type like void *. */
  68. struct notify_func *nf = malloc (sizeof *nf);
  69. if (nf == NULL)
  70. result = -1;
  71. else
  72. {
  73. nf->func = sigev->sigev_notify_function;
  74. nf->value = sigev->sigev_value;
  75. if (__pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0)
  76. {
  77. free (nf);
  78. result = -1;
  79. }
  80. }
  81. }
  82. else if (sigev->sigev_notify == SIGEV_SIGNAL)
  83. {
  84. /* We have to send a signal. */
  85. #if _POSIX_REALTIME_SIGNALS > 0
  86. /* Note that the standard gives us the option of using a plain
  87. non-queuing signal here when SA_SIGINFO is not set for the signal. */
  88. if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, getpid ())
  89. < 0)
  90. result = -1;
  91. #else
  92. /* There are no queued signals on this system at all. */
  93. result = raise (sigev->sigev_signo);
  94. #endif
  95. }
  96. return result;
  97. }
  98. void
  99. __aio_notify (struct requestlist *req)
  100. {
  101. struct waitlist *waitlist;
  102. struct aiocb *aiocbp = &req->aiocbp->aiocb;
  103. if (__aio_notify_only (&aiocbp->aio_sigevent) != 0)
  104. {
  105. /* XXX What shall we do if already an error is set by
  106. read/write/fsync? */
  107. aiocbp->__error_code = errno;
  108. aiocbp->__return_value = -1;
  109. }
  110. /* Now also notify possibly waiting threads. */
  111. waitlist = req->waiting;
  112. while (waitlist != NULL)
  113. {
  114. struct waitlist *next = waitlist->next;
  115. if (waitlist->sigevp == NULL)
  116. {
  117. if (waitlist->result != NULL && aiocbp->__return_value == -1)
  118. *waitlist->result = -1;
  119. #ifdef DONT_NEED_AIO_MISC_COND
  120. AIO_MISC_NOTIFY (waitlist);
  121. #else
  122. /* Decrement the counter. */
  123. --*waitlist->counterp;
  124. pthread_cond_signal (waitlist->cond);
  125. #endif
  126. }
  127. else
  128. /* This is part of an asynchronous `lio_listio' operation. If
  129. this request is the last one, send the signal. */
  130. if (--*waitlist->counterp == 0)
  131. {
  132. __aio_notify_only (waitlist->sigevp);
  133. /* This is tricky. See lio_listio.c for the reason why
  134. this works. */
  135. free ((void *) waitlist->counterp);
  136. }
  137. waitlist = next;
  138. }
  139. }