void internal_function __gai_notify (struct requestlist *req) { struct waitlist *waitlist; /* Now also notify possibly waiting threads. */ waitlist = req->waiting; while (waitlist != NULL) { struct waitlist *next = waitlist->next; /* Decrement the counter. This is used in both cases. */ --*waitlist->counterp; if (waitlist->sigevp == NULL) pthread_cond_signal (waitlist->cond); else /* This is part of a asynchronous `getaddrinfo_a' operation. If this request is the last one, send the signal. */ if (*waitlist->counterp == 0) { __gai_notify_only (waitlist->sigevp, waitlist->caller_pid); /* This is tricky. See getaddrinfo_a.c for the reason why this works. */ free ((void *) waitlist->counterp); } waitlist = next; } }
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; }