diff options
Diffstat (limited to 'resolv/gai_notify.c')
-rw-r--r-- | resolv/gai_notify.c | 53 |
1 files changed, 43 insertions, 10 deletions
diff --git a/resolv/gai_notify.c b/resolv/gai_notify.c index 987a64c0e2..c3ce0afb45 100644 --- a/resolv/gai_notify.c +++ b/resolv/gai_notify.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2001. @@ -20,15 +20,24 @@ #include <netdb.h> #include <pthread.h> #include <stdlib.h> +#include <gai_misc.h> -#include "gai_misc.h" +struct notify_func + { + void (*func) (sigval_t); + sigval_t value; + }; static void * notify_func_wrapper (void *arg) { - struct sigevent *sigev = arg; - sigev->sigev_notify_function (sigev->sigev_value); + gai_start_notify_thread (); + struct notify_func *const n = arg; + void (*func) (sigval_t) = n->func; + sigval_t value = n->value; + free (n); + (*func) (value); return NULL; } @@ -54,8 +63,26 @@ __gai_notify_only (struct sigevent *sigev, pid_t caller_pid) pattr = &attr; } - if (pthread_create (&tid, pattr, notify_func_wrapper, sigev) < 0) + /* SIGEV may be freed as soon as we return, so we cannot let the + notification thread use that pointer. Even though a sigval_t is + only one word and the same size as a void *, we cannot just pass + the value through pthread_create as the argument and have the new + thread run the user's function directly, because on some machines + the calling convention for a union like sigval_t is different from + that for a pointer type like void *. */ + struct notify_func *nf = malloc (sizeof *nf); + if (nf == NULL) result = -1; + else + { + nf->func = sigev->sigev_notify_function; + nf->value = sigev->sigev_value; + if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) + { + free (nf); + result = -1; + } + } } else if (sigev->sigev_notify == SIGEV_SIGNAL) /* We have to send a signal. */ @@ -79,15 +106,21 @@ __gai_notify (struct requestlist *req) { 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); + { +#ifdef DONT_NEED_GAI_MISC_COND + GAI_MISC_NOTIFY (waitlist); +#else + /* Decrement the counter. */ + --*waitlist->counterp; + + pthread_cond_signal (waitlist->cond); +#endif + } else /* This is part of a asynchronous `getaddrinfo_a' operation. If this request is the last one, send the signal. */ - if (*waitlist->counterp == 0) + if (--*waitlist->counterp == 0) { __gai_notify_only (waitlist->sigevp, waitlist->caller_pid); /* This is tricky. See getaddrinfo_a.c for the reason why |