/* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2021 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU Lesser General Public License, as published by the Free Software * Foundation; either version 2.1 of the License, or (at your option) any * later version. Please see the file LICENSE-LGPL for details. * * Web Page: http://brltty.app/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include #include "log.h" #include "async_event.h" #include "async_signal.h" #include "async_internal.h" #include "get_thread.h" #ifdef ASYNC_CAN_HANDLE_SIGNALS #if defined(HAVE_SYS_SIGNALFD_H) #include #include "async_io.h" #else /* paradigm-specific signal monitoring definitions */ #endif /* paradigm-specific signal monitoring definitions */ struct AsyncSignalDataStruct { #ifdef ASYNC_CAN_MONITOR_SIGNALS Queue *signalQueue; #endif /* ASYNC_CAN_MONITOR_SIGNALS */ #ifdef ASYNC_CAN_BLOCK_SIGNALS sigset_t obtainableSignals; #endif /* ASYNC_CAN_BLOCK_SIGNALS */ #ifdef ASYNC_CAN_OBTAIN_SIGNALS sigset_t claimedSignals; sigset_t obtainedSignals; int firstObtainableSignal; int lastObtainableSignal; #endif /* ASYNC_CAN_OBTAIN_SIGNALS */ }; void asyncDeallocateSignalData (AsyncSignalData *sd) { if (sd) { #ifdef ASYNC_CAN_MONITOR_SIGNALS if (sd->signalQueue) deallocateQueue(sd->signalQueue); #endif /* ASYNC_CAN_MONITOR_SIGNALS */ free(sd); } } #if defined(ASYNC_CAN_BLOCK_SIGNALS) || defined(ASYNC_CAN_MONITOR_SIGNALS) || defined(ASYNC_CAN_OBTAIN_SIGNALS) static AsyncSignalData * getSignalData (void) { AsyncThreadSpecificData *tsd = asyncGetThreadSpecificData(); if (!tsd) return NULL; if (!tsd->signalData) { AsyncSignalData *sd; if (!(sd = malloc(sizeof(*sd)))) { logMallocError(); return NULL; } memset(sd, 0, sizeof(*sd)); #ifdef ASYNC_CAN_MONITOR_SIGNALS sd->signalQueue = NULL; #endif /* ASYNC_CAN_MONITOR_SIGNALS */ #ifdef ASYNC_CAN_BLOCK_SIGNALS sigemptyset(&sd->obtainableSignals); #endif /* ASYNC_CAN_BLOCK_SIGNALS */ #ifdef ASYNC_CAN_OBTAIN_SIGNALS sigemptyset(&sd->claimedSignals); sigemptyset(&sd->obtainedSignals); sd->firstObtainableSignal = SIGRTMIN; sd->lastObtainableSignal = SIGRTMAX; #ifdef ASYNC_CAN_BLOCK_SIGNALS { int signalNumber; for (signalNumber=sd->firstObtainableSignal; signalNumber<=sd->lastObtainableSignal; signalNumber+=1) { sigaddset(&sd->obtainableSignals, signalNumber); } } #endif /* ASYNC_CAN_BLOCK_SIGNALS */ #endif /* ASYNC_CAN_OBTAIN_SIGNALS */ tsd->signalData = sd; } return tsd->signalData; } #endif /* need signal data */ int asyncHandleSignal (int signalNumber, AsyncSignalHandler *newHandler, AsyncSignalHandler **oldHandler) { #if defined(HAVE_SIGACTION) struct sigaction newAction; struct sigaction oldAction; memset(&newAction, 0, sizeof(newAction)); sigemptyset(&newAction.sa_mask); newAction.sa_handler = newHandler; if (sigaction(signalNumber, &newAction, &oldAction) != -1) { if (oldHandler) *oldHandler = oldAction.sa_handler; return 1; } logSystemError("sigaction"); #else /* set signal handler */ AsyncSignalHandler *result = signal(signalNumber, newHandler); if (result != SIG_ERR) { if (oldHandler) *oldHandler = result; return 1; } logSystemError("signal"); #endif /* set signal handler */ return 0; } int asyncIgnoreSignal (int signalNumber, AsyncSignalHandler **oldHandler) { return asyncHandleSignal(signalNumber, SIG_IGN, oldHandler); } int asyncRevertSignal (int signalNumber, AsyncSignalHandler **oldHandler) { return asyncHandleSignal(signalNumber, SIG_DFL, oldHandler); } ASYNC_SIGNAL_HANDLER(asyncEmptySignalHandler) { } #ifdef ASYNC_CAN_BLOCK_SIGNALS static int setSignalMask (int how, const sigset_t *newMask, sigset_t *oldMask) { #ifdef GOT_PTHREADS int error = pthread_sigmask(how, newMask, oldMask); if (!error) return 1; logActionError(error, "pthread_setmask"); #else /* GOT_PTHREADS */ if (sigprocmask(how, newMask, oldMask) != -1) return 1; logSystemError("sigprocmask"); #endif /* GOT_PTHREADS */ return 0; } static int makeSignalMask (sigset_t *signalMask, int signalNumber) { if (sigemptyset(signalMask) != -1) { if (sigaddset(signalMask, signalNumber) != -1) { return 1; } else { logSystemError("sigaddset"); } } else { logSystemError("sigemptyset"); } return 0; } int asyncSetSignalBlocked (int signalNumber, int state) { sigset_t mask; if (makeSignalMask(&mask, signalNumber)) { if (setSignalMask((state? SIG_BLOCK: SIG_UNBLOCK), &mask, NULL)) { return 1; } } return 0; } static int getSignalMask (sigset_t *mask) { return setSignalMask(SIG_SETMASK, NULL, mask); } int asyncIsSignalBlocked (int signalNumber) { sigset_t signalMask; if (getSignalMask(&signalMask)) { int result = sigismember(&signalMask, signalNumber); if (result != -1) return result; logSystemError("sigismember"); } return 0; } int asyncWithSignalsBlocked ( const sigset_t *mask, AsyncWithSignalsBlockedFunction *function, void *data ) { sigset_t oldMask; if (setSignalMask(SIG_BLOCK, mask, &oldMask)) { function(data); setSignalMask(SIG_SETMASK, &oldMask, NULL); return 1; } return 0; } int asyncWithSignalBlocked ( int number, AsyncWithSignalsBlockedFunction *function, void *data ) { sigset_t mask; if (makeSignalMask(&mask, number)) { if (asyncWithSignalsBlocked(&mask, function, data)) { return 1; } } return 0; } int asyncWithAllSignalsBlocked ( AsyncWithSignalsBlockedFunction *function, void *data ) { sigset_t mask; if (sigfillset(&mask) != -1) { if (asyncWithSignalsBlocked(&mask, function, data)) { return 1; } } else { logSystemError("sigfillset"); } return 0; } int asyncWithObtainableSignalsBlocked ( AsyncWithSignalsBlockedFunction *function, void *data ) { AsyncSignalData *sd = getSignalData(); if (sd) { if (asyncWithSignalsBlocked(&sd->obtainableSignals, function, data)) { return 1; } } return 0; } int asyncBlockObtainableSignals (void) { AsyncSignalData *sd = getSignalData(); if (sd) { if (setSignalMask(SIG_BLOCK, &sd->obtainableSignals, NULL)) { return 1; } } return 0; } #endif /* ASYNC_CAN_BLOCK_SIGNALS */ #ifdef ASYNC_CAN_MONITOR_SIGNALS typedef struct { int number; Queue *monitors; unsigned wasBlocked:1; #if defined(HAVE_SYS_SIGNALFD_H) struct { int fileDescriptor; AsyncHandle asyncMonitor; } signalfd; #else /* paradigm-specific signal monitoring fields */ struct { AsyncEvent *event; AsyncSignalHandler *old; } handler; #endif /* paradigm-specific signal monitoring fields */ } SignalEntry; typedef struct { SignalEntry *signal; AsyncSignalCallback *callback; void *data; unsigned active:1; unsigned delete:1; } MonitorEntry; #if defined(HAVE_SYS_SIGNALFD_H) static void logSignalfdAction (const SignalEntry *sig, const char *action) { logMessage(LOG_CATEGORY(ASYNC_EVENTS), "%s signalfd monitor: sig=%d fd=%d", action, sig->number, sig->signalfd.fileDescriptor); } static void initializeSignalfdFileDescriptor (SignalEntry *sig) { sig->signalfd.fileDescriptor = -1; } static void initializeSignalfdAsyncMonitor (SignalEntry *sig) { sig->signalfd.asyncMonitor = NULL; } static void initializeSignalMonitoring (SignalEntry *sig) { initializeSignalfdFileDescriptor(sig); initializeSignalfdAsyncMonitor(sig); } static void closeSignalfdFileDescriptor (SignalEntry *sig) { struct signalfd_siginfo buffer; while (read(sig->signalfd.fileDescriptor, &buffer, sizeof(buffer)) != -1); close(sig->signalfd.fileDescriptor); initializeSignalfdFileDescriptor(sig); } static void cancelSignalfdAsyncMonitor (SignalEntry *sig) { asyncCancelRequest(sig->signalfd.asyncMonitor); initializeSignalfdAsyncMonitor(sig); } static void deactivateSignalMonitoring (SignalEntry *sig) { logSignalfdAction(sig, "destroying"); cancelSignalfdAsyncMonitor(sig); closeSignalfdFileDescriptor(sig); } #else /* paradigm-specific signal monitoring functions */ static void initializeHandlerEvent (SignalEntry *sig) { sig->handler.event = NULL; } static void initializeOldHandler (SignalEntry *sig) { sig->handler.old = NULL; } static void initializeSignalMonitoring (SignalEntry *sig) { initializeHandlerEvent(sig); initializeOldHandler(sig); } static void discardHandlerEvent (SignalEntry *sig) { asyncDiscardEvent(sig->handler.event); initializeHandlerEvent(sig); } static void restoreOldHandler (SignalEntry *sig) { asyncHandleSignal(sig->number, sig->handler.old, NULL); initializeOldHandler(sig); } static void deactivateSignalMonitoring (SignalEntry *sig) { restoreOldHandler(sig); discardHandlerEvent(sig); } #endif /* paradigm-specific signal monitoring functions */ static void deallocateMonitorEntry (void *item, void *data) { MonitorEntry *mon = item; free(mon); } static void deallocateSignalEntry (void *item, void *data) { SignalEntry *sig = item; deallocateQueue(sig->monitors); free(sig); } static Queue * getSignalQueue (int create) { AsyncSignalData *sd = getSignalData(); if (!sd) return NULL; if (!sd->signalQueue && create) { sd->signalQueue = newQueue(deallocateSignalEntry, NULL); } return sd->signalQueue; } typedef struct { SignalEntry *const signalEntry; } DeleteSignalEntryParameters; ASYNC_WITH_SIGNALS_BLOCKED_FUNCTION(asyncDeleteSignalEntry) { DeleteSignalEntryParameters *parameters = data; Queue *signals = getSignalQueue(0); Element *signalElement = findElementWithItem(signals, parameters->signalEntry); deleteElement(signalElement); } static void deleteMonitor (Element *monitorElement) { MonitorEntry *mon = getElementItem(monitorElement); SignalEntry *sig = mon->signal; logSymbol(LOG_CATEGORY(ASYNC_EVENTS), mon->callback, "signal monitor removed: %d", sig->number); deleteElement(monitorElement); if (getQueueSize(sig->monitors) == 0) { logMessage(LOG_CATEGORY(ASYNC_EVENTS), "deactivating signal monitoring: %d", sig->number); asyncSetSignalBlocked(sig->number, sig->wasBlocked); deactivateSignalMonitoring(sig); { DeleteSignalEntryParameters parameters = { .signalEntry = sig }; asyncWithAllSignalsBlocked(asyncDeleteSignalEntry, ¶meters); } } } static void cancelMonitor (Element *monitorElement) { MonitorEntry *mon = getElementItem(monitorElement); if (mon->active) { mon->delete = 1; } else { deleteMonitor(monitorElement); } } static void handlePendingSignal (const SignalEntry *sig) { Element *monitorElement = getStackHead(sig->monitors); if (monitorElement) { MonitorEntry *mon = getElementItem(monitorElement); AsyncSignalCallback *callback = mon->callback; const AsyncSignalCallbackParameters parameters = { .signal = sig->number, .data = mon->data }; logSymbol(LOG_CATEGORY(ASYNC_EVENTS), callback, "signal %d starting", sig->number); mon->active = 1; if (!callback(¶meters)) mon->delete = 1; mon->active = 0; logSymbol(LOG_CATEGORY(ASYNC_EVENTS), callback, "signal %d finished", sig->number); if (mon->delete) deleteMonitor(monitorElement); } } typedef struct { Queue *const signalQueue; SignalEntry *const signalEntry; Element *signalElement; } AddSignalEntryParameters; ASYNC_WITH_SIGNALS_BLOCKED_FUNCTION(asyncAddSignalEntry) { AddSignalEntryParameters *parameters = data; parameters->signalElement = enqueueItem(parameters->signalQueue, parameters->signalEntry); } typedef struct { int signalNumber; } TestMonitoredSignalKey; static int testMonitoredSignal (const void *item, void *data) { const SignalEntry *sig = item; const TestMonitoredSignalKey *key = data; return sig->number == key->signalNumber; } static Element * getSignalElement (int signalNumber, int create) { Queue *signals = getSignalQueue(create); if (signals) { { TestMonitoredSignalKey key = { .signalNumber = signalNumber }; { Element *element = findElement(signals, testMonitoredSignal, &key); if (element) return element; } } if (create) { SignalEntry *sig; if ((sig = malloc(sizeof(*sig)))) { memset(sig, 0, sizeof(*sig)); sig->number = signalNumber; initializeSignalMonitoring(sig); if ((sig->monitors = newQueue(deallocateMonitorEntry, NULL))) { { static AsyncQueueMethods methods = { .cancelRequest = cancelMonitor }; setQueueData(sig->monitors, &methods); } { AddSignalEntryParameters parameters = { .signalQueue = signals, .signalEntry = sig, .signalElement = NULL }; asyncWithAllSignalsBlocked(asyncAddSignalEntry, ¶meters); if (parameters.signalElement) return parameters.signalElement; } deallocateQueue(sig->monitors); } free(sig); } else { logMallocError(); } } } return NULL; } #if defined(HAVE_SYS_SIGNALFD_H) ASYNC_INPUT_CALLBACK(asyncHandleSignalfdInput) { static const char label[] = "signalfd"; const SignalEntry *sig = parameters->data; if (parameters->error) { logMessage(LOG_WARNING, "%s read error: fd=%d sig=%d: %s", label, sig->signalfd.fileDescriptor, sig->number, strerror(parameters->error)); } else if (parameters->end) { logMessage(LOG_WARNING, "%s end-of-file: fd=%d sig=%d", label, sig->signalfd.fileDescriptor, sig->number); } else { const struct signalfd_siginfo *info = parameters->buffer; handlePendingSignal(sig); return sizeof(*info); } return 0; } static int activateSignalMonitoring (SignalEntry *sig) { sigset_t mask; if (makeSignalMask(&mask, sig->number)) { int flags = 0; #ifdef SFD_NONBLOCK flags |= SFD_NONBLOCK; #endif /* SFD_NONBLOCK */ #ifdef SFD_CLOEXEC flags |= SFD_CLOEXEC; #endif /* SFD_CLOEXEC */ if ((sig->signalfd.fileDescriptor = signalfd(-1, &mask, flags)) != -1) { if (asyncReadFile(&sig->signalfd.asyncMonitor, sig->signalfd.fileDescriptor, sizeof(struct signalfd_siginfo), asyncHandleSignalfdInput, sig)) { if (sig->wasBlocked || asyncSetSignalBlocked(sig->number, 1)) { logSignalfdAction(sig, "created"); return 1; } cancelSignalfdAsyncMonitor(sig); } closeSignalfdFileDescriptor(sig); } else { logSystemError("signalfd"); } } return 0; } #else /* paradigm-specific signal monitoring handlers */ ASYNC_EVENT_CALLBACK(asyncHandlePendingSignal) { SignalEntry *sig = parameters->eventData; handlePendingSignal(sig); } ASYNC_SIGNAL_HANDLER(asyncHandleMonitoredSignal) { Element *signalElement = getSignalElement(signalNumber, 0); if (signalElement) { SignalEntry *sig = getElementItem(signalElement); asyncSignalEvent(sig->handler.event, NULL); } } static int activateSignalMonitoring (SignalEntry *sig) { if ((sig->handler.event = asyncNewEvent(asyncHandlePendingSignal, sig))) { if (asyncHandleSignal(sig->number, asyncHandleMonitoredSignal, &sig->handler.old)) { if (!sig->wasBlocked || asyncSetSignalBlocked(sig->number, 0)) { return 1; } restoreOldHandler(sig); } discardHandlerEvent(sig); } return 0; } #endif /* paradigm-specific signal monitoring handlers */ typedef struct { int signal; AsyncSignalCallback *callback; void *data; } MonitorElementParameters; static Element * newMonitorElement (const void *parameters) { const MonitorElementParameters *mep = parameters; Element *signalElement = getSignalElement(mep->signal, 1); if (signalElement) { SignalEntry *sig = getElementItem(signalElement); int newSignal = getQueueSize(sig->monitors) == 0; MonitorEntry *mon; if ((mon = malloc(sizeof(*mon)))) { memset(mon, 0, sizeof(*mon)); mon->signal = sig; mon->callback = mep->callback; mon->data = mep->data; mon->active = 0; mon->delete = 0; { Element *monitorElement = enqueueItem(sig->monitors, mon); if (monitorElement) { int added = !newSignal; if (!added) { logMessage(LOG_CATEGORY(ASYNC_EVENTS), "activating signal monitoring: %d", sig->number); sig->wasBlocked = asyncIsSignalBlocked(sig->number); if (activateSignalMonitoring(sig)) added = 1; } if (added) { logSymbol(LOG_CATEGORY(ASYNC_EVENTS), mon->callback, "signal monitor added: %d", sig->number); return monitorElement; } deleteElement(monitorElement); } } free(mon); } else { logMallocError(); } if (newSignal) deleteElement(signalElement); } return NULL; } int asyncMonitorSignal ( AsyncHandle *handle, int signal, AsyncSignalCallback *callback, void *data ) { const MonitorElementParameters mep = { .signal = signal, .callback = callback, .data = data }; return asyncMakeHandle(handle, newMonitorElement, &mep); } #endif /* ASYNC_CAN_MONITOR_SIGNALS */ #ifdef ASYNC_CAN_OBTAIN_SIGNALS int asyncClaimSignalNumber (int signal) { AsyncSignalData *sd = getSignalData(); if (sd) { const char *reason = "signal number not claimable"; if (sigismember(&sd->obtainableSignals, signal)) { if (sigismember(&sd->claimedSignals, signal)) { reason = "signal number already claimed"; } else if (sigismember(&sd->obtainedSignals, signal)) { reason = "signal number in use"; } else { sigaddset(&sd->claimedSignals, signal); return 1; } } logMessage(LOG_ERR, "%s: %d", reason, signal); } return 0; } int asyncReleaseSignalNumber (int signal) { AsyncSignalData *sd = getSignalData(); if (sd) { if (sigismember(&sd->claimedSignals, signal)) { sigdelset(&sd->claimedSignals, signal); return 1; } } logMessage(LOG_ERR, "signal number not claimed: %d", signal); return 0; } int asyncObtainSignalNumber (void) { AsyncSignalData *sd = getSignalData(); if (sd) { int signal; for (signal=sd->firstObtainableSignal; signal<=sd->lastObtainableSignal; signal+=1) { if (sigismember(&sd->obtainableSignals, signal)) { if (!sigismember(&sd->claimedSignals, signal)) { if (!sigismember(&sd->obtainedSignals, signal)) { sigaddset(&sd->obtainedSignals, signal); return signal; } } } } } logMessage(LOG_ERR, "no obtainable signal number"); return 0; } int asyncRelinquishSignalNumber (int signal) { AsyncSignalData *sd = getSignalData(); if (sd) { if (sigismember(&sd->obtainedSignals, signal)) { sigdelset(&sd->obtainedSignals, signal); return 1; } } logMessage(LOG_ERR, "signal number not obtained: %d", signal); return 0; } #endif /* ASYNC_CAN_OBTAIN_SIGNALS */ #endif /* ASYNC_CAN_HANDLE_SIGNALS */