Include <signal.h> in sysdeps/nptl/allocrtsig.c
[platform/upstream/glibc.git] / resolv / gai_notify.c
1 /* Copyright (C) 2001-2015 Free Software Foundation, Inc.
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
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.
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
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <netdb.h>
20 #include <pthread.h>
21 #include <stdlib.h>
22 #include <gai_misc.h>
23
24
25 struct notify_func
26   {
27     void (*func) (sigval_t);
28     sigval_t value;
29   };
30
31 static void *
32 notify_func_wrapper (void *arg)
33 {
34   gai_start_notify_thread ();
35   struct notify_func *const n = arg;
36   void (*func) (sigval_t) = n->func;
37   sigval_t value = n->value;
38   free (n);
39   (*func) (value);
40   return NULL;
41 }
42
43
44 int
45 internal_function
46 __gai_notify_only (struct sigevent *sigev, pid_t caller_pid)
47 {
48   int result = 0;
49
50   /* Send the signal to notify about finished processing of the request.  */
51   if (sigev->sigev_notify == SIGEV_THREAD)
52     {
53       /* We have to start a thread.  */
54       pthread_t tid;
55       pthread_attr_t attr, *pattr;
56
57       pattr = (pthread_attr_t *) sigev->sigev_notify_attributes;
58       if (pattr == NULL)
59         {
60           pthread_attr_init (&attr);
61           pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
62           pattr = &attr;
63         }
64
65       /* SIGEV may be freed as soon as we return, so we cannot let the
66          notification thread use that pointer.  Even though a sigval_t is
67          only one word and the same size as a void *, we cannot just pass
68          the value through pthread_create as the argument and have the new
69          thread run the user's function directly, because on some machines
70          the calling convention for a union like sigval_t is different from
71          that for a pointer type like void *.  */
72       struct notify_func *nf = malloc (sizeof *nf);
73       if (nf == NULL)
74         result = -1;
75       else
76         {
77           nf->func = sigev->sigev_notify_function;
78           nf->value = sigev->sigev_value;
79           if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0)
80             {
81               free (nf);
82               result = -1;
83             }
84         }
85     }
86   else if (sigev->sigev_notify == SIGEV_SIGNAL)
87     /* We have to send a signal.  */
88     if (__gai_sigqueue (sigev->sigev_signo, sigev->sigev_value, caller_pid)
89         < 0)
90       result = -1;
91
92   return result;
93 }
94
95
96 void
97 internal_function
98 __gai_notify (struct requestlist *req)
99 {
100   struct waitlist *waitlist;
101
102   /* Now also notify possibly waiting threads.  */
103   waitlist = req->waiting;
104   while (waitlist != NULL)
105     {
106       struct waitlist *next = waitlist->next;
107
108       if (waitlist->sigevp == NULL)
109         {
110 #ifdef DONT_NEED_GAI_MISC_COND
111           GAI_MISC_NOTIFY (waitlist);
112 #else
113           /* Decrement the counter.  */
114           --*waitlist->counterp;
115
116           pthread_cond_signal (waitlist->cond);
117 #endif
118         }
119       else
120         /* This is part of an asynchronous `getaddrinfo_a' operation.  If
121            this request is the last one, send the signal.  */
122         if (--*waitlist->counterp == 0)
123           {
124             __gai_notify_only (waitlist->sigevp, waitlist->caller_pid);
125             /* This is tricky.  See getaddrinfo_a.c for the reason why
126                this works.  */
127             free ((void *) waitlist->counterp);
128           }
129
130       waitlist = next;
131     }
132 }