1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <assert.h>
21: #include <errno.h>
22: #include <pthread.h>
23: #include <stdlib.h>
24: #include <sys/time.h>
25:
26: #include <gai_misc.h>
27:
28:
29:
30: #ifndef gai_create_helper_thread
31: # define gai_create_helper_thread __gai_create_helper_thread
32:
33: extern inline int
34: __gai_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
35: void *arg)
36: {
37: pthread_attr_t attr;
38:
39:
40: pthread_attr_init (&attr);
41: pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
42:
43: int ret = pthread_create (threadp, &attr, tf, arg);
44:
45: (void) pthread_attr_destroy (&attr);
46: return ret;
47: }
48: #endif
49:
50:
51:
52: static struct requestlist **pool;
53:
54:
55: static size_t pool_max_size;
56: static size_t pool_size;
57:
58:
59:
60:
61: #define ENTRIES_PER_ROW 32
62:
63:
64: #define ROWS_STEP 8
65:
66:
67: static struct requestlist *freelist;
68:
69:
70: static struct requestlist *requests;
71: static struct requestlist *requests_tail;
72:
73:
74: static int nthreads;
75:
76:
77: static int idle_thread_count;
78:
79:
80:
81:
82: static struct gaiinit optim =
83: {
84: 20,
85: 64,
86: 0,
87: 0,
88: 0,
89: 0,
90: 1,
91: 0
92: };
93:
94:
95:
96: pthread_mutex_t __gai_requests_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
97:
98:
99:
100:
101: pthread_cond_t __gai_new_request_notification = PTHREAD_COND_INITIALIZER;
102:
103:
104:
105: static struct requestlist *
106: get_elem (void)
107: {
108: struct requestlist *result;
109:
110: if (freelist == NULL)
111: {
112: struct requestlist *new_row;
113: int cnt;
114:
115: if (pool_size + 1 >= pool_max_size)
116: {
117: size_t new_max_size = pool_max_size + ROWS_STEP;
118: struct requestlist **new_tab;
119:
120: new_tab = (struct requestlist **)
121: realloc (pool, new_max_size * sizeof (struct requestlist *));
122:
123: if (new_tab == NULL)
124: return NULL;
125:
126: pool_max_size = new_max_size;
127: pool = new_tab;
128: }
129:
130:
131: cnt = pool_size == 0 ? optim.gai_num : ENTRIES_PER_ROW;
132: new_row = (struct requestlist *) calloc (cnt,
133: sizeof (struct requestlist));
134: if (new_row == NULL)
135: return NULL;
136:
137: pool[pool_size++] = new_row;
138:
139:
140: do
141: {
142: new_row->next = freelist;
143: freelist = new_row++;
144: }
145: while (--cnt > 0);
146: }
147:
148: result = freelist;
149: freelist = freelist->next;
150:
151: return result;
152: }
153:
154:
155: struct requestlist *
156: internal_function
157: __gai_find_request (const struct gaicb *gaicbp)
158: {
159: struct requestlist *runp;
160:
161: runp = requests;
162: while (runp != NULL)
163: if (runp->gaicbp == gaicbp)
164: return runp;
165: else
166: runp = runp->next;
167:
168: return NULL;
169: }
170:
171:
172: int
173: internal_function
174: __gai_remove_request (struct gaicb *gaicbp)
175: {
176: struct requestlist *runp;
177: struct requestlist *lastp;
178:
179: runp = requests;
180: lastp = NULL;
181: while (runp != NULL)
182: if (runp->gaicbp == gaicbp)
183: break;
184: else
185: {
186: lastp = runp;
187: runp = runp->next;
188: }
189:
190: if (runp == NULL)
191:
192: return -1;
193: if (runp->running != 0)
194:
195: return 1;
196:
197:
198: if (lastp == NULL)
199: requests = runp->next;
200: else
201: lastp->next = runp->next;
202: if (runp == requests_tail)
203: requests_tail = lastp;
204:
205: return 0;
206: }
207:
208:
209:
210: static void *handle_requests (void *arg);
211:
212:
213:
214:
215: struct requestlist *
216: internal_function
217: __gai_enqueue_request (struct gaicb *gaicbp)
218: {
219: struct requestlist *newp;
220: struct requestlist *lastp;
221:
222:
223: pthread_mutex_lock (&__gai_requests_mutex);
224:
225:
226: newp = get_elem ();
227: if (newp == NULL)
228: {
229: pthread_mutex_unlock (&__gai_requests_mutex);
230: __set_errno (EAGAIN);
231: return NULL;
232: }
233: newp->running = 0;
234: newp->gaicbp = gaicbp;
235: newp->waiting = NULL;
236: newp->next = NULL;
237:
238: lastp = requests_tail;
239: if (requests_tail == NULL)
240: requests = requests_tail = newp;
241: else
242: {
243: requests_tail->next = newp;
244: requests_tail = newp;
245: }
246:
247: gaicbp->__return = EAI_INPROGRESS;
248:
249:
250: if (nthreads < optim.gai_threads && idle_thread_count == 0)
251: {
252: pthread_t thid;
253:
254: newp->running = 1;
255:
256:
257: if (gai_create_helper_thread (&thid, handle_requests, newp) == 0)
258:
259:
260: ++nthreads;
261: else
262: {
263: if (nthreads == 0)
264: {
265:
266:
267:
268: assert (lastp->next == newp);
269: lastp->next = NULL;
270: requests_tail = lastp;
271:
272: newp->next = freelist;
273: freelist = newp;
274:
275: newp = NULL;
276: }
277: else
278:
279: newp->running = 0;
280: }
281: }
282:
283:
284: if (newp != NULL)
285: {
286:
287:
288: if (idle_thread_count > 0)
289: pthread_cond_signal (&__gai_new_request_notification);
290: }
291:
292:
293: pthread_mutex_unlock (&__gai_requests_mutex);
294:
295: return newp;
296: }
297:
298:
299: static void *
300: __attribute__ ((noreturn))
301: handle_requests (void *arg)
302: {
303: struct requestlist *runp = (struct requestlist *) arg;
304:
305: do
306: {
307:
308:
309:
310:
311:
312: if (runp == NULL)
313: pthread_mutex_lock (&__gai_requests_mutex);
314: else
315: {
316:
317: struct gaicb *req = runp->gaicbp;
318: struct requestlist *srchp;
319: struct requestlist *lastp;
320:
321: req->__return = getaddrinfo (req->ar_name, req->ar_service,
322: req->ar_request, &req->ar_result);
323:
324:
325: pthread_mutex_lock (&__gai_requests_mutex);
326:
327:
328:
329: __gai_notify (runp);
330:
331:
332: lastp = NULL;
333: srchp = requests;
334: while (srchp != runp)
335: {
336: lastp = srchp;
337: srchp = srchp->next;
338: }
339: assert (runp->running == 1);
340:
341: if (requests_tail == runp)
342: requests_tail = lastp;
343: if (lastp == NULL)
344: requests = requests->next;
345: else
346: lastp->next = runp->next;
347:
348:
349: runp->next = freelist;
350: freelist = runp;
351: }
352:
353: runp = requests;
354: while (runp != NULL && runp->running != 0)
355: runp = runp->next;
356:
357:
358:
359: if (runp == NULL && optim.gai_idle_time >= 0)
360: {
361: struct timeval now;
362: struct timespec wakeup_time;
363:
364: ++idle_thread_count;
365: gettimeofday (&now, NULL);
366: wakeup_time.tv_sec = now.tv_sec + optim.gai_idle_time;
367: wakeup_time.tv_nsec = now.tv_usec * 1000;
368: if (wakeup_time.tv_nsec > 1000000000)
369: {
370: wakeup_time.tv_nsec -= 1000000000;
371: ++wakeup_time.tv_sec;
372: }
373: pthread_cond_timedwait (&__gai_new_request_notification,
374: &__gai_requests_mutex, &wakeup_time);
375: --idle_thread_count;
376: runp = requests;
377: while (runp != NULL && runp->running != 0)
378: runp = runp->next;
379: }
380:
381: if (runp == NULL)
382: --nthreads;
383: else
384: {
385:
386: assert (runp->running == 0);
387: runp->running = 1;
388:
389:
390:
391:
392: if (requests != NULL)
393: {
394:
395:
396:
397:
398: if (idle_thread_count > 0)
399: pthread_cond_signal (&__gai_new_request_notification);
400: else if (nthreads < optim.gai_threads)
401: {
402: pthread_t thid;
403: pthread_attr_t attr;
404:
405:
406: pthread_attr_init (&attr);
407: pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
408:
409:
410:
411:
412: if (pthread_create (&thid, &attr, handle_requests, NULL)
413: == 0)
414: ++nthreads;
415: }
416: }
417: }
418:
419:
420: pthread_mutex_unlock (&__gai_requests_mutex);
421: }
422: while (runp != NULL);
423:
424: pthread_exit (NULL);
425: }
426:
427:
428:
429: libc_freeres_fn (free_res)
430: {
431: size_t row;
432:
433: for (row = 0; row < pool_max_size; ++row)
434: free (pool[row]);
435:
436: free (pool);
437: }