/* * 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_wait.h" #include "async_internal.h" #include "timing.h" typedef struct { AsyncThreadSpecificData *tsd; long int timeout; } CallbackExecuterParameters; typedef int CallbackExecuter (CallbackExecuterParameters *parameters); typedef struct { CallbackExecuter *execute; const char *action; } CallbackExecuterEntry; struct AsyncWaitDataStruct { AsyncThreadSpecificData *tsd; unsigned int waitDepth; }; static int alarmCallbackExecuter (CallbackExecuterParameters *parameters) { return asyncExecuteAlarmCallback(parameters->tsd->alarmData, ¶meters->timeout); } static int taskCallbackExecuter (CallbackExecuterParameters *parameters) { AsyncThreadSpecificData *tsd = parameters->tsd; if (tsd->waitData->waitDepth != 1) return 0; return asyncExecuteTaskCallback(tsd->taskData); } static int ioCallbackExecuter (CallbackExecuterParameters *parameters) { return asyncExecuteIoCallback(parameters->tsd->ioData, parameters->timeout); } static const CallbackExecuterEntry callbackExecuterTable[] = { { .execute = alarmCallbackExecuter, .action = "alarm handled" }, { .execute = taskCallbackExecuter, .action = "task performed" }, { .execute = ioCallbackExecuter, .action = "I/O operation handled" }, { .execute = NULL, .action = "wait timed out" } }; void asyncDeallocateWaitData (AsyncWaitData *wd) { if (wd) { free(wd); } } static AsyncWaitData * getWaitData (void) { AsyncThreadSpecificData *tsd = asyncGetThreadSpecificData(); if (!tsd) return NULL; if (!tsd->waitData) { AsyncWaitData *wd; if (!(wd = malloc(sizeof(*wd)))) { logMallocError(); return NULL; } memset(wd, 0, sizeof(*wd)); wd->tsd = tsd; wd->waitDepth = 0; tsd->waitData = wd; } return tsd->waitData; } static void awaitAction (long int timeout) { AsyncWaitData *wd = getWaitData(); if (wd) { const CallbackExecuterEntry *cbx = callbackExecuterTable; CallbackExecuterParameters parameters = { .tsd = wd->tsd, .timeout = timeout }; wd->waitDepth += 1; logMessage(LOG_CATEGORY(ASYNC_EVENTS), "begin: level %u: timeout %ld", wd->waitDepth, timeout); while (cbx->execute) { if (cbx->execute(¶meters)) break; cbx += 1; } logMessage(LOG_CATEGORY(ASYNC_EVENTS), "end: level %u: %s", wd->waitDepth, cbx->action); wd->waitDepth -= 1; } else { logMessage(LOG_CATEGORY(ASYNC_EVENTS), "waiting: %ld", timeout); approximateDelay(timeout); } } int asyncAwaitCondition (int timeout, AsyncConditionTester *testCondition, void *data) { int first = 1; TimePeriod period; startTimePeriod(&period, timeout); while (!(testCondition && testCondition(data))) { long int elapsed; if (first) { first = 0; elapsed = 0; } else if (afterTimePeriod(&period, &elapsed)) { return 0; } awaitAction(timeout - elapsed); } logSymbol(LOG_CATEGORY(ASYNC_EVENTS), testCondition, "condition satisfied"); return 1; } void asyncWait (int duration) { asyncAwaitCondition(duration, NULL, NULL); } void asyncWaitFor (AsyncConditionTester *testCondition, void *data) { while (!asyncAwaitCondition(1000000, testCondition, data)); }