From e6fa87193fb9ed9672fb346d34bbe093ddcfe814 Mon Sep 17 00:00:00 2001 From: David Robillard Date: Wed, 2 May 2012 23:56:42 +0000 Subject: Separate EventSource interface from EventQueue implementation. git-svn-id: http://svn.drobilla.net/lad/trunk/ingen@4316 a436a847-0d15-0410-975c-d299462d15a1 --- src/server/EventQueue.cpp | 126 +++++++++++++++++++++++++++++++++++++ src/server/EventQueue.hpp | 61 ++++++++++++++++++ src/server/EventSource.cpp | 126 ------------------------------------- src/server/EventSource.hpp | 63 ------------------- src/server/JackDriver.cpp | 1 - src/server/ServerInterfaceImpl.cpp | 4 +- src/server/ServerInterfaceImpl.hpp | 8 +-- src/server/wscript | 2 +- 8 files changed, 194 insertions(+), 197 deletions(-) create mode 100644 src/server/EventQueue.cpp create mode 100644 src/server/EventQueue.hpp delete mode 100644 src/server/EventSource.cpp delete mode 100644 src/server/EventSource.hpp diff --git a/src/server/EventQueue.cpp b/src/server/EventQueue.cpp new file mode 100644 index 00000000..ffafe17a --- /dev/null +++ b/src/server/EventQueue.cpp @@ -0,0 +1,126 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#include "Event.hpp" +#include "EventQueue.hpp" +#include "PostProcessor.hpp" +#include "ProcessContext.hpp" +#include "ThreadManager.hpp" + +using namespace std; + +namespace Ingen { +namespace Server { + +EventQueue::EventQueue() +{ + Thread::set_context(THREAD_PRE_PROCESS); + set_name("EventQueue"); +} + +EventQueue::~EventQueue() +{ + Thread::stop(); +} + +/** Push an unprepared event onto the queue. + */ +void +EventQueue::push_queued(Event* const ev) +{ + assert(!ev->is_prepared()); + assert(!ev->next()); + + Event* const head = _head.get(); + Event* const tail = _tail.get(); + + if (!head) { + _head = ev; + _tail = ev; + } else { + _tail = ev; + tail->next(ev); + } + + if (!_prepared_back.get()) { + _prepared_back = ev; + } + + whip(); +} + +/** Process all events for a cycle. + * + * Executed events will be pushed to @a dest. + */ +void +EventQueue::process(PostProcessor& dest, ProcessContext& context, bool limit) +{ + ThreadManager::assert_thread(THREAD_PROCESS); + + if (!_head.get()) + return; + + /* Limit the maximum number of queued events to process per cycle. This + makes the process callback (more) realtime-safe by preventing being + choked by events coming in faster than they can be processed. + FIXME: test this and figure out a good value + */ + const size_t MAX_QUEUED_EVENTS = context.nframes() / 32; + + size_t num_events_processed = 0; + + Event* ev = _head.get(); + Event* last = ev; + + while (ev && ev->is_prepared() && ev->time() < context.end()) { + ev->execute(context); + last = ev; + ev = (Event*)ev->next(); + ++num_events_processed; + if (limit && (num_events_processed > MAX_QUEUED_EVENTS)) + break; + } + + if (num_events_processed > 0) { + Event* next = (Event*)last->next(); + last->next(NULL); + assert(!last->next()); + dest.append(_head.get(), last); + _head = next; + if (!next) + _tail = NULL; + } +} + +/** Pre-process a single event */ +void +EventQueue::_whipped() +{ + Event* ev = _prepared_back.get(); + if (!ev) + return; + + assert(!ev->is_prepared()); + ev->pre_process(); + assert(ev->is_prepared()); + + _prepared_back = (Event*)ev->next(); +} + +} // namespace Server +} // namespace Ingen + diff --git a/src/server/EventQueue.hpp b/src/server/EventQueue.hpp new file mode 100644 index 00000000..e1adbd6b --- /dev/null +++ b/src/server/EventQueue.hpp @@ -0,0 +1,61 @@ +/* + This file is part of Ingen. + Copyright 2007-2012 David Robillard + + Ingen is free software: you can redistribute it and/or modify it under the + terms of the GNU Affero General Public License as published by the Free + Software Foundation, either version 3 of the License, or any later version. + + Ingen is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. + + You should have received a copy of the GNU Affero General Public License + along with Ingen. If not, see . +*/ + +#ifndef INGEN_ENGINE_EVENTQUEUE_HPP +#define INGEN_ENGINE_EVENTQUEUE_HPP + +#include "raul/AtomicPtr.hpp" +#include "raul/Slave.hpp" + +#include "EventSource.hpp" + +namespace Ingen { +namespace Server { + +class Event; +class PostProcessor; +class ProcessContext; + +/** An EventSource which prepares events in its own thread. + */ +class EventQueue : public EventSource + , public Raul::Slave +{ +public: + explicit EventQueue(); + virtual ~EventQueue(); + + void process(PostProcessor& dest, ProcessContext& context, bool limit=true); + + inline bool unprepared_events() const { return _prepared_back.get(); } + inline bool empty() const { return !_head.get(); } + +protected: + void push_queued(Event* const ev); + + virtual void _whipped(); ///< Prepare 1 event + +private: + Raul::AtomicPtr _head; + Raul::AtomicPtr _prepared_back; + Raul::AtomicPtr _tail; +}; + +} // namespace Server +} // namespace Ingen + +#endif // INGEN_ENGINE_EVENTQUEUE_HPP + diff --git a/src/server/EventSource.cpp b/src/server/EventSource.cpp deleted file mode 100644 index a8eb3ec4..00000000 --- a/src/server/EventSource.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#include "EventSource.hpp" -#include "PostProcessor.hpp" -#include "ProcessContext.hpp" -#include "Event.hpp" -#include "ThreadManager.hpp" - -using namespace std; - -namespace Ingen { -namespace Server { - -EventSource::EventSource() -{ - Thread::set_context(THREAD_PRE_PROCESS); - set_name("EventSource"); -} - -EventSource::~EventSource() -{ - Thread::stop(); -} - -/** Push an unprepared event onto the queue. - */ -void -EventSource::push_queued(Event* const ev) -{ - assert(!ev->is_prepared()); - assert(!ev->next()); - - Event* const head = _head.get(); - Event* const tail = _tail.get(); - - if (!head) { - _head = ev; - _tail = ev; - } else { - _tail = ev; - tail->next(ev); - } - - if (!_prepared_back.get()) { - _prepared_back = ev; - } - - whip(); -} - -/** Process all events for a cycle. - * - * Executed events will be pushed to @a dest. - */ -void -EventSource::process(PostProcessor& dest, ProcessContext& context, bool limit) -{ - ThreadManager::assert_thread(THREAD_PROCESS); - - if (!_head.get()) - return; - - /* Limit the maximum number of queued events to process per cycle. This - makes the process callback (more) realtime-safe by preventing being - choked by events coming in faster than they can be processed. - FIXME: test this and figure out a good value - */ - const size_t MAX_QUEUED_EVENTS = context.nframes() / 32; - - size_t num_events_processed = 0; - - Event* ev = _head.get(); - Event* last = ev; - - while (ev && ev->is_prepared() && ev->time() < context.end()) { - ev->execute(context); - last = ev; - ev = (Event*)ev->next(); - ++num_events_processed; - if (limit && (num_events_processed > MAX_QUEUED_EVENTS)) - break; - } - - if (num_events_processed > 0) { - Event* next = (Event*)last->next(); - last->next(NULL); - assert(!last->next()); - dest.append(_head.get(), last); - _head = next; - if (!next) - _tail = NULL; - } -} - -/** Pre-process a single event */ -void -EventSource::_whipped() -{ - Event* ev = _prepared_back.get(); - if (!ev) - return; - - assert(!ev->is_prepared()); - ev->pre_process(); - assert(ev->is_prepared()); - - _prepared_back = (Event*)ev->next(); -} - -} // namespace Server -} // namespace Ingen - diff --git a/src/server/EventSource.hpp b/src/server/EventSource.hpp deleted file mode 100644 index e8619786..00000000 --- a/src/server/EventSource.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - This file is part of Ingen. - Copyright 2007-2012 David Robillard - - Ingen is free software: you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free - Software Foundation, either version 3 of the License, or any later version. - - Ingen is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU Affero General Public License for details. - - You should have received a copy of the GNU Affero General Public License - along with Ingen. If not, see . -*/ - -#ifndef INGEN_ENGINE_EVENTSOURCE_HPP -#define INGEN_ENGINE_EVENTSOURCE_HPP - -#include "raul/AtomicPtr.hpp" -#include "raul/Slave.hpp" - -namespace Ingen { -namespace Server { - -class Event; -class Event; -class PostProcessor; -class ProcessContext; - -/** Source for events to run in the audio thread. - * - * The Driver gets events from an EventSource in the process callback - * (realtime audio thread) and executes them, then they are sent to the - * PostProcessor and finalised (post-processing thread). - */ -class EventSource : public Raul::Slave -{ -public: - explicit EventSource(); - virtual ~EventSource(); - - void process(PostProcessor& dest, ProcessContext& context, bool limit=true); - - inline bool unprepared_events() const { return _prepared_back.get(); } - inline bool empty() const { return !_head.get(); } - -protected: - void push_queued(Event* const ev); - - virtual void _whipped(); ///< Prepare 1 event - -private: - Raul::AtomicPtr _head; - Raul::AtomicPtr _prepared_back; - Raul::AtomicPtr _tail; -}; - -} // namespace Server -} // namespace Ingen - -#endif // INGEN_ENGINE_EVENTSOURCE_HPP - diff --git a/src/server/JackDriver.cpp b/src/server/JackDriver.cpp index 68a2d683..cccaadf1 100644 --- a/src/server/JackDriver.cpp +++ b/src/server/JackDriver.cpp @@ -36,7 +36,6 @@ #include "Engine.hpp" #include "Event.hpp" #include "Event.hpp" -#include "EventSource.hpp" #include "JackDriver.hpp" #include "MessageContext.hpp" #include "PatchImpl.hpp" diff --git a/src/server/ServerInterfaceImpl.cpp b/src/server/ServerInterfaceImpl.cpp index 4c7ed140..492139ed 100644 --- a/src/server/ServerInterfaceImpl.cpp +++ b/src/server/ServerInterfaceImpl.cpp @@ -23,7 +23,7 @@ #include "ClientBroadcaster.hpp" #include "Driver.hpp" #include "Engine.hpp" -#include "EventSource.hpp" +#include "EventQueue.hpp" #include "ServerInterfaceImpl.hpp" #include "events.hpp" @@ -36,7 +36,7 @@ namespace Ingen { namespace Server { ServerInterfaceImpl::ServerInterfaceImpl(Engine& engine) - : EventSource() + : EventQueue() , _request_client(NULL) , _request_id(-1) , _engine(engine) diff --git a/src/server/ServerInterfaceImpl.hpp b/src/server/ServerInterfaceImpl.hpp index 56aea0a3..f34afaae 100644 --- a/src/server/ServerInterfaceImpl.hpp +++ b/src/server/ServerInterfaceImpl.hpp @@ -23,7 +23,7 @@ #include "raul/SharedPtr.hpp" #include "ingen/Interface.hpp" #include "ingen/Resource.hpp" -#include "EventSource.hpp" +#include "EventQueue.hpp" #include "types.hpp" namespace Ingen { @@ -33,15 +33,15 @@ class Engine; /** A queued (preprocessed) event source / interface. * - * This is the bridge between the Interface presented to the client, and - * the EventSource that needs to be presented to the Driver. + * This is both an Interface and an EventSource, calling Interface methods + * will result in events in the EventSource. * * Responses occur through the event mechanism (which notified clients in * event post_process methods) and are related to an event by an integer ID. * If you do not register a request, you have no way of knowing if your calls * are successful. */ -class ServerInterfaceImpl : public EventSource, +class ServerInterfaceImpl : public EventQueue, public Interface { public: diff --git a/src/server/wscript b/src/server/wscript index a5ecbc0f..faaeb38a 100644 --- a/src/server/wscript +++ b/src/server/wscript @@ -13,7 +13,7 @@ def build(bld): Engine.cpp EngineStore.cpp Event.cpp - EventSource.cpp + EventQueue.cpp GraphObjectImpl.cpp InputPort.cpp InternalPlugin.cpp -- cgit v1.2.1