/*
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_MESSAGECONTEXT_HPP
#define INGEN_ENGINE_MESSAGECONTEXT_HPP
#include
#include
#include "raul/Thread.hpp"
#include "raul/Semaphore.hpp"
#include "raul/AtomicPtr.hpp"
#include "lv2/lv2plug.in/ns/ext/atom/atom.h"
#include "Context.hpp"
#include "ProcessContext.hpp"
#include "ThreadManager.hpp"
namespace Ingen {
namespace Server {
class NodeImpl;
/** Context of a work() call.
*
* The message context is a non-hard-realtime thread used to execute things
* that can take too long to execute in an audio thread, and do sloppy timed
* event propagation and scheduling.
*
* \ingroup engine
*/
class MessageContext : public Context, public Raul::Thread
{
public:
explicit MessageContext(Engine& engine)
: Context(engine, MESSAGE)
, Raul::Thread("MessageContext")
, _sem(0)
, _requests(engine.event_queue_size())
, _end_time(0)
{
Thread::set_context(THREAD_MESSAGE);
}
/** Schedule a message context run at a certain time.
* Safe to call from either process thread or pre-process thread.
*/
void run(NodeImpl* node, FrameTime time);
protected:
struct Request {
Request(FrameTime t=0, NodeImpl* n=0) : time(t), node(n) {}
FrameTime time;
NodeImpl* node;
};
public:
/** Signal the end of a cycle that has produced messages.
* AUDIO THREAD ONLY.
*/
inline void signal(ProcessContext& context) {
ThreadManager::assert_thread(THREAD_PROCESS);
const Request cycle_end_request(context.end(), NULL);
_requests.write(sizeof(Request), &cycle_end_request);
_sem.post();
}
/** Return true iff requests are pending. Safe from any thread. */
inline bool has_requests() const {
return _requests.read_space() >= sizeof(Request);
}
protected:
/** Thread run method (wait for and execute requests from process thread */
void _run();
/** Execute a request (possibly enqueueing more requests) */
void execute(const Request& req);
Raul::Semaphore _sem;
Raul::RingBuffer _requests;
Glib::Mutex _mutex;
Glib::Cond _cond;
Request _non_rt_request;
struct RequestEarlier {
bool operator()(const Request& r1, const Request& r2) {
return r1.time < r2.time;
}
};
typedef std::set Queue;
Queue _queue;
FrameTime _end_time;
};
} // namespace Server
} // namespace Ingen
#endif // INGEN_ENGINE_MESSAGECONTEXT_HPP