| /* |
| * 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-2023 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 <dave@mielke.cc>. |
| */ |
| |
| #include "prologue.h" |
| |
| #include <string.h> |
| |
| #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 <sys/signalfd.h> |
| #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 */ |