Home | History | Annotate | Line # | Download | only in input
      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 (at) 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 
     50 static int  dmxFdCount      = 0;
     51 static 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 
     65 static 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. */
     87 void 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. */
     97 void dmxSigioUnblock(void)
     98 {
     99     sigset_t s;
    100 
    101     sigemptyset(&s);
    102     sigaddset(&s, SIGIO);
    103     sigprocmask(SIG_UNBLOCK, &s, 0);
    104 }
    105 
    106 static 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 
    123 static 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 
    133 static 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 
    161 static 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. */
    189 void 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. */
    200 void 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(). */
    214 void 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. */
    227 void 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