summaryrefslogtreecommitdiff
path: root/libs/ardour/ardour/worker.h
blob: 6e1a7c91f1849f6cdb011fac5621987acd500194 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
  Copyright (C) 2012-2016 Paul Davis
  Author: David Robillard

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifndef __ardour_worker_h__
#define __ardour_worker_h__

#include <stdint.h>

#include <glibmm/threads.h>

#include "pbd/ringbuffer.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 LIBARDOUR_API Workee {
public:
	virtual ~Workee() {}

	/**
	   Do some work in the worker thread.
	*/
	virtual int work(Worker& worker, uint32_t size, const void* data) = 0;

	/**
	   Handle a response from the worker thread in the audio thread.
	*/
	virtual int work_response(uint32_t size, const void* data) = 0;
};

/**
   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 LIBARDOUR_API Worker
{
public:
	Worker(Workee* workee, uint32_t ring_size, bool threaded=true);
	~Worker();

	/**
	   Schedule work (audio thread).
	   @return false on error.
	*/
	bool schedule(uint32_t size, const void* data);

	/**
	   Respond from work (worker thread).
	   @return false on error.
	*/
	bool respond(uint32_t size, const void* data);

	/**
	   Emit any pending responses (audio thread).
	*/
	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.

	   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

#endif  /* __ardour_worker_h__ */