gai_notify.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /* Copyright (C) 2001-2026 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, see
  13. <https://www.gnu.org/licenses/>. */
  14. #include <netdb.h>
  15. #include <pthread.h>
  16. #include <stdlib.h>
  17. #include <gai_misc.h>
  18. #if !PTHREAD_IN_LIBC
  19. /* The available function names differ outside of libc. (In libc, we
  20. need to use hidden aliases to avoid the PLT.) */
  21. #define __pthread_attr_init pthread_attr_init
  22. #define __pthread_attr_setdetachstate pthread_attr_setdetachstate
  23. #define __pthread_cond_signal pthread_cond_signal
  24. #define __pthread_cond_timedwait pthread_cond_timedwait
  25. #define __pthread_create pthread_create
  26. #endif
  27. struct notify_func
  28. {
  29. void (*func) (sigval_t);
  30. sigval_t value;
  31. };
  32. static void *
  33. notify_func_wrapper (void *arg)
  34. {
  35. gai_start_notify_thread ();
  36. struct notify_func *const n = arg;
  37. void (*func) (sigval_t) = n->func;
  38. sigval_t value = n->value;
  39. free (n);
  40. (*func) (value);
  41. return NULL;
  42. }
  43. int
  44. __gai_notify_only (struct sigevent *sigev, pid_t caller_pid)
  45. {
  46. int result = 0;
  47. /* Send the signal to notify about finished processing of the request. */
  48. if (sigev->sigev_notify == SIGEV_THREAD)
  49. {
  50. /* We have to start a thread. */
  51. pthread_t tid;
  52. pthread_attr_t attr, *pattr;
  53. pattr = (pthread_attr_t *) sigev->sigev_notify_attributes;
  54. if (pattr == NULL)
  55. {
  56. __pthread_attr_init (&attr);
  57. __pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
  58. pattr = &attr;
  59. }
  60. /* SIGEV may be freed as soon as we return, so we cannot let the
  61. notification thread use that pointer. Even though a sigval_t is
  62. only one word and the same size as a void *, we cannot just pass
  63. the value through pthread_create as the argument and have the new
  64. thread run the user's function directly, because on some machines
  65. the calling convention for a union like sigval_t is different from
  66. that for a pointer type like void *. */
  67. struct notify_func *nf = malloc (sizeof *nf);
  68. if (nf == NULL)
  69. result = -1;
  70. else
  71. {
  72. nf->func = sigev->sigev_notify_function;
  73. nf->value = sigev->sigev_value;
  74. if (__pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0)
  75. {
  76. free (nf);
  77. result = -1;
  78. }
  79. }
  80. }
  81. else if (sigev->sigev_notify == SIGEV_SIGNAL)
  82. /* We have to send a signal. */
  83. if (__gai_sigqueue (sigev->sigev_signo, sigev->sigev_value, caller_pid)
  84. < 0)
  85. result = -1;
  86. return result;
  87. }
  88. void
  89. __gai_notify (struct requestlist *req)
  90. {
  91. struct waitlist *waitlist;
  92. /* Now also notify possibly waiting threads. */
  93. waitlist = req->waiting;
  94. while (waitlist != NULL)
  95. {
  96. struct waitlist *next = waitlist->next;
  97. if (waitlist->sigevp == NULL)
  98. {
  99. #ifdef DONT_NEED_GAI_MISC_COND
  100. GAI_MISC_NOTIFY (waitlist);
  101. #else
  102. /* Decrement the counter. */
  103. --*waitlist->counterp;
  104. pthread_cond_signal (waitlist->cond);
  105. #endif
  106. }
  107. else
  108. /* This is part of an asynchronous `getaddrinfo_a' operation. If
  109. this request is the last one, send the signal. */
  110. if (--*waitlist->counterp == 0)
  111. {
  112. __gai_notify_only (waitlist->sigevp, waitlist->caller_pid);
  113. /* This is tricky. See getaddrinfo_a.c for the reason why
  114. this works. */
  115. free ((void *) waitlist->counterp);
  116. }
  117. waitlist = next;
  118. }
  119. }