]>
Commit | Line | Data |
---|---|---|
f7a9f785 | 1 | /* Copyright (C) 2001-2016 Free Software Foundation, Inc. |
2ace5721 UD |
2 | This file is part of the GNU C Library. |
3 | Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
2ace5721 UD |
9 | |
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 13 | Lesser General Public License for more details. |
2ace5721 | 14 | |
41bdb6e2 | 15 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
16 | License along with the GNU C Library; if not, see |
17 | <http://www.gnu.org/licenses/>. */ | |
2ace5721 UD |
18 | |
19 | #include <errno.h> | |
20 | #include <netdb.h> | |
21 | #include <pthread.h> | |
22 | #include <stdlib.h> | |
23 | #include <unistd.h> | |
24 | ||
f1762c0c | 25 | #include <gai_misc.h> |
2ace5721 UD |
26 | |
27 | ||
28 | /* We need this special structure to handle asynchronous I/O. */ | |
29 | struct async_waitlist | |
30 | { | |
e185d57e | 31 | unsigned int counter; |
2ace5721 UD |
32 | struct sigevent sigev; |
33 | struct waitlist list[0]; | |
34 | }; | |
35 | ||
36 | ||
37 | int | |
38 | getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) | |
39 | { | |
40 | struct sigevent defsigev; | |
41 | struct requestlist *requests[ent]; | |
42 | int cnt; | |
e185d57e | 43 | volatile unsigned int total = 0; |
2ace5721 UD |
44 | int result = 0; |
45 | ||
46 | /* Check arguments. */ | |
47 | if (mode != GAI_WAIT && mode != GAI_NOWAIT) | |
48 | { | |
49 | __set_errno (EINVAL); | |
50 | return EAI_SYSTEM; | |
51 | } | |
52 | ||
53 | if (sig == NULL) | |
54 | { | |
55 | defsigev.sigev_notify = SIGEV_NONE; | |
56 | sig = &defsigev; | |
57 | } | |
58 | ||
59 | /* Request the mutex. */ | |
60 | pthread_mutex_lock (&__gai_requests_mutex); | |
61 | ||
62 | /* Now we can enqueue all requests. Since we already acquired the | |
63 | mutex the enqueue function need not do this. */ | |
64 | for (cnt = 0; cnt < ent; ++cnt) | |
65 | if (list[cnt] != NULL) | |
66 | { | |
67 | requests[cnt] = __gai_enqueue_request (list[cnt]); | |
68 | ||
69 | if (requests[cnt] != NULL) | |
70 | /* Successfully enqueued. */ | |
71 | ++total; | |
72 | else | |
73 | /* Signal that we've seen an error. `errno' and the error code | |
74 | of the gaicb will tell more. */ | |
75 | result = EAI_SYSTEM; | |
76 | } | |
77 | else | |
78 | requests[cnt] = NULL; | |
79 | ||
80 | if (total == 0) | |
81 | { | |
82 | /* We don't have anything to do except signalling if we work | |
83 | asynchronously. */ | |
84 | ||
85 | /* Release the mutex. We do this before raising a signal since the | |
86 | signal handler might do a `siglongjmp' and then the mutex is | |
87 | locked forever. */ | |
88 | pthread_mutex_unlock (&__gai_requests_mutex); | |
89 | ||
90 | if (mode == GAI_NOWAIT) | |
91 | __gai_notify_only (sig, | |
92 | sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0); | |
93 | ||
94 | return result; | |
95 | } | |
96 | else if (mode == GAI_WAIT) | |
97 | { | |
f1762c0c | 98 | #ifndef DONT_NEED_GAI_MISC_COND |
2ace5721 | 99 | pthread_cond_t cond = PTHREAD_COND_INITIALIZER; |
f1762c0c | 100 | #endif |
2ace5721 UD |
101 | struct waitlist waitlist[ent]; |
102 | int oldstate; | |
103 | ||
104 | total = 0; | |
105 | for (cnt = 0; cnt < ent; ++cnt) | |
106 | if (requests[cnt] != NULL) | |
107 | { | |
f1762c0c | 108 | #ifndef DONT_NEED_GAI_MISC_COND |
2ace5721 | 109 | waitlist[cnt].cond = &cond; |
f1762c0c | 110 | #endif |
2ace5721 UD |
111 | waitlist[cnt].next = requests[cnt]->waiting; |
112 | waitlist[cnt].counterp = &total; | |
113 | waitlist[cnt].sigevp = NULL; | |
114 | waitlist[cnt].caller_pid = 0; /* Not needed. */ | |
115 | requests[cnt]->waiting = &waitlist[cnt]; | |
116 | ++total; | |
117 | } | |
118 | ||
119 | /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation | |
120 | points we must be careful. We added entries to the waiting lists | |
121 | which we must remove. So defer cancelation for now. */ | |
122 | pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); | |
123 | ||
124 | while (total > 0) | |
f1762c0c UD |
125 | { |
126 | #ifdef DONT_NEED_GAI_MISC_COND | |
9694fc44 UD |
127 | int not_used __attribute__ ((unused)); |
128 | GAI_MISC_WAIT (not_used, total, NULL, 1); | |
f1762c0c UD |
129 | #else |
130 | pthread_cond_wait (&cond, &__gai_requests_mutex); | |
131 | #endif | |
132 | } | |
2ace5721 UD |
133 | |
134 | /* Now it's time to restore the cancelation state. */ | |
135 | pthread_setcancelstate (oldstate, NULL); | |
136 | ||
f1762c0c | 137 | #ifndef DONT_NEED_GAI_MISC_COND |
2ace5721 UD |
138 | /* Release the conditional variable. */ |
139 | if (pthread_cond_destroy (&cond) != 0) | |
140 | /* This must never happen. */ | |
141 | abort (); | |
f1762c0c | 142 | #endif |
2ace5721 UD |
143 | } |
144 | else | |
145 | { | |
146 | struct async_waitlist *waitlist; | |
147 | ||
148 | waitlist = (struct async_waitlist *) | |
149 | malloc (sizeof (struct async_waitlist) | |
150 | + (ent * sizeof (struct waitlist))); | |
151 | ||
152 | if (waitlist == NULL) | |
153 | result = EAI_AGAIN; | |
154 | else | |
155 | { | |
156 | pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0; | |
157 | total = 0; | |
158 | ||
159 | for (cnt = 0; cnt < ent; ++cnt) | |
160 | if (requests[cnt] != NULL) | |
161 | { | |
f1762c0c | 162 | #ifndef DONT_NEED_GAI_MISC_COND |
2ace5721 | 163 | waitlist->list[cnt].cond = NULL; |
f1762c0c | 164 | #endif |
2ace5721 UD |
165 | waitlist->list[cnt].next = requests[cnt]->waiting; |
166 | waitlist->list[cnt].counterp = &waitlist->counter; | |
167 | waitlist->list[cnt].sigevp = &waitlist->sigev; | |
168 | waitlist->list[cnt].caller_pid = caller_pid; | |
169 | requests[cnt]->waiting = &waitlist->list[cnt]; | |
170 | ++total; | |
171 | } | |
172 | ||
173 | waitlist->counter = total; | |
174 | waitlist->sigev = *sig; | |
175 | } | |
176 | } | |
177 | ||
178 | /* Release the mutex. */ | |
179 | pthread_mutex_unlock (&__gai_requests_mutex); | |
180 | ||
181 | return result; | |
182 | } |