Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* sigio.c -- Support for SIGIO handler installation and removal |
2 | * Created: Thu Jun 3 15:39:18 1999 by faith@precisioninsight.com | |
3 | * | |
4 | * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. | |
5 | * All Rights Reserved. | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a | |
8 | * copy of this software and associated documentation files (the "Software"), | |
9 | * to deal in the Software without restriction, including without limitation | |
10 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
11 | * and/or sell copies of the Software, and to permit persons to whom the | |
12 | * Software is furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice (including the next | |
15 | * paragraph) shall be included in all copies or substantial portions of the | |
16 | * Software. | |
17 | * | |
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
21 | * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
22 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
23 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
24 | * DEALINGS IN THE SOFTWARE. | |
25 | * | |
26 | * Authors: Rickard E. (Rik) Faith <faith@valinux.com> | |
27 | */ | |
28 | /* | |
29 | * Copyright (c) 2002 by The XFree86 Project, Inc. | |
30 | * | |
31 | * Permission is hereby granted, free of charge, to any person obtaining a | |
32 | * copy of this software and associated documentation files (the "Software"), | |
33 | * to deal in the Software without restriction, including without limitation | |
34 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
35 | * and/or sell copies of the Software, and to permit persons to whom the | |
36 | * Software is furnished to do so, subject to the following conditions: | |
37 | * | |
38 | * The above copyright notice and this permission notice shall be included in | |
39 | * all copies or substantial portions of the Software. | |
40 | * | |
41 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
42 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
43 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
44 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
45 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
46 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
47 | * OTHER DEALINGS IN THE SOFTWARE. | |
48 | * | |
49 | * Except as contained in this notice, the name of the copyright holder(s) | |
50 | * and author(s) shall not be used in advertising or otherwise to promote | |
51 | * the sale, use or other dealings in this Software without prior written | |
52 | * authorization from the copyright holder(s) and author(s). | |
53 | */ | |
54 | ||
55 | #ifdef HAVE_XORG_CONFIG_H | |
56 | #include <xorg-config.h> | |
57 | #endif | |
58 | ||
59 | #include <X11/X.h> | |
60 | #include "xf86.h" | |
61 | #include "xf86Priv.h" | |
62 | #include "xf86_OSlib.h" | |
63 | #include "inputstr.h" | |
64 | ||
65 | #ifdef HAVE_STROPTS_H | |
66 | #include <stropts.h> | |
67 | #endif | |
68 | ||
69 | #ifdef MAXDEVICES | |
70 | /* MAXDEVICES represents the maximimum number of input devices usable | |
71 | * at the same time plus one entry for DRM support. | |
72 | */ | |
73 | #define MAX_FUNCS (MAXDEVICES + 1) | |
74 | #else | |
75 | #define MAX_FUNCS 16 | |
76 | #endif | |
77 | ||
78 | typedef struct _xf86SigIOFunc { | |
79 | void (*f) (int, void *); | |
80 | int fd; | |
81 | void *closure; | |
82 | } Xf86SigIOFunc; | |
83 | ||
84 | static Xf86SigIOFunc xf86SigIOFuncs[MAX_FUNCS]; | |
85 | static int xf86SigIOMax; | |
86 | static int xf86SigIOMaxFd; | |
87 | static fd_set xf86SigIOMask; | |
88 | ||
89 | /* | |
90 | * SIGIO gives no way of discovering which fd signalled, select | |
91 | * to discover | |
92 | */ | |
93 | static void | |
94 | xf86SIGIO(int sig) | |
95 | { | |
96 | int i; | |
97 | fd_set ready; | |
98 | struct timeval to; | |
99 | int save_errno = errno; /* do not clobber the global errno */ | |
100 | int r; | |
101 | ||
102 | inSignalContext = TRUE; | |
103 | ||
104 | ready = xf86SigIOMask; | |
105 | to.tv_sec = 0; | |
106 | to.tv_usec = 0; | |
107 | SYSCALL(r = select(xf86SigIOMaxFd, &ready, 0, 0, &to)); | |
108 | for (i = 0; r > 0 && i < xf86SigIOMax; i++) | |
109 | if (xf86SigIOFuncs[i].f && FD_ISSET(xf86SigIOFuncs[i].fd, &ready)) { | |
110 | (*xf86SigIOFuncs[i].f) (xf86SigIOFuncs[i].fd, | |
111 | xf86SigIOFuncs[i].closure); | |
112 | r--; | |
113 | } | |
114 | if (r > 0) { | |
115 | xf86Msg(X_ERROR, "SIGIO %d descriptors not handled\n", r); | |
116 | } | |
117 | /* restore global errno */ | |
118 | errno = save_errno; | |
119 | ||
120 | inSignalContext = FALSE; | |
121 | } | |
122 | ||
123 | static int | |
124 | xf86IsPipe(int fd) | |
125 | { | |
126 | struct stat buf; | |
127 | ||
128 | if (fstat(fd, &buf) < 0) | |
129 | return 0; | |
130 | return S_ISFIFO(buf.st_mode); | |
131 | } | |
132 | ||
133 | int | |
134 | xf86InstallSIGIOHandler(int fd, void (*f) (int, void *), void *closure) | |
135 | { | |
136 | struct sigaction sa; | |
137 | struct sigaction osa; | |
138 | int i; | |
139 | int installed = FALSE; | |
140 | ||
141 | if (!xf86Info.useSIGIO) | |
142 | return 0; | |
143 | ||
144 | for (i = 0; i < MAX_FUNCS; i++) { | |
145 | if (!xf86SigIOFuncs[i].f) { | |
146 | if (xf86IsPipe(fd)) | |
147 | return 0; | |
148 | OsBlockSIGIO(); | |
149 | #ifdef O_ASYNC | |
150 | if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC) == -1) { | |
151 | xf86Msg(X_WARNING, "fcntl(%d, O_ASYNC): %s\n", | |
152 | fd, strerror(errno)); | |
153 | } | |
154 | else { | |
155 | if (fcntl(fd, F_SETOWN, getpid()) == -1) { | |
156 | xf86Msg(X_WARNING, "fcntl(%d, F_SETOWN): %s\n", | |
157 | fd, strerror(errno)); | |
158 | } | |
159 | else { | |
160 | installed = TRUE; | |
161 | } | |
162 | } | |
163 | #endif | |
164 | #ifdef I_SETSIG /* System V Streams - used on Solaris for input devices */ | |
165 | if (!installed && isastream(fd)) { | |
166 | if (ioctl(fd, I_SETSIG, S_INPUT | S_ERROR | S_HANGUP) == -1) { | |
167 | xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG): %s\n", | |
168 | fd, strerror(errno)); | |
169 | } | |
170 | else { | |
171 | installed = TRUE; | |
172 | } | |
173 | } | |
174 | #endif | |
175 | if (!installed) { | |
176 | OsReleaseSIGIO(); | |
177 | return 0; | |
178 | } | |
179 | sigemptyset(&sa.sa_mask); | |
180 | sigaddset(&sa.sa_mask, SIGIO); | |
181 | sa.sa_flags = 0; | |
182 | sa.sa_handler = xf86SIGIO; | |
183 | sigaction(SIGIO, &sa, &osa); | |
184 | xf86SigIOFuncs[i].fd = fd; | |
185 | xf86SigIOFuncs[i].closure = closure; | |
186 | xf86SigIOFuncs[i].f = f; | |
187 | if (i >= xf86SigIOMax) | |
188 | xf86SigIOMax = i + 1; | |
189 | if (fd >= xf86SigIOMaxFd) | |
190 | xf86SigIOMaxFd = fd + 1; | |
191 | FD_SET(fd, &xf86SigIOMask); | |
192 | OsReleaseSIGIO(); | |
193 | return 1; | |
194 | } | |
195 | /* Allow overwriting of the closure and callback */ | |
196 | else if (xf86SigIOFuncs[i].fd == fd) { | |
197 | xf86SigIOFuncs[i].closure = closure; | |
198 | xf86SigIOFuncs[i].f = f; | |
199 | return 1; | |
200 | } | |
201 | } | |
202 | return 0; | |
203 | } | |
204 | ||
205 | int | |
206 | xf86RemoveSIGIOHandler(int fd) | |
207 | { | |
208 | struct sigaction sa; | |
209 | struct sigaction osa; | |
210 | int i; | |
211 | int max; | |
212 | int maxfd; | |
213 | int ret; | |
214 | ||
215 | if (!xf86Info.useSIGIO) | |
216 | return 0; | |
217 | ||
218 | max = 0; | |
219 | maxfd = -1; | |
220 | ret = 0; | |
221 | for (i = 0; i < MAX_FUNCS; i++) { | |
222 | if (xf86SigIOFuncs[i].f) { | |
223 | if (xf86SigIOFuncs[i].fd == fd) { | |
224 | xf86SigIOFuncs[i].f = 0; | |
225 | xf86SigIOFuncs[i].fd = 0; | |
226 | xf86SigIOFuncs[i].closure = 0; | |
227 | FD_CLR(fd, &xf86SigIOMask); | |
228 | ret = 1; | |
229 | } | |
230 | else { | |
231 | max = i + 1; | |
232 | if (xf86SigIOFuncs[i].fd >= maxfd) | |
233 | maxfd = xf86SigIOFuncs[i].fd + 1; | |
234 | } | |
235 | } | |
236 | } | |
237 | if (ret) { | |
238 | #ifdef O_ASYNC | |
239 | fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC); | |
240 | #endif | |
241 | #ifdef I_SETSIG | |
242 | if (isastream(fd)) { | |
243 | if (ioctl(fd, I_SETSIG, 0) == -1) { | |
244 | xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG, 0): %s\n", | |
245 | fd, strerror(errno)); | |
246 | } | |
247 | } | |
248 | #endif | |
249 | xf86SigIOMax = max; | |
250 | xf86SigIOMaxFd = maxfd; | |
251 | if (!max) { | |
252 | sigemptyset(&sa.sa_mask); | |
253 | sigaddset(&sa.sa_mask, SIGIO); | |
254 | sa.sa_flags = 0; | |
255 | sa.sa_handler = SIG_IGN; | |
256 | sigaction(SIGIO, &sa, &osa); | |
257 | } | |
258 | } | |
259 | return ret; | |
260 | } | |
261 | ||
262 | int | |
263 | xf86BlockSIGIO(void) | |
264 | { | |
265 | return OsBlockSIGIO(); | |
266 | } | |
267 | ||
268 | void | |
269 | xf86UnblockSIGIO(int wasset) | |
270 | { | |
271 | OsReleaseSIGIO(); | |
272 | } | |
273 | ||
274 | void | |
275 | xf86AssertBlockedSIGIO(char *where) | |
276 | { | |
277 | sigset_t set, old; | |
278 | ||
279 | sigemptyset(&set); | |
280 | sigprocmask(SIG_BLOCK, &set, &old); | |
281 | if (!sigismember(&old, SIGIO)) | |
282 | xf86Msg(X_ERROR, "SIGIO not blocked at %s\n", where); | |
283 | } | |
284 | ||
285 | /* XXX This is a quick hack for the benefit of xf86SetSilkenMouse() */ | |
286 | ||
287 | int | |
288 | xf86SIGIOSupported(void) | |
289 | { | |
290 | return 1; | |
291 | } |