]>
Commit | Line | Data |
---|---|---|
d71b808a | 1 | /* Notify initiator of AIO request. |
d4697bc9 | 2 | Copyright (C) 1997-2014 Free Software Foundation, Inc. |
d71b808a UD |
3 | This file is part of the GNU C Library. |
4 | Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. | |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
d71b808a UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
d71b808a | 15 | |
41bdb6e2 | 16 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
17 | License along with the GNU C Library; if not, see |
18 | <http://www.gnu.org/licenses/>. */ | |
d71b808a | 19 | |
4959e310 | 20 | #include <errno.h> |
d71b808a UD |
21 | #include <pthread.h> |
22 | #include <stdlib.h> | |
3de5235f | 23 | #include <unistd.h> |
ffdd5e50 | 24 | #include <aio_misc.h> |
d71b808a | 25 | |
ffdd5e50 UD |
26 | #ifndef aio_start_notify_thread |
27 | # define aio_start_notify_thread() do { } while (0) | |
28 | #endif | |
ed2d7a57 | 29 | |
57b4cb25 RM |
30 | struct notify_func |
31 | { | |
32 | void (*func) (sigval_t); | |
33 | sigval_t value; | |
34 | }; | |
35 | ||
ed2d7a57 UD |
36 | static void * |
37 | notify_func_wrapper (void *arg) | |
38 | { | |
ffdd5e50 | 39 | aio_start_notify_thread (); |
57b4cb25 RM |
40 | struct notify_func *const n = arg; |
41 | void (*func) (sigval_t) = n->func; | |
42 | sigval_t value = n->value; | |
43 | free (n); | |
44 | (*func) (value); | |
ed2d7a57 UD |
45 | return NULL; |
46 | } | |
47 | ||
48 | ||
d71b808a | 49 | int |
00995ca9 | 50 | internal_function |
b61c8aba | 51 | #ifdef BROKEN_THREAD_SIGNALS |
3a9eb648 | 52 | __aio_notify_only (struct sigevent *sigev, pid_t caller_pid) |
b61c8aba UD |
53 | #else |
54 | __aio_notify_only (struct sigevent *sigev) | |
55 | #endif | |
d71b808a UD |
56 | { |
57 | int result = 0; | |
58 | ||
59 | /* Send the signal to notify about finished processing of the request. */ | |
b61c8aba | 60 | if (__builtin_expect (sigev->sigev_notify == SIGEV_THREAD, 0)) |
d71b808a UD |
61 | { |
62 | /* We have to start a thread. */ | |
63 | pthread_t tid; | |
64 | pthread_attr_t attr, *pattr; | |
65 | ||
66 | pattr = (pthread_attr_t *) sigev->sigev_notify_attributes; | |
67 | if (pattr == NULL) | |
68 | { | |
69 | pthread_attr_init (&attr); | |
70 | pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); | |
71 | pattr = &attr; | |
72 | } | |
73 | ||
57b4cb25 RM |
74 | /* SIGEV may be freed as soon as we return, so we cannot let the |
75 | notification thread use that pointer. Even though a sigval_t is | |
76 | only one word and the same size as a void *, we cannot just pass | |
77 | the value through pthread_create as the argument and have the new | |
78 | thread run the user's function directly, because on some machines | |
79 | the calling convention for a union like sigval_t is different from | |
80 | that for a pointer type like void *. */ | |
81 | struct notify_func *nf = malloc (sizeof *nf); | |
82 | if (nf == NULL) | |
d71b808a | 83 | result = -1; |
57b4cb25 RM |
84 | else |
85 | { | |
86 | nf->func = sigev->sigev_notify_function; | |
87 | nf->value = sigev->sigev_value; | |
88 | if (pthread_create (&tid, pattr, notify_func_wrapper, nf) < 0) | |
89 | { | |
90 | free (nf); | |
91 | result = -1; | |
92 | } | |
93 | } | |
d71b808a UD |
94 | } |
95 | else if (sigev->sigev_notify == SIGEV_SIGNAL) | |
221dc560 RM |
96 | { |
97 | /* We have to send a signal. */ | |
8bece752 | 98 | #if _POSIX_REALTIME_SIGNALS > 0 |
221dc560 RM |
99 | /* Note that the standard gives us the option of using a plain |
100 | non-queuing signal here when SA_SIGINFO is not set for the signal. */ | |
b61c8aba | 101 | # ifdef BROKEN_THREAD_SIGNALS |
221dc560 RM |
102 | if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, caller_pid) |
103 | < 0) | |
104 | result = -1; | |
b61c8aba UD |
105 | # else |
106 | if (__aio_sigqueue (sigev->sigev_signo, sigev->sigev_value, getpid ()) | |
107 | < 0) | |
108 | result = -1; | |
109 | # endif | |
221dc560 RM |
110 | #else |
111 | /* There are no queued signals on this system at all. */ | |
112 | result = raise (sigev->sigev_signo); | |
113 | #endif | |
114 | } | |
d71b808a UD |
115 | |
116 | return result; | |
117 | } | |
118 | ||
119 | ||
120 | void | |
00995ca9 | 121 | internal_function |
d71b808a UD |
122 | __aio_notify (struct requestlist *req) |
123 | { | |
124 | struct waitlist *waitlist; | |
125 | struct aiocb *aiocbp = &req->aiocbp->aiocb; | |
126 | ||
b61c8aba | 127 | #ifdef BROKEN_THREAD_SIGNALS |
3a9eb648 | 128 | if (__aio_notify_only (&aiocbp->aio_sigevent, req->caller_pid) != 0) |
b61c8aba UD |
129 | #else |
130 | if (__aio_notify_only (&aiocbp->aio_sigevent) != 0) | |
131 | #endif | |
d71b808a UD |
132 | { |
133 | /* XXX What shall we do if already an error is set by | |
134 | read/write/fsync? */ | |
135 | aiocbp->__error_code = errno; | |
136 | aiocbp->__return_value = -1; | |
137 | } | |
138 | ||
139 | /* Now also notify possibly waiting threads. */ | |
140 | waitlist = req->waiting; | |
141 | while (waitlist != NULL) | |
142 | { | |
143 | struct waitlist *next = waitlist->next; | |
144 | ||
a334319f | 145 | if (waitlist->sigevp == NULL) |
9759bbf1 UD |
146 | { |
147 | if (waitlist->result != NULL && aiocbp->__return_value == -1) | |
148 | *waitlist->result = -1; | |
149 | ||
679d83ba UD |
150 | #ifdef DONT_NEED_AIO_MISC_COND |
151 | AIO_MISC_NOTIFY (waitlist); | |
152 | #else | |
153 | /* Decrement the counter. */ | |
154 | --*waitlist->counterp; | |
155 | ||
9759bbf1 | 156 | pthread_cond_signal (waitlist->cond); |
679d83ba | 157 | #endif |
9759bbf1 | 158 | } |
d71b808a | 159 | else |
c0c3f78a | 160 | /* This is part of an asynchronous `lio_listio' operation. If |
d71b808a | 161 | this request is the last one, send the signal. */ |
679d83ba | 162 | if (--*waitlist->counterp == 0) |
d71b808a | 163 | { |
b61c8aba | 164 | #ifdef BROKEN_THREAD_SIGNALS |
3a9eb648 | 165 | __aio_notify_only (waitlist->sigevp, waitlist->caller_pid); |
b61c8aba UD |
166 | #else |
167 | __aio_notify_only (waitlist->sigevp); | |
168 | #endif | |
d71b808a UD |
169 | /* This is tricky. See lio_listio.c for the reason why |
170 | this works. */ | |
171 | free ((void *) waitlist->counterp); | |
172 | } | |
173 | ||
174 | waitlist = next; | |
175 | } | |
176 | } |