From 641e6651220719a70c0fc2cdf9abac60458e587a Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sun, 30 Mar 2014 21:13:41 +0000 Subject: Hopefully fix dead lock issues with locked events. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@5346 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/PostProcessor.cpp | 33 +++++++++++++++++++-------------- src/server/PreProcessor.cpp | 8 +++++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/server/PostProcessor.cpp b/src/server/PostProcessor.cpp index 69668f2b..af429c01 100644 --- a/src/server/PostProcessor.cpp +++ b/src/server/PostProcessor.cpp @@ -43,12 +43,16 @@ PostProcessor::append(ProcessContext& context, Event* first, Event* last) { assert(first); assert(last); - if (_head) { - _tail.load()->next(first); + assert(!last->next()); + + /* Note that tail is only used here, not in process(). The head must be + checked first here, since if it is NULL the tail pointer is junk. */ + if (!_head) { _tail = last; + _head = first; } else { + _tail.load()->next(first); _tail = last; - _head = first; } } @@ -63,17 +67,14 @@ PostProcessor::process() { const FrameTime end_time = _max_time; - // To avoid a race, we only process up to tail and never write to _tail - Event* const tail = _tail.load(); - Event* ev = _head.load(); if (!ev) { - // Process audio thread notifications up until end + // Process audio thread notifications until end _engine.process_context().emit_notifications(end_time); return; } - while (ev->time() < end_time) { + while (ev && ev->time() < end_time) { Event* const next = (Event*)ev->next(); // Process audio thread notifications up until this event's time @@ -83,14 +84,18 @@ PostProcessor::process() ev->post_process(); delete ev; - if (ev == tail || (next && next->time() >= end_time)) { - // Reached end, update _head - _head = next; - break; - } - ev = next; } + + // Since _head was not NULL, we know it hasn't been changed since + _head = ev; + + /* If next is NULL, then _tail may now be invalid. However, it would cause + a race to reset _tail here. Instead, append() checks only _head for + emptiness, and resets the tail appropriately. */ + + // Process remaining audio thread notifications until end + _engine.process_context().emit_notifications(end_time); } } // namespace Server diff --git a/src/server/PreProcessor.cpp b/src/server/PreProcessor.cpp index aa4f0b06..f786ca10 100644 --- a/src/server/PreProcessor.cpp +++ b/src/server/PreProcessor.cpp @@ -56,6 +56,8 @@ PreProcessor::event(Event* const ev) assert(!ev->is_prepared()); assert(!ev->next()); + /* Note that tail is only used here, not in process(). The head must be + checked first here, since if it is NULL the tail pointer is junk. */ Event* const head = _head.load(); if (!head) { _head = ev; @@ -105,9 +107,9 @@ PreProcessor::process(ProcessContext& context, PostProcessor& dest, size_t limit // Since _head was not NULL, we know it hasn't been changed since _head = next; - /* If next is NULL, then _tail may now be invalid. However, in this - case _head is also NULL so event() will not read _tail. Since it - could cause a race with event(), _tail is not set to NULL here. */ + /* If next is NULL, then _tail may now be invalid. However, it would cause + a race to reset _tail here. Instead, append() checks only _head for + emptiness, and resets the tail appropriately. */ } return n_processed; -- cgit v1.2.1