| /* |
| * 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_io.h" |
| #include "async_event.h" |
| #include "async_internal.h" |
| #include "file.h" |
| #include "io_misc.h" |
| |
| struct AsyncEventStruct { |
| AsyncEventCallback *callback; |
| void *data; |
| |
| FileDescriptor pipeInput; |
| FileDescriptor pipeOutput; |
| |
| FileDescriptor monitorDescriptor; |
| AsyncHandle monitorHandle; |
| |
| #ifdef __MINGW32__ |
| CRITICAL_SECTION criticalSection; |
| unsigned int pendingCount; |
| #endif /* __MINGW32__ */ |
| }; |
| |
| ASYNC_MONITOR_CALLBACK(asyncMonitorEventPipe) { |
| AsyncEvent *event = parameters->data; |
| void *data; |
| const size_t size = sizeof(data); |
| |
| if (readFileDescriptor(event->pipeOutput, &data, size) == size) { |
| #ifdef __MINGW32__ |
| EnterCriticalSection(&event->criticalSection); |
| if (!--event->pendingCount) ResetEvent(event->monitorDescriptor); |
| LeaveCriticalSection(&event->criticalSection); |
| #endif /* __MINGW32__ */ |
| |
| { |
| AsyncEventCallback *callback = event->callback; |
| |
| const AsyncEventCallbackParameters parameters = { |
| .eventData = event->data, |
| .signalData = data |
| }; |
| |
| logSymbol(LOG_CATEGORY(ASYNC_EVENTS), callback, "event starting"); |
| if (callback) callback(¶meters); |
| } |
| |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int |
| asyncSignalEvent (AsyncEvent *event, void *data) { |
| const size_t size = sizeof(data); |
| ssize_t result = writeFileDescriptor(event->pipeInput, &data, size); |
| |
| if (result == size) { |
| #ifdef __MINGW32__ |
| EnterCriticalSection(&event->criticalSection); |
| if (!event->pendingCount++) SetEvent(event->monitorDescriptor); |
| LeaveCriticalSection(&event->criticalSection); |
| #endif /* __MINGW32__ */ |
| |
| return 1; |
| } |
| |
| if (result == -1) { |
| logSystemError("write"); |
| } else { |
| logMessage(LOG_ERR, "short write"); |
| } |
| |
| return 0; |
| } |
| |
| AsyncEvent * |
| asyncNewEvent (AsyncEventCallback *callback, void *data) { |
| AsyncEvent *event; |
| |
| if ((event = malloc(sizeof(*event)))) { |
| memset(event, 0, sizeof(*event)); |
| event->callback = callback; |
| event->data = data; |
| |
| if (createAnonymousPipe(&event->pipeInput, &event->pipeOutput)) { |
| #ifdef __MINGW32__ |
| if (!(event->monitorDescriptor = CreateEvent(NULL, TRUE, FALSE, NULL))) { |
| logWindowsSystemError("CreateEvent"); |
| event->monitorDescriptor = INVALID_FILE_DESCRIPTOR; |
| } |
| #else /* __MINGW32__ */ |
| setCloseOnExec(event->pipeInput, 1); |
| setCloseOnExec(event->pipeOutput, 1); |
| event->monitorDescriptor = event->pipeOutput; |
| #endif /* __MINGW32__ */ |
| |
| if (event->monitorDescriptor != INVALID_FILE_DESCRIPTOR) { |
| if (asyncMonitorFileInput(&event->monitorHandle, event->monitorDescriptor, |
| asyncMonitorEventPipe, event)) { |
| #ifdef __MINGW32__ |
| InitializeCriticalSection(&event->criticalSection); |
| event->pendingCount = 0; |
| #endif /* __MINGW32__ */ |
| |
| logSymbol(LOG_CATEGORY(ASYNC_EVENTS), event->callback, "event added"); |
| return event; |
| } |
| |
| closeFileDescriptor(event->monitorDescriptor); |
| } |
| |
| closeFileDescriptor(event->pipeInput); |
| closeFileDescriptor(event->pipeOutput); |
| } |
| |
| free(event); |
| } else { |
| logMallocError(); |
| } |
| |
| return NULL; |
| } |
| |
| void |
| asyncDiscardEvent (AsyncEvent *event) { |
| asyncCancelRequest(event->monitorHandle); |
| |
| closeFileDescriptor(event->pipeInput); |
| closeFileDescriptor(event->pipeOutput); |
| |
| #ifdef __MINGW32__ |
| CloseHandle(event->monitorDescriptor); |
| DeleteCriticalSection(&event->criticalSection); |
| #endif /* __MINGW32__ */ |
| |
| logSymbol(LOG_CATEGORY(ASYNC_EVENTS), event->callback, "event removed"); |
| free(event); |
| } |
| |