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