From d4788f5eb3f94e01a6575f227f2ab80330f1a8e1 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Thu, 29 Apr 2021 16:53:12 +0300 Subject: Periodic: Handling removal during iteration --- src/periodic.c | 32 +++++++++++++++++++++++++------- src/periodic.h | 2 ++ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/periodic.c b/src/periodic.c index 0291ff98..068f2a1e 100644 --- a/src/periodic.c +++ b/src/periodic.c @@ -57,6 +57,21 @@ iDefineTypeConstructionArgs(PeriodicCommand, (iAny *ctx, const char *cmd), ctx, static const uint32_t postingInterval_Periodic_ = 500; +static void removePending_Periodic_(iPeriodic *d) { + iForEach(PtrSet, i, &d->pendingRemoval) { + size_t pos; + iPeriodicCommand key = { .context = *i.value }; + if (locate_SortedArray(&d->commands, &key, &pos)) { + iPeriodicCommand *pc = at_SortedArray(&d->commands, pos); + deinit_PeriodicCommand(pc); + remove_Array(&d->commands.values, pos); + } + } + clear_PtrSet(&d->pendingRemoval); +} + +static iBool isDispatching_; + iBool dispatchCommands_Periodic(iPeriodic *d) { const uint32_t now = SDL_GetTicks(); if (now - d->lastPostTime < postingInterval_Periodic_) { @@ -65,20 +80,24 @@ iBool dispatchCommands_Periodic(iPeriodic *d) { d->lastPostTime = now; iBool wasPosted = iFalse; lock_Mutex(d->mutex); + isDispatching_ = iTrue; + iAssert(isEmpty_PtrSet(&d->pendingRemoval)); iConstForEach(Array, i, &d->commands.values) { const iPeriodicCommand *pc = i.value; + iAssert(isInstance_Object(pc->context, &Class_Widget)); const SDL_UserEvent ev = { .type = SDL_USEREVENT, .code = command_UserEventCode, .data1 = (void *) cstr_String(&pc->command), .data2 = findRoot_Window(get_Window(), pc->context) }; - iAssert(isInstance_Object(pc->context, &Class_Widget)); setCurrent_Root(ev.data2); dispatchEvent_Widget(pc->context, (const SDL_Event *) &ev); wasPosted = iTrue; } + removePending_Periodic_(d); setCurrent_Root(NULL); + isDispatching_ = iFalse; unlock_Mutex(d->mutex); return wasPosted; } @@ -87,9 +106,11 @@ void init_Periodic(iPeriodic *d) { d->mutex = new_Mutex(); init_SortedArray(&d->commands, sizeof(iPeriodicCommand), cmp_PeriodicCommand_); d->lastPostTime = 0; + init_PtrSet(&d->pendingRemoval); } void deinit_Periodic(iPeriodic *d) { + deinit_PtrSet(&d->pendingRemoval); iForEach(Array, i, &d->commands.values) { deinit_PeriodicCommand(i.value); } @@ -115,12 +136,9 @@ void add_Periodic(iPeriodic *d, iAny *context, const char *command) { void remove_Periodic(iPeriodic *d, iAny *context) { lock_Mutex(d->mutex); - size_t pos; - iPeriodicCommand key = { .context = context }; - if (locate_SortedArray(&d->commands, &key, &pos)) { - iPeriodicCommand *pc = at_SortedArray(&d->commands, pos); - deinit_PeriodicCommand(pc); - remove_Array(&d->commands.values, pos); + insert_PtrSet(&d->pendingRemoval, context); + if (!isDispatching_) { + removePending_Periodic_(d); } unlock_Mutex(d->mutex); } diff --git a/src/periodic.h b/src/periodic.h index 8886617b..3a0501d9 100644 --- a/src/periodic.h +++ b/src/periodic.h @@ -21,6 +21,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include #include iDeclareType(Periodic) @@ -31,6 +32,7 @@ struct Impl_Periodic { iMutex * mutex; iSortedArray commands; uint32_t lastPostTime; + iPtrSet pendingRemoval; /* contexts */ }; void init_Periodic (iPeriodic *); -- cgit v1.2.3