xenocara/xserver/hw/dmx/input/dmxsigio.c

235 lines
6.0 KiB
C
Raw Normal View History

2006-11-26 11:13:41 -07:00
/*
* Copyright 2002-2003 Red Hat Inc., Durham, North Carolina.
*
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation on the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT. IN NO EVENT SHALL RED HAT AND/OR THEIR SUPPLIERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* Authors:
* Rickard E. (Rik) Faith <faith@redhat.com>
*
*/
/** \file
*
* Provides an interface for handling SIGIO signals for input devices. */
#ifdef HAVE_DMX_CONFIG_H
#include <dmx-config.h>
#endif
#include "inputstr.h"
#include "dmxinputinit.h"
#include "dmxsigio.h"
#include "dmxevents.h"
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
static int dmxFdCount = 0;
2006-11-26 11:13:41 -07:00
static Bool dmxInputEnabled = TRUE;
/* Define equivalents for non-POSIX systems (e.g., SGI IRIX, Solaris) */
#ifndef O_ASYNC
#ifdef FASYNC
#define O_ASYNC FASYNC
#else
#define O_ASYNC 0
#endif
2006-11-26 11:13:41 -07:00
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK FNONBLK
#endif
static void
dmxSigioHandler(int sig)
2006-11-26 11:13:41 -07:00
{
int i, j;
2006-11-26 11:13:41 -07:00
DMXInputInfo *dmxInput;
for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++) {
if (dmxInput->sigioState == DMX_ACTIVESIGIO) {
for (j = 0; j < dmxInput->numDevs; j++) {
DMXLocalInputInfoPtr dmxLocal = dmxInput->devs[j];
2006-11-26 11:13:41 -07:00
if (dmxLocal->collect_events) {
dmxLocal->collect_events(&dmxLocal->pDevice->public,
dmxMotion,
dmxEnqueue,
dmxCheckSpecialKeys, DMX_NO_BLOCK);
2006-11-26 11:13:41 -07:00
}
}
}
}
}
static void
dmxSigioHook(void)
2006-11-26 11:13:41 -07:00
{
struct sigaction a;
sigset_t s;
2006-11-26 11:13:41 -07:00
memset(&a, 0, sizeof(a));
a.sa_handler = dmxSigioHandler;
sigemptyset(&a.sa_mask);
sigaddset(&a.sa_mask, SIGIO);
sigaddset(&a.sa_mask, SIGALRM);
sigaddset(&a.sa_mask, SIGVTALRM);
sigaction(SIGIO, &a, 0);
2006-11-26 11:13:41 -07:00
sigemptyset(&s);
sigprocmask(SIG_SETMASK, &s, 0);
}
static void
dmxSigioUnhook(void)
2006-11-26 11:13:41 -07:00
{
struct sigaction a;
memset(&a, 0, sizeof(a));
2006-11-26 11:13:41 -07:00
a.sa_handler = SIG_IGN;
sigemptyset(&a.sa_mask);
sigaction(SIGIO, &a, 0);
}
static void
dmxSigioAdd(DMXInputInfo * dmxInput)
2006-11-26 11:13:41 -07:00
{
int flags;
int i;
switch (dmxInput->sigioState) {
case DMX_NOSIGIO:
return;
case DMX_USESIGIO:
dmxInput->sigioState = DMX_ACTIVESIGIO;
break;
case DMX_ACTIVESIGIO:
return;
2006-11-26 11:13:41 -07:00
}
for (i = 0; i < dmxInput->sigioFdCount; i++) {
if (!dmxInput->sigioAdded[i]) {
int fd = dmxInput->sigioFd[i];
2006-11-26 11:13:41 -07:00
fcntl(fd, F_SETOWN, getpid());
flags = fcntl(fd, F_GETFL);
flags |= O_ASYNC | O_NONBLOCK;
2006-11-26 11:13:41 -07:00
fcntl(fd, F_SETFL, flags);
2006-11-26 11:13:41 -07:00
AddEnabledDevice(fd);
dmxInput->sigioAdded[i] = TRUE;
if (++dmxFdCount == 1)
dmxSigioHook();
2006-11-26 11:13:41 -07:00
}
}
}
static void
dmxSigioRemove(DMXInputInfo * dmxInput)
2006-11-26 11:13:41 -07:00
{
int flags;
int i;
2006-11-26 11:13:41 -07:00
switch (dmxInput->sigioState) {
case DMX_NOSIGIO:
return;
case DMX_USESIGIO:
return;
case DMX_ACTIVESIGIO:
dmxInput->sigioState = DMX_USESIGIO;
break;
2006-11-26 11:13:41 -07:00
}
for (i = 0; i < dmxInput->sigioFdCount; i++) {
if (dmxInput->sigioAdded[i]) {
int fd = dmxInput->sigioFd[i];
2006-11-26 11:13:41 -07:00
dmxInput->sigioAdded[i] = FALSE;
RemoveEnabledDevice(fd);
2006-11-26 11:13:41 -07:00
flags = fcntl(fd, F_GETFL);
flags &= ~(O_ASYNC | O_NONBLOCK);
2006-11-26 11:13:41 -07:00
fcntl(fd, F_SETFL, flags);
if (!--dmxFdCount)
dmxSigioUnhook();
2006-11-26 11:13:41 -07:00
}
}
}
/** Enable SIGIO handling. This instantiates the handler with the OS. */
void
dmxSigioEnableInput(void)
2006-11-26 11:13:41 -07:00
{
int i;
DMXInputInfo *dmxInput;
2006-11-26 11:13:41 -07:00
dmxInputEnabled = TRUE;
for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
dmxSigioAdd(dmxInput);
}
/** Disable SIGIO handling. This removes the hanlder from the OS. */
void
dmxSigioDisableInput(void)
2006-11-26 11:13:41 -07:00
{
int i;
DMXInputInfo *dmxInput;
2006-11-26 11:13:41 -07:00
dmxInputEnabled = FALSE;
for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
dmxSigioRemove(dmxInput);
}
/** Make a note that the input device described in \a dmxInput will be
* using the file descriptor \a fd for SIGIO signals. Calls
* AddEnabledDevice ifi SIGIO handling has been enabled with
* #dmxSigioEnableInput(). */
void
dmxSigioRegister(DMXInputInfo * dmxInput, int fd)
2006-11-26 11:13:41 -07:00
{
dmxInput->sigioState = DMX_USESIGIO;
if (dmxInput->sigioFdCount >= DMX_MAX_SIGIO_FDS)
dmxLog(dmxFatal, "Too many SIGIO file descriptors (%d >= %d)\n",
dmxInput->sigioFdCount, DMX_MAX_SIGIO_FDS);
2006-11-26 11:13:41 -07:00
dmxInput->sigioFd[dmxInput->sigioFdCount++] = fd;
if (dmxInputEnabled)
dmxSigioAdd(dmxInput);
2006-11-26 11:13:41 -07:00
}
/** Remove the notes that \a dmxInput is using any file descriptors for
* SIGIO signals. Calls RemoveEnabledDevice. */
void
dmxSigioUnregister(DMXInputInfo * dmxInput)
2006-11-26 11:13:41 -07:00
{
if (dmxInput->sigioState == DMX_NOSIGIO)
return;
2006-11-26 11:13:41 -07:00
dmxSigioRemove(dmxInput);
dmxInput->sigioState = DMX_NOSIGIO;
2006-11-26 11:13:41 -07:00
dmxInput->sigioFdCount = 0;
}