summaryrefslogtreecommitdiffstats
path: root/src/server/Task.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/Task.hpp')
-rw-r--r--src/server/Task.hpp120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/server/Task.hpp b/src/server/Task.hpp
new file mode 100644
index 00000000..97a6101c
--- /dev/null
+++ b/src/server/Task.hpp
@@ -0,0 +1,120 @@
+/*
+ This file is part of Ingen.
+ Copyright 2007-2017 David Robillard <http://drobilla.net/>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef INGEN_ENGINE_TASK_HPP
+#define INGEN_ENGINE_TASK_HPP
+
+#include <atomic>
+#include <cassert>
+#include <deque>
+#include <functional>
+#include <memory>
+#include <ostream>
+
+namespace ingen {
+namespace server {
+
+class BlockImpl;
+class RunContext;
+
+class Task {
+public:
+ enum class Mode {
+ SINGLE, ///< Single block to run
+ SEQUENTIAL, ///< Elements must be run sequentially in order
+ PARALLEL ///< Elements may be run in any order in parallel
+ };
+
+ Task(Mode mode, BlockImpl* block = nullptr)
+ : _block(block)
+ , _mode(mode)
+ , _done_end(0)
+ , _next(0)
+ , _done(false)
+ {
+ assert(!(mode == Mode::SINGLE && !block));
+ }
+
+ Task(Task&& task)
+ : _children(std::move(task._children))
+ , _block(task._block)
+ , _mode(task._mode)
+ , _done_end(task._done_end)
+ , _next(task._next.load())
+ , _done(task._done.load())
+ {}
+
+ Task& operator=(Task&& task)
+ {
+ _children = std::move(task._children);
+ _block = task._block;
+ _mode = task._mode;
+ _done_end = task._done_end;
+ _next = task._next.load();
+ _done = task._done.load();
+ return *this;
+ }
+
+ /** Run task in the given context. */
+ void run(RunContext& context);
+
+ /** Pretty print task to the given stream (recursively). */
+ void dump(std::function<void (const std::string&)> sink, unsigned indent, bool first) const;
+
+ /** Return true iff this is an empty task. */
+ bool empty() const { return _mode != Mode::SINGLE && _children.empty(); }
+
+ /** Simplify task expression. */
+ static std::unique_ptr<Task> simplify(std::unique_ptr<Task>&& task);
+
+ /** Steal a child task from this task (succeeds for PARALLEL only). */
+ Task* steal(RunContext& context);
+
+ /** Prepend a child to this task. */
+ void push_front(Task&& task) {
+ _children.emplace_front(std::unique_ptr<Task>(new Task(std::move(task))));
+ }
+
+ Mode mode() const { return _mode; }
+ BlockImpl* block() const { return _block; }
+ bool done() const { return _done; }
+
+ void set_done(bool done) { _done = done; }
+
+private:
+ typedef std::deque<std::unique_ptr<Task>> Children;
+
+ Task(const Task&) = delete;
+ Task& operator=(const Task&) = delete;
+
+ Task* get_task(RunContext& context);
+
+ void append(std::unique_ptr<Task>&& t) {
+ _children.emplace_back(std::move(t));
+ }
+
+ Children _children; ///< Vector of child tasks
+ BlockImpl* _block; ///< Used for SINGLE only
+ Mode _mode; ///< Execution mode
+ unsigned _done_end; ///< Index of rightmost done sub-task
+ std::atomic<unsigned> _next; ///< Index of next sub-task
+ std::atomic<bool> _done; ///< Completion phase
+};
+
+} // namespace server
+} // namespace ingen
+
+#endif // INGEN_ENGINE_TASK_HPP