1/* 2 * Copyright 2002-2003 Red Hat Inc., Durham, North Carolina. 3 * 4 * All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation on the rights to use, copy, modify, merge, 10 * publish, distribute, sublicense, and/or sell copies of the Software, 11 * and to permit persons to whom the Software is furnished to do so, 12 * subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial 16 * portions of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 * NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS 22 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* 29 * Authors: 30 * Rickard E. (Rik) Faith <faith@redhat.com> 31 * 32 */ 33 34/** \file 35 * 36 * Provides an interface for handling SIGIO signals for input devices. */ 37 38#ifdef HAVE_DMX_CONFIG_H 39#include <dmx-config.h> 40#endif 41 42#include "inputstr.h" 43#include "dmxinputinit.h" 44#include "dmxsigio.h" 45#include "dmxevents.h" 46#include <signal.h> 47#include <unistd.h> 48#include <fcntl.h> 49 50static int dmxFdCount = 0; 51static Bool dmxInputEnabled = TRUE; 52 53/* Define equivalents for non-POSIX systems (e.g., SGI IRIX, Solaris) */ 54#ifndef O_ASYNC 55# ifdef FASYNC 56# define O_ASYNC FASYNC 57# else 58# define O_ASYNC 0 59# endif 60#endif 61#ifndef O_NONBLOCK 62#define O_NONBLOCK FNONBLK 63#endif 64 65static void dmxSigioHandler(int sig) 66{ 67 int i, j; 68 DMXInputInfo *dmxInput; 69 70 for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) { 71 if (dmxInput->sigioState == DMX_ACTIVESIGIO) { 72 for (j = 0; j < dmxInput->numDevs; j++) { 73 DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j]; 74 if (dmxLocal->collect_events) { 75 dmxLocal->collect_events(&dmxLocal->pDevice->public, 76 dmxMotion, 77 dmxEnqueue, 78 dmxCheckSpecialKeys, 79 DMX_NO_BLOCK); 80 } 81 } 82 } 83 } 84} 85 86/** Block SIGIO handling. */ 87void dmxSigioBlock(void) 88{ 89 sigset_t s; 90 91 sigemptyset(&s); 92 sigaddset(&s, SIGIO); 93 sigprocmask(SIG_BLOCK, &s, 0); 94} 95 96/** Unblock SIGIO handling. */ 97void dmxSigioUnblock(void) 98{ 99 sigset_t s; 100 101 sigemptyset(&s); 102 sigaddset(&s, SIGIO); 103 sigprocmask(SIG_UNBLOCK, &s, 0); 104} 105 106static void dmxSigioHook(void) 107{ 108 struct sigaction a; 109 sigset_t s; 110 111 memset(&a, 0, sizeof(a)); 112 a.sa_handler = dmxSigioHandler; 113 sigemptyset(&a.sa_mask); 114 sigaddset(&a.sa_mask, SIGIO); 115 sigaddset(&a.sa_mask, SIGALRM); 116 sigaddset(&a.sa_mask, SIGVTALRM); 117 sigaction(SIGIO, &a, 0); 118 119 sigemptyset(&s); 120 sigprocmask(SIG_SETMASK, &s, 0); 121} 122 123static void dmxSigioUnhook(void) 124{ 125 struct sigaction a; 126 127 memset (&a, 0, sizeof(a)); 128 a.sa_handler = SIG_IGN; 129 sigemptyset(&a.sa_mask); 130 sigaction(SIGIO, &a, 0); 131} 132 133static void dmxSigioAdd(DMXInputInfo *dmxInput) 134{ 135 int flags; 136 int i; 137 138 switch (dmxInput->sigioState) { 139 case DMX_NOSIGIO: return; 140 case DMX_USESIGIO: dmxInput->sigioState = DMX_ACTIVESIGIO; break; 141 case DMX_ACTIVESIGIO: return; 142 } 143 144 for (i = 0; i < dmxInput->sigioFdCount; i++) { 145 if (!dmxInput->sigioAdded[i]) { 146 int fd = dmxInput->sigioFd[i]; 147 148 fcntl(fd, F_SETOWN, getpid()); 149 flags = fcntl(fd, F_GETFL); 150 flags |= O_ASYNC|O_NONBLOCK; 151 fcntl(fd, F_SETFL, flags); 152 153 AddEnabledDevice(fd); 154 dmxInput->sigioAdded[i] = TRUE; 155 156 if (++dmxFdCount == 1) dmxSigioHook(); 157 } 158 } 159} 160 161static void dmxSigioRemove(DMXInputInfo *dmxInput) 162{ 163 int flags; 164 int i; 165 166 switch (dmxInput->sigioState) { 167 case DMX_NOSIGIO: return; 168 case DMX_USESIGIO: return; 169 case DMX_ACTIVESIGIO: dmxInput->sigioState = DMX_USESIGIO; break; 170 } 171 172 for (i = 0; i < dmxInput->sigioFdCount; i++) { 173 if (dmxInput->sigioAdded[i]) { 174 int fd = dmxInput->sigioFd[i]; 175 176 dmxInput->sigioAdded[i] = FALSE; 177 RemoveEnabledDevice(fd); 178 179 flags = fcntl(fd, F_GETFL); 180 flags &= ~(O_ASYNC|O_NONBLOCK); 181 fcntl(fd, F_SETFL, flags); 182 183 if (!--dmxFdCount) dmxSigioUnhook(); 184 } 185 } 186} 187 188/** Enable SIGIO handling. This instantiates the handler with the OS. */ 189void dmxSigioEnableInput(void) 190{ 191 int i; 192 DMXInputInfo *dmxInput; 193 194 dmxInputEnabled = TRUE; 195 for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) 196 dmxSigioAdd(dmxInput); 197} 198 199/** Disable SIGIO handling. This removes the hanlder from the OS. */ 200void dmxSigioDisableInput(void) 201{ 202 int i; 203 DMXInputInfo *dmxInput; 204 205 dmxInputEnabled = FALSE; 206 for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) 207 dmxSigioRemove(dmxInput); 208} 209 210/** Make a note that the input device described in \a dmxInput will be 211 * using the file descriptor \a fd for SIGIO signals. Calls 212 * AddEnabledDevice ifi SIGIO handling has been enabled with 213 * #dmxSigioEnableInput(). */ 214void dmxSigioRegister(DMXInputInfo *dmxInput, int fd) 215{ 216 dmxInput->sigioState = DMX_USESIGIO; 217 if (dmxInput->sigioFdCount >= DMX_MAX_SIGIO_FDS) 218 dmxLog(dmxFatal, "Too many SIGIO file descriptors (%d >= %d)\n", 219 dmxInput->sigioFdCount, DMX_MAX_SIGIO_FDS); 220 221 dmxInput->sigioFd[dmxInput->sigioFdCount++] = fd; 222 if (dmxInputEnabled) dmxSigioAdd(dmxInput); 223} 224 225/** Remove the notes that \a dmxInput is using any file descriptors for 226 * SIGIO signals. Calls RemoveEnabledDevice. */ 227void dmxSigioUnregister(DMXInputInfo *dmxInput) 228{ 229 if (dmxInput->sigioState == DMX_NOSIGIO) return; 230 dmxSigioRemove(dmxInput); 231 dmxInput->sigioState = DMX_NOSIGIO; 232 dmxInput->sigioFdCount = 0; 233} 234