#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;
static Bool dmxInputEnabled = TRUE;
#ifndef O_ASYNC
# ifdef FASYNC
# define O_ASYNC FASYNC
# else
# define O_ASYNC 0
# endif
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK FNONBLK
#endif
static void dmxSigioHandler(int sig)
{
int i, j;
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];
if (dmxLocal->collect_events) {
dmxLocal->collect_events(&dmxLocal->pDevice->public,
dmxMotion,
dmxEnqueue,
dmxCheckSpecialKeys,
DMX_NO_BLOCK);
}
}
}
}
}
void dmxSigioBlock(void)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGIO);
sigprocmask(SIG_BLOCK, &s, 0);
}
void dmxSigioUnblock(void)
{
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGIO);
sigprocmask(SIG_UNBLOCK, &s, 0);
}
static void dmxSigioHook(void)
{
struct sigaction a;
sigset_t s;
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);
sigemptyset(&s);
sigprocmask(SIG_SETMASK, &s, 0);
}
static void dmxSigioUnhook(void)
{
struct sigaction a;
memset (&a, 0, sizeof(a));
a.sa_handler = SIG_IGN;
sigemptyset(&a.sa_mask);
sigaction(SIGIO, &a, 0);
}
static void dmxSigioAdd(DMXInputInfo *dmxInput)
{
int flags;
int i;
switch (dmxInput->sigioState) {
case DMX_NOSIGIO: return;
case DMX_USESIGIO: dmxInput->sigioState = DMX_ACTIVESIGIO; break;
case DMX_ACTIVESIGIO: return;
}
for (i = 0; i < dmxInput->sigioFdCount; i++) {
if (!dmxInput->sigioAdded[i]) {
int fd = dmxInput->sigioFd[i];
fcntl(fd, F_SETOWN, getpid());
flags = fcntl(fd, F_GETFL);
flags |= O_ASYNC|O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
AddEnabledDevice(fd);
dmxInput->sigioAdded[i] = TRUE;
if (++dmxFdCount == 1) dmxSigioHook();
}
}
}
static void dmxSigioRemove(DMXInputInfo *dmxInput)
{
int flags;
int i;
switch (dmxInput->sigioState) {
case DMX_NOSIGIO: return;
case DMX_USESIGIO: return;
case DMX_ACTIVESIGIO: dmxInput->sigioState = DMX_USESIGIO; break;
}
for (i = 0; i < dmxInput->sigioFdCount; i++) {
if (dmxInput->sigioAdded[i]) {
int fd = dmxInput->sigioFd[i];
dmxInput->sigioAdded[i] = FALSE;
RemoveEnabledDevice(fd);
flags = fcntl(fd, F_GETFL);
flags &= ~(O_ASYNC|O_NONBLOCK);
fcntl(fd, F_SETFL, flags);
if (!--dmxFdCount) dmxSigioUnhook();
}
}
}
void dmxSigioEnableInput(void)
{
int i;
DMXInputInfo *dmxInput;
dmxInputEnabled = TRUE;
for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
dmxSigioAdd(dmxInput);
}
void dmxSigioDisableInput(void)
{
int i;
DMXInputInfo *dmxInput;
dmxInputEnabled = FALSE;
for (i = 0, dmxInput = &dmxInputs[0]; i < dmxNumInputs; i++, dmxInput++)
dmxSigioRemove(dmxInput);
}
void dmxSigioRegister(DMXInputInfo *dmxInput, int fd)
{
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);
dmxInput->sigioFd[dmxInput->sigioFdCount++] = fd;
if (dmxInputEnabled) dmxSigioAdd(dmxInput);
}
void dmxSigioUnregister(DMXInputInfo *dmxInput)
{
if (dmxInput->sigioState == DMX_NOSIGIO) return;
dmxSigioRemove(dmxInput);
dmxInput->sigioState = DMX_NOSIGIO;
dmxInput->sigioFdCount = 0;
}