getaddrinfo_a.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  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 <errno.h>
  15. #include <netdb.h>
  16. #include <pthread.h>
  17. #include <stdlib.h>
  18. #include <unistd.h>
  19. #include <gai_misc.h>
  20. /* We need this special structure to handle asynchronous I/O. */
  21. struct async_waitlist
  22. {
  23. unsigned int counter;
  24. struct sigevent sigev;
  25. struct waitlist list[0];
  26. };
  27. int
  28. __getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig)
  29. {
  30. struct sigevent defsigev;
  31. struct requestlist *requests[ent];
  32. int cnt;
  33. volatile unsigned int total = 0;
  34. int result = 0;
  35. /* Check arguments. */
  36. if (mode != GAI_WAIT && mode != GAI_NOWAIT)
  37. {
  38. __set_errno (EINVAL);
  39. return EAI_SYSTEM;
  40. }
  41. if (sig == NULL)
  42. {
  43. defsigev.sigev_notify = SIGEV_NONE;
  44. sig = &defsigev;
  45. }
  46. /* Request the mutex. */
  47. __pthread_mutex_lock (&__gai_requests_mutex);
  48. /* Now we can enqueue all requests. Since we already acquired the
  49. mutex the enqueue function need not do this. */
  50. for (cnt = 0; cnt < ent; ++cnt)
  51. if (list[cnt] != NULL)
  52. {
  53. requests[cnt] = __gai_enqueue_request (list[cnt]);
  54. if (requests[cnt] != NULL)
  55. /* Successfully enqueued. */
  56. ++total;
  57. else
  58. /* Signal that we've seen an error. `errno' and the error code
  59. of the gaicb will tell more. */
  60. result = EAI_SYSTEM;
  61. }
  62. else
  63. requests[cnt] = NULL;
  64. if (total == 0)
  65. {
  66. /* We don't have anything to do except signalling if we work
  67. asynchronously. */
  68. /* Release the mutex. We do this before raising a signal since the
  69. signal handler might do a `siglongjmp' and then the mutex is
  70. locked forever. */
  71. __pthread_mutex_unlock (&__gai_requests_mutex);
  72. if (mode == GAI_NOWAIT)
  73. __gai_notify_only (sig,
  74. sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0);
  75. return result;
  76. }
  77. else if (mode == GAI_WAIT)
  78. {
  79. #ifndef DONT_NEED_GAI_MISC_COND
  80. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  81. #endif
  82. struct waitlist waitlist[ent];
  83. int oldstate;
  84. total = 0;
  85. for (cnt = 0; cnt < ent; ++cnt)
  86. if (requests[cnt] != NULL)
  87. {
  88. #ifndef DONT_NEED_GAI_MISC_COND
  89. waitlist[cnt].cond = &cond;
  90. #endif
  91. waitlist[cnt].next = requests[cnt]->waiting;
  92. waitlist[cnt].counterp = &total;
  93. waitlist[cnt].sigevp = NULL;
  94. waitlist[cnt].caller_pid = 0; /* Not needed. */
  95. requests[cnt]->waiting = &waitlist[cnt];
  96. ++total;
  97. }
  98. /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation
  99. points we must be careful. We added entries to the waiting lists
  100. which we must remove. So defer cancelation for now. */
  101. __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate);
  102. while (total > 0)
  103. {
  104. #ifdef DONT_NEED_GAI_MISC_COND
  105. int not_used __attribute__ ((unused));
  106. GAI_MISC_WAIT (not_used, total, NULL, 1);
  107. #else
  108. pthread_cond_wait (&cond, &__gai_requests_mutex);
  109. #endif
  110. }
  111. /* Now it's time to restore the cancelation state. */
  112. __pthread_setcancelstate (oldstate, NULL);
  113. #ifndef DONT_NEED_GAI_MISC_COND
  114. /* Release the conditional variable. */
  115. if (pthread_cond_destroy (&cond) != 0)
  116. /* This must never happen. */
  117. abort ();
  118. #endif
  119. }
  120. else
  121. {
  122. struct async_waitlist *waitlist;
  123. waitlist = (struct async_waitlist *)
  124. malloc (sizeof (struct async_waitlist)
  125. + (ent * sizeof (struct waitlist)));
  126. if (waitlist == NULL)
  127. result = EAI_AGAIN;
  128. else
  129. {
  130. pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0;
  131. total = 0;
  132. for (cnt = 0; cnt < ent; ++cnt)
  133. if (requests[cnt] != NULL)
  134. {
  135. #ifndef DONT_NEED_GAI_MISC_COND
  136. waitlist->list[cnt].cond = NULL;
  137. #endif
  138. waitlist->list[cnt].next = requests[cnt]->waiting;
  139. waitlist->list[cnt].counterp = &waitlist->counter;
  140. waitlist->list[cnt].sigevp = &waitlist->sigev;
  141. waitlist->list[cnt].caller_pid = caller_pid;
  142. requests[cnt]->waiting = &waitlist->list[cnt];
  143. ++total;
  144. }
  145. waitlist->counter = total;
  146. waitlist->sigev = *sig;
  147. }
  148. }
  149. /* Release the mutex. */
  150. __pthread_mutex_unlock (&__gai_requests_mutex);
  151. return result;
  152. }
  153. #if PTHREAD_IN_LIBC
  154. versioned_symbol (libc, __getaddrinfo_a, getaddrinfo_a, GLIBC_2_34);
  155. # if OTHER_SHLIB_COMPAT (libanl, GLIBC_2_2_3, GLIBC_2_34)
  156. compat_symbol (libanl, __getaddrinfo_a, getaddrinfo_a, GLIBC_2_2_3);
  157. # endif
  158. #else /* !PTHREAD_IN_LIBC */
  159. strong_alias (__getaddrinfo_a, getaddrinfo_a)
  160. #endif /* !PTHREAD_IN_LIBC */