xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/os-support/shared/sigio.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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