/*
- Copyright (C) 2012 Paul Davis
+ Copyright (C) 2012-2016 Paul Davis
Author: David Robillard
This program is free software; you can redistribute it and/or modify
#include <stdint.h>
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include "pbd/ringbuffer.h"
-#include "pbd/semaphore.h"
+#include "pbd/semutils.h"
+
+#include "ardour/libardour_visibility.h"
namespace ARDOUR {
+class Worker;
+
/**
An object that needs to schedule non-RT work in the audio thread.
*/
-class Workee {
+class LIBARDOUR_API Workee {
public:
virtual ~Workee() {}
/**
Do some work in the worker thread.
*/
- virtual void work(uint32_t size, const void* data) = 0;
+ virtual int work(Worker& worker, uint32_t size, const void* data) = 0;
/**
Handle a response from the worker thread in the audio thread.
*/
- virtual void work_response(uint32_t size, const void* data) = 0;
+ virtual int work_response(uint32_t size, const void* data) = 0;
};
/**
- A worker thread for non-realtime tasks scheduled in the audio thread.
+ A worker for non-realtime tasks scheduled from another thread.
+
+ A worker may be a separate thread that runs to execute scheduled work
+ asynchronously, or unthreaded, in which case work is executed immediately
+ upon scheduling by the calling thread.
*/
-class Worker
+class LIBARDOUR_API Worker
{
public:
- Worker(Workee* workee, uint32_t ring_size);
+ Worker(Workee* workee, uint32_t ring_size, bool threaded=true);
~Worker();
/**
*/
void emit_responses();
+ /**
+ Enable or disable synchronous execution.
+
+ If enabled, all work is performed immediately in schedule() regardless
+ of whether or not the worker is threaded. This is used for exporting,
+ where we want to temporarily execute all work synchronously but the
+ worker is typically used threaded for live rolling.
+ */
+ void set_synchronous(bool synchronous) { _synchronous = synchronous; }
+
private:
void run();
+ /**
+ Peek in RB, get size and check if a block of 'size' is available.
- Workee* _workee;
- Glib::Thread* _thread;
- RingBuffer<uint8_t>* _requests;
- RingBuffer<uint8_t>* _responses;
- uint8_t* _response;
- PBD::Semaphore _sem;
- bool _exit;
+ Handle the unlikley edge-case, if we're called in between the
+ responder writing 'size' and 'data'.
+
+ @param rb the ringbuffer to check
+ @return true if the message is complete, false otherwise
+ */
+ bool verify_message_completeness(RingBuffer<uint8_t>* rb);
+
+ Workee* _workee;
+ RingBuffer<uint8_t>* _requests;
+ RingBuffer<uint8_t>* _responses;
+ uint8_t* _response;
+ PBD::Semaphore _sem;
+ Glib::Threads::Thread* _thread;
+ bool _exit;
+ bool _synchronous;
};
} // namespace ARDOUR