/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 2001. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include /* We need this special structure to handle asynchronous I/O. */ struct async_waitlist { int counter; struct sigevent sigev; struct waitlist list[0]; }; int getaddrinfo_a (int mode, struct gaicb *list[], int ent, struct sigevent *sig) { struct sigevent defsigev; struct requestlist *requests[ent]; int cnt; volatile int total = 0; int result = 0; /* Check arguments. */ if (mode != GAI_WAIT && mode != GAI_NOWAIT) { __set_errno (EINVAL); return EAI_SYSTEM; } if (sig == NULL) { defsigev.sigev_notify = SIGEV_NONE; sig = &defsigev; } /* Request the mutex. */ pthread_mutex_lock (&__gai_requests_mutex); /* Now we can enqueue all requests. Since we already acquired the mutex the enqueue function need not do this. */ for (cnt = 0; cnt < ent; ++cnt) if (list[cnt] != NULL) { requests[cnt] = __gai_enqueue_request (list[cnt]); if (requests[cnt] != NULL) /* Successfully enqueued. */ ++total; else /* Signal that we've seen an error. `errno' and the error code of the gaicb will tell more. */ result = EAI_SYSTEM; } else requests[cnt] = NULL; if (total == 0) { /* We don't have anything to do except signalling if we work asynchronously. */ /* Release the mutex. We do this before raising a signal since the signal handler might do a `siglongjmp' and then the mutex is locked forever. */ pthread_mutex_unlock (&__gai_requests_mutex); if (mode == GAI_NOWAIT) __gai_notify_only (sig, sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0); return result; } else if (mode == GAI_WAIT) { #ifndef DONT_NEED_GAI_MISC_COND pthread_cond_t cond = PTHREAD_COND_INITIALIZER; #endif struct waitlist waitlist[ent]; int oldstate; total = 0; for (cnt = 0; cnt < ent; ++cnt) if (requests[cnt] != NULL) { #ifndef DONT_NEED_GAI_MISC_COND waitlist[cnt].cond = &cond; #endif waitlist[cnt].next = requests[cnt]->waiting; waitlist[cnt].counterp = &total; waitlist[cnt].sigevp = NULL; waitlist[cnt].caller_pid = 0; /* Not needed. */ requests[cnt]->waiting = &waitlist[cnt]; ++total; } /* Since `pthread_cond_wait'/`pthread_cond_timedwait' are cancelation points we must be careful. We added entries to the waiting lists which we must remove. So defer cancelation for now. */ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &oldstate); while (total > 0) { #ifdef DONT_NEED_GAI_MISC_COND int result; GAI_MISC_WAIT (result, total, NULL, 1); #else pthread_cond_wait (&cond, &__gai_requests_mutex); #endif } /* Now it's time to restore the cancelation state. */ pthread_setcancelstate (oldstate, NULL); #ifndef DONT_NEED_GAI_MISC_COND /* Release the conditional variable. */ if (pthread_cond_destroy (&cond) != 0) /* This must never happen. */ abort (); #endif } else { struct async_waitlist *waitlist; waitlist = (struct async_waitlist *) malloc (sizeof (struct async_waitlist) + (ent * sizeof (struct waitlist))); if (waitlist == NULL) result = EAI_AGAIN; else { pid_t caller_pid = sig->sigev_notify == SIGEV_SIGNAL ? getpid () : 0; total = 0; for (cnt = 0; cnt < ent; ++cnt) if (requests[cnt] != NULL) { #ifndef DONT_NEED_GAI_MISC_COND waitlist->list[cnt].cond = NULL; #endif waitlist->list[cnt].next = requests[cnt]->waiting; waitlist->list[cnt].counterp = &waitlist->counter; waitlist->list[cnt].sigevp = &waitlist->sigev; waitlist->list[cnt].caller_pid = caller_pid; requests[cnt]->waiting = &waitlist->list[cnt]; ++total; } waitlist->counter = total; waitlist->sigev = *sig; } } /* Release the mutex. */ pthread_mutex_unlock (&__gai_requests_mutex); return result; }