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 <xserver_poll.h>
61 #include "xf86.h"
62 #include "xf86Priv.h"
63 #include "xf86_OSlib.h"
64 #include "inputstr.h"
65
66 #ifdef HAVE_STROPTS_H
67 #include <stropts.h>
68 #endif
69
70 #ifdef MAXDEVICES
71 /* MAXDEVICES represents the maximimum number of input devices usable
72 * at the same time plus one entry for DRM support.
73 */
74 #define MAX_FUNCS (MAXDEVICES + 1)
75 #else
76 #define MAX_FUNCS 16
77 #endif
78
79 typedef struct _xf86SigIOFunc {
80 void (*f) (int, void *);
81 int fd;
82 void *closure;
83 } Xf86SigIOFunc;
84
85 static Xf86SigIOFunc xf86SigIOFuncs[MAX_FUNCS];
86 static int xf86SigIOMax;
87 static struct pollfd *xf86SigIOFds;
88 static int xf86SigIONum;
89
90 static Bool
xf86SigIOAdd(int fd)91 xf86SigIOAdd(int fd)
92 {
93 struct pollfd *n;
94
95 n = realloc(xf86SigIOFds, (xf86SigIONum + 1) * sizeof (struct pollfd));
96 if (!n)
97 return FALSE;
98
99 n[xf86SigIONum].fd = fd;
100 n[xf86SigIONum].events = POLLIN;
101 xf86SigIONum++;
102 xf86SigIOFds = n;
103 return TRUE;
104 }
105
106 static void
xf86SigIORemove(int fd)107 xf86SigIORemove(int fd)
108 {
109 int i;
110 for (i = 0; i < xf86SigIONum; i++)
111 if (xf86SigIOFds[i].fd == fd) {
112 memmove(&xf86SigIOFds[i], &xf86SigIOFds[i+1], (xf86SigIONum - i - 1) * sizeof (struct pollfd));
113 xf86SigIONum--;
114 break;
115 }
116 }
117
118 /*
119 * SIGIO gives no way of discovering which fd signalled, select
120 * to discover
121 */
122 static void
xf86SIGIO(int sig)123 xf86SIGIO(int sig)
124 {
125 int i, f;
126 int save_errno = errno; /* do not clobber the global errno */
127 int r;
128
129 inSignalContext = TRUE;
130
131 SYSCALL(r = xserver_poll(xf86SigIOFds, xf86SigIONum, 0));
132 for (f = 0; r > 0 && f < xf86SigIONum; f++) {
133 if (xf86SigIOFds[f].revents & POLLIN) {
134 for (i = 0; i < xf86SigIOMax; i++)
135 if (xf86SigIOFuncs[i].f && xf86SigIOFuncs[i].fd == xf86SigIOFds[f].fd)
136 (*xf86SigIOFuncs[i].f) (xf86SigIOFuncs[i].fd,
137 xf86SigIOFuncs[i].closure);
138 r--;
139 }
140 }
141 if (r > 0) {
142 xf86Msg(X_ERROR, "SIGIO %d descriptors not handled\n", r);
143 }
144 /* restore global errno */
145 errno = save_errno;
146
147 inSignalContext = FALSE;
148 }
149
150 static int
xf86IsPipe(int fd)151 xf86IsPipe(int fd)
152 {
153 struct stat buf;
154
155 if (fstat(fd, &buf) < 0)
156 return 0;
157 return S_ISFIFO(buf.st_mode);
158 }
159
160 static void
block_sigio(void)161 block_sigio(void)
162 {
163 sigset_t set;
164
165 sigemptyset(&set);
166 sigaddset(&set, SIGIO);
167 xthread_sigmask(SIG_BLOCK, &set, NULL);
168 }
169
170 static void
release_sigio(void)171 release_sigio(void)
172 {
173 sigset_t set;
174
175 sigemptyset(&set);
176 sigaddset(&set, SIGIO);
177 xthread_sigmask(SIG_UNBLOCK, &set, NULL);
178 }
179
180 int
xf86InstallSIGIOHandler(int fd,void (* f)(int,void *),void * closure)181 xf86InstallSIGIOHandler(int fd, void (*f) (int, void *), void *closure)
182 {
183 struct sigaction sa;
184 struct sigaction osa;
185 int i;
186 int installed = FALSE;
187
188 if (!xf86Info.useSIGIO)
189 return 0;
190
191 for (i = 0; i < MAX_FUNCS; i++) {
192 if (!xf86SigIOFuncs[i].f) {
193 if (xf86IsPipe(fd))
194 return 0;
195 block_sigio();
196 #ifdef O_ASYNC
197 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC) == -1) {
198 xf86Msg(X_WARNING, "fcntl(%d, O_ASYNC): %s\n",
199 fd, strerror(errno));
200 }
201 else {
202 if (fcntl(fd, F_SETOWN, getpid()) == -1) {
203 xf86Msg(X_WARNING, "fcntl(%d, F_SETOWN): %s\n",
204 fd, strerror(errno));
205 }
206 else {
207 installed = TRUE;
208 }
209 }
210 #endif
211 #if defined(I_SETSIG) && defined(HAVE_ISASTREAM)
212 /* System V Streams - used on Solaris for input devices */
213 if (!installed && isastream(fd)) {
214 if (ioctl(fd, I_SETSIG, S_INPUT | S_ERROR | S_HANGUP) == -1) {
215 xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG): %s\n",
216 fd, strerror(errno));
217 }
218 else {
219 installed = TRUE;
220 }
221 }
222 #endif
223 if (!installed) {
224 release_sigio();
225 return 0;
226 }
227 sigemptyset(&sa.sa_mask);
228 sigaddset(&sa.sa_mask, SIGIO);
229 sa.sa_flags = SA_RESTART;
230 sa.sa_handler = xf86SIGIO;
231 sigaction(SIGIO, &sa, &osa);
232 xf86SigIOFuncs[i].fd = fd;
233 xf86SigIOFuncs[i].closure = closure;
234 xf86SigIOFuncs[i].f = f;
235 if (i >= xf86SigIOMax)
236 xf86SigIOMax = i + 1;
237 xf86SigIOAdd(fd);
238 release_sigio();
239 return 1;
240 }
241 /* Allow overwriting of the closure and callback */
242 else if (xf86SigIOFuncs[i].fd == fd) {
243 xf86SigIOFuncs[i].closure = closure;
244 xf86SigIOFuncs[i].f = f;
245 return 1;
246 }
247 }
248 return 0;
249 }
250
251 int
xf86RemoveSIGIOHandler(int fd)252 xf86RemoveSIGIOHandler(int fd)
253 {
254 struct sigaction sa;
255 struct sigaction osa;
256 int i;
257 int max;
258 int ret;
259
260 if (!xf86Info.useSIGIO)
261 return 0;
262
263 max = 0;
264 ret = 0;
265 for (i = 0; i < MAX_FUNCS; i++) {
266 if (xf86SigIOFuncs[i].f) {
267 if (xf86SigIOFuncs[i].fd == fd) {
268 xf86SigIOFuncs[i].f = 0;
269 xf86SigIOFuncs[i].fd = 0;
270 xf86SigIOFuncs[i].closure = 0;
271 xf86SigIORemove(fd);
272 ret = 1;
273 }
274 else {
275 max = i + 1;
276 }
277 }
278 }
279 if (ret) {
280 #ifdef O_ASYNC
281 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC);
282 #endif
283 #if defined(I_SETSIG) && defined(HAVE_ISASTREAM)
284 if (isastream(fd)) {
285 if (ioctl(fd, I_SETSIG, 0) == -1) {
286 xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG, 0): %s\n",
287 fd, strerror(errno));
288 }
289 }
290 #endif
291 xf86SigIOMax = max;
292 if (!max) {
293 sigemptyset(&sa.sa_mask);
294 sigaddset(&sa.sa_mask, SIGIO);
295 sa.sa_flags = 0;
296 sa.sa_handler = SIG_IGN;
297 sigaction(SIGIO, &sa, &osa);
298 }
299 }
300 return ret;
301 }
302