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 maximum 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 79typedef struct _xf86SigIOFunc { 80 void (*f) (int, void *); 81 int fd; 82 void *closure; 83} Xf86SigIOFunc; 84 85static Xf86SigIOFunc xf86SigIOFuncs[MAX_FUNCS]; 86static int xf86SigIOMax; 87static struct pollfd *xf86SigIOFds; 88static int xf86SigIONum; 89 90static Bool 91xf86SigIOAdd(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 106static void 107xf86SigIORemove(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 */ 122static void 123xf86SIGIO(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 150static int 151xf86IsPipe(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 160static void 161block_sigio(void) 162{ 163 sigset_t set; 164 165 sigemptyset(&set); 166 sigaddset(&set, SIGIO); 167 xthread_sigmask(SIG_BLOCK, &set, NULL); 168} 169 170static void 171release_sigio(void) 172{ 173 sigset_t set; 174 175 sigemptyset(&set); 176 sigaddset(&set, SIGIO); 177 xthread_sigmask(SIG_UNBLOCK, &set, NULL); 178} 179 180int 181xf86InstallSIGIOHandler(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 for (i = 0; i < MAX_FUNCS; i++) { 189 if (!xf86SigIOFuncs[i].f) { 190 if (xf86IsPipe(fd)) 191 return 0; 192 block_sigio(); 193#ifdef O_ASYNC 194 if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_ASYNC) == -1) { 195 xf86Msg(X_WARNING, "fcntl(%d, O_ASYNC): %s\n", 196 fd, strerror(errno)); 197 } 198 else { 199 if (fcntl(fd, F_SETOWN, getpid()) == -1) { 200 xf86Msg(X_WARNING, "fcntl(%d, F_SETOWN): %s\n", 201 fd, strerror(errno)); 202 } 203 else { 204 installed = TRUE; 205 } 206 } 207#endif 208#if defined(I_SETSIG) && defined(HAVE_ISASTREAM) 209 /* System V Streams - used on Solaris for input devices */ 210 if (!installed && isastream(fd)) { 211 if (ioctl(fd, I_SETSIG, S_INPUT | S_ERROR | S_HANGUP) == -1) { 212 xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG): %s\n", 213 fd, strerror(errno)); 214 } 215 else { 216 installed = TRUE; 217 } 218 } 219#endif 220 if (!installed) { 221 release_sigio(); 222 return 0; 223 } 224 sigemptyset(&sa.sa_mask); 225 sigaddset(&sa.sa_mask, SIGIO); 226 sa.sa_flags = SA_RESTART; 227 sa.sa_handler = xf86SIGIO; 228 sigaction(SIGIO, &sa, &osa); 229 xf86SigIOFuncs[i].fd = fd; 230 xf86SigIOFuncs[i].closure = closure; 231 xf86SigIOFuncs[i].f = f; 232 if (i >= xf86SigIOMax) 233 xf86SigIOMax = i + 1; 234 xf86SigIOAdd(fd); 235 release_sigio(); 236 return 1; 237 } 238 /* Allow overwriting of the closure and callback */ 239 else if (xf86SigIOFuncs[i].fd == fd) { 240 xf86SigIOFuncs[i].closure = closure; 241 xf86SigIOFuncs[i].f = f; 242 return 1; 243 } 244 } 245 return 0; 246} 247 248int 249xf86RemoveSIGIOHandler(int fd) 250{ 251 struct sigaction sa; 252 struct sigaction osa; 253 int i; 254 int max; 255 int ret; 256 257 max = 0; 258 ret = 0; 259 for (i = 0; i < MAX_FUNCS; i++) { 260 if (xf86SigIOFuncs[i].f) { 261 if (xf86SigIOFuncs[i].fd == fd) { 262 xf86SigIOFuncs[i].f = 0; 263 xf86SigIOFuncs[i].fd = 0; 264 xf86SigIOFuncs[i].closure = 0; 265 xf86SigIORemove(fd); 266 ret = 1; 267 } 268 else { 269 max = i + 1; 270 } 271 } 272 } 273 if (ret) { 274#ifdef O_ASYNC 275 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_ASYNC); 276#endif 277#if defined(I_SETSIG) && defined(HAVE_ISASTREAM) 278 if (isastream(fd)) { 279 if (ioctl(fd, I_SETSIG, 0) == -1) { 280 xf86Msg(X_WARNING, "fcntl(%d, I_SETSIG, 0): %s\n", 281 fd, strerror(errno)); 282 } 283 } 284#endif 285 xf86SigIOMax = max; 286 if (!max) { 287 sigemptyset(&sa.sa_mask); 288 sigaddset(&sa.sa_mask, SIGIO); 289 sa.sa_flags = 0; 290 sa.sa_handler = SIG_IGN; 291 sigaction(SIGIO, &sa, &osa); 292 } 293 } 294 return ret; 295} 296