From 024d857f0dc239726cc8c042e8b9296e8886af7d Mon Sep 17 00:00:00 2001 From: David Robillard Date: Thu, 26 Jul 2012 16:38:44 +0000 Subject: Fix post processor ordering to be correctly monotonic between both pre-processed events and notifications. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4560 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/Context.cpp | 9 +++++++-- src/server/Context.hpp | 2 +- src/server/PostProcessor.cpp | 30 ++++++++++++++---------------- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/server/Context.cpp b/src/server/Context.cpp index 0f7555a4..745b849f 100644 --- a/src/server/Context.cpp +++ b/src/server/Context.cpp @@ -33,10 +33,11 @@ struct Notification LV2_URID k = 0, uint32_t s = 0, Raul::Atom::TypeID t = 0) - : port(p), key(k), size(s), type(t) + : port(p), time(f), key(k), size(s), type(t) {} PortImpl* port; + FrameTime time; LV2_URID key; uint32_t size; Raul::Atom::TypeID type; @@ -74,11 +75,15 @@ Context::notify(LV2_URID key, } void -Context::emit_notifications() +Context::emit_notifications(FrameTime end) { const uint32_t read_space = _event_sink.read_space(); Notification note; for (uint32_t i = 0; i < read_space; i += sizeof(note)) { + if (_event_sink.peek(sizeof(note), ¬e) != sizeof(note) || + note.time >= end) { + return; + } if (_event_sink.read(sizeof(note), ¬e) == sizeof(note)) { Raul::Atom value = _engine.world()->forge().alloc( note.size, note.type, NULL); diff --git a/src/server/Context.hpp b/src/server/Context.hpp index bd740504..caebd7a4 100644 --- a/src/server/Context.hpp +++ b/src/server/Context.hpp @@ -62,7 +62,7 @@ public: const void* body = NULL); /** Emit pending notifications in some other non-realtime thread. */ - void emit_notifications(); + void emit_notifications(FrameTime end); inline ID id() const { return _id; } diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp index 16b0317d..984f69b5 100644 --- a/src/server/PostProcessor.cpp +++ b/src/server/PostProcessor.cpp @@ -54,34 +54,32 @@ PostProcessor::append(ProcessContext& context, Event* first, Event* last) void PostProcessor::process() { - const FrameTime end_time = _max_time.get(); + const FrameTime end_time = _max_time.get() + 1; - /* FIXME: The order here is a bit tricky: if the normal events are - * processed first, then a deleted port may still have a pending - * broadcast event which will segfault if executed afterwards. - * If it's the other way around, broadcasts will be sent for - * ports the client doesn't even know about yet... */ - - /* FIXME: process events from all threads if parallel */ - - /* Process audio thread generated events */ - _engine.process_context().emit_notifications(); + // To avoid a race, we only process up to tail and never write to _tail + Event* const tail = _tail.get(); - /* Process normal events */ Event* ev = _head.get(); if (!ev) { return; } - Event* const tail = _tail.get(); - _head = (Event*)tail->next(); - while (ev && ev->time() <= end_time) { + while (ev->time() < end_time) { Event* const next = (Event*)ev->next(); + + // Process audio thread notifications up until this event's time + _engine.process_context().emit_notifications(ev->time()); + + // Process and delete this event ev->post_process(); delete ev; - if (ev == tail) { + + if (ev == tail || next->time() >= end_time) { + // Reached end, update _head + _head = next; break; } + ev = next; } } -- cgit v1.2.1