Move processing thread list from ARDOUR::Graph into AudioBackend implementation

This commit is contained in:
Tim Mayberry 2013-10-02 19:40:48 +10:00
parent df363a4fb3
commit 53ad2d187f
8 changed files with 63 additions and 88 deletions

View file

@ -399,18 +399,26 @@ class AudioBackend : public PortEngine {
* stacksize. The thread will begin executing @param func, and will exit * stacksize. The thread will begin executing @param func, and will exit
* when that function returns. * when that function returns.
*/ */
virtual int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize) = 0; virtual int create_process_thread (boost::function<void()> func) = 0;
/** Wait for the thread specified by @param thread to exit. /** Wait for all processing threads to exit.
* *
* Return zero on success, non-zero on failure. * Return zero on success, non-zero on failure.
*/ */
virtual int join_process_thread (AudioBackendThread* thread) = 0; virtual int join_process_threads () = 0;
/** Return true if execution context is in a backend thread /** Return true if execution context is in a backend thread
*/ */
virtual bool in_process_thread () = 0; virtual bool in_process_thread () = 0;
/** Return the minimum stack size of audio threads in bytes
*/
static size_t thread_stack_size () { return 100000; }
/** Return number of processing threads
*/
virtual uint32_t process_thread_count () = 0;
virtual void update_latencies () = 0; virtual void update_latencies () = 0;
protected: protected:

View file

@ -1,32 +0,0 @@
/*
Copyright (C) 2013 Paul Davis
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.
*/
namespace ARDOUR {
class AudioBackendThread
{
public:
AudioBackendThread () { }
virtual ~AudioBackendThread () { }
};
} // namespace ARDOUR

View file

@ -58,7 +58,6 @@ class Session;
class ProcessThread; class ProcessThread;
class AudioBackend; class AudioBackend;
class AudioBackendInfo; class AudioBackendInfo;
class AudioBackendThread;
class AudioEngine : public SessionHandlePtr, public PortManager class AudioEngine : public SessionHandlePtr, public PortManager
{ {
@ -102,10 +101,10 @@ public:
pframes_t samples_since_cycle_start (); pframes_t samples_since_cycle_start ();
bool get_sync_offset (pframes_t& offset) const; bool get_sync_offset (pframes_t& offset) const;
int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize); int create_process_thread (boost::function<void()> func);
int join_process_thread (AudioBackendThread*); int join_process_threads ();
bool in_process_thread (); bool in_process_thread ();
uint32_t process_thread_count ();
bool is_realtime() const; bool is_realtime() const;
bool connected() const; bool connected() const;

View file

@ -47,8 +47,6 @@ class Route;
class Session; class Session;
class GraphEdges; class GraphEdges;
class AudioBackendThread;
typedef boost::shared_ptr<GraphNode> node_ptr_t; typedef boost::shared_ptr<GraphNode> node_ptr_t;
typedef std::list< node_ptr_t > node_list_t; typedef std::list< node_ptr_t > node_list_t;
@ -59,8 +57,6 @@ class Graph : public SessionHandleRef
public: public:
Graph (Session & session); Graph (Session & session);
uint32_t threads_in_use () const { return _thread_list.size(); }
void prep(); void prep();
void trigger (GraphNode * n); void trigger (GraphNode * n);
void rechain (boost::shared_ptr<RouteList>, GraphEdges const &); void rechain (boost::shared_ptr<RouteList>, GraphEdges const &);
@ -93,7 +89,6 @@ protected:
virtual void session_going_away (); virtual void session_going_away ();
private: private:
std::list<AudioBackendThread*> _thread_list;
volatile bool _quit_threads; volatile bool _quit_threads;
void reset_thread_list (); void reset_thread_list ();

View file

@ -826,21 +826,21 @@ AudioEngine::get_sync_offset (pframes_t& offset) const
} }
int int
AudioEngine::create_process_thread (boost::function<void()> func, AudioBackendThread* thread, size_t stacksize) AudioEngine::create_process_thread (boost::function<void()> func)
{ {
if (!_backend) { if (!_backend) {
return -1; return -1;
} }
return _backend->create_process_thread (func, thread, stacksize); return _backend->create_process_thread (func);
} }
int int
AudioEngine::join_process_thread (AudioBackendThread* thr) AudioEngine::join_process_threads ()
{ {
if (!_backend) { if (!_backend) {
return -1; return -1;
} }
return _backend->join_process_thread (thr); return _backend->join_process_threads ();
} }
bool bool
@ -852,6 +852,15 @@ AudioEngine::in_process_thread ()
return _backend->in_process_thread (); return _backend->in_process_thread ();
} }
uint32_t
AudioEngine::process_thread_count ()
{
if (!_backend) {
return 0;
}
return _backend->process_thread_count ();
}
int int
AudioEngine::set_device_name (const std::string& name) AudioEngine::set_device_name (const std::string& name)
{ {

View file

@ -96,29 +96,24 @@ Graph::reset_thread_list ()
number of threads. number of threads.
*/ */
if (_thread_list.size() == num_threads) { if (AudioEngine::instance()->process_thread_count() == num_threads) {
return; return;
} }
Glib::Threads::Mutex::Lock lm (_session.engine().process_lock()); Glib::Threads::Mutex::Lock lm (_session.engine().process_lock());
AudioBackendThread* backend_thread;
if (!_thread_list.empty()) { if (AudioEngine::instance()->process_thread_count() != 0) {
drop_threads (); drop_threads ();
} }
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), backend_thread, 100000) != 0) { if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this)) != 0) {
throw failed_constructor (); throw failed_constructor ();
} }
_thread_list.push_back (backend_thread);
for (uint32_t i = 1; i < num_threads; ++i) { for (uint32_t i = 1; i < num_threads; ++i) {
if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), backend_thread, 100000) != 0) { if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this))) {
throw failed_constructor (); throw failed_constructor ();
} }
_thread_list.push_back (backend_thread);
} }
} }
@ -140,17 +135,15 @@ Graph::drop_threads ()
{ {
_quit_threads = true; _quit_threads = true;
for (unsigned int i=0; i< _thread_list.size(); i++) { uint32_t thread_count = AudioEngine::instance()->process_thread_count ();
for (unsigned int i=0; i < thread_count; i++) {
_execution_sem.signal (); _execution_sem.signal ();
} }
_callback_start_sem.signal (); _callback_start_sem.signal ();
for (list<AudioBackendThread*>::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { AudioEngine::instance()->join_process_threads ();
AudioEngine::instance()->join_process_thread (*i);
}
_thread_list.clear ();
_execution_tokens = 0; _execution_tokens = 0;

View file

@ -33,7 +33,6 @@
#include "ardour/audioengine.h" #include "ardour/audioengine.h"
#include "ardour/session.h" #include "ardour/session.h"
#include "ardour/types.h" #include "ardour/types.h"
#include "ardour/audio_backend_thread.h"
#include "jack_audiobackend.h" #include "jack_audiobackend.h"
#include "jack_connection.h" #include "jack_connection.h"
@ -46,16 +45,6 @@ using namespace PBD;
using std::string; using std::string;
using std::vector; using std::vector;
class JACKAudioBackendThread : public AudioBackendThread
{
public:
JACKAudioBackendThread (jack_native_thread_t id)
: thread_id(id) { }
jack_native_thread_t thread_id;
};
#define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
#define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
@ -837,40 +826,45 @@ JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* ar
} }
int int
JACKAudioBackend::create_process_thread (boost::function<void()> f, AudioBackendThread* backend_thread, size_t stacksize) JACKAudioBackend::create_process_thread (boost::function<void()> f)
{ {
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
jack_native_thread_t thread_id; jack_native_thread_t thread_id;
ThreadData* td = new ThreadData (this, f, stacksize); ThreadData* td = new ThreadData (this, f, thread_stack_size());
if (jack_client_create_thread (_priv_jack, &thread_id, jack_client_real_time_priority (_priv_jack), if (jack_client_create_thread (_priv_jack, &thread_id, jack_client_real_time_priority (_priv_jack),
jack_is_realtime (_priv_jack), _start_process_thread, td)) { jack_is_realtime (_priv_jack), _start_process_thread, td)) {
return -1; return -1;
} }
backend_thread = new JACKAudioBackendThread(thread_id); _jack_threads.push_back(thread_id);
return 0; return 0;
} }
int int
JACKAudioBackend::join_process_thread (AudioBackendThread* backend_thread) JACKAudioBackend::join_process_threads ()
{ {
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
JACKAudioBackendThread * jack_thread = dynamic_cast<JACKAudioBackendThread*>(backend_thread);
int ret = 0; int ret = 0;
for (std::vector<jack_native_thread_t>::const_iterator i = _jack_threads.begin ();
i != _jack_threads.end(); i++) {
#if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS) #if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS)
if (jack_client_stop_thread (_priv_jack, jack_thread->thread_id) != 0) { if (jack_client_stop_thread (_priv_jack, *i) != 0) {
error << "AudioEngine: cannot stop process thread" << endmsg;
ret = -1;
}
#else #else
void* status; void* status;
ret = pthread_join (jack_thread->thread_id, &status); if (pthread_join (*i, &status) != 0) {
#endif #endif
delete jack_thread; error << "AudioEngine: cannot stop process thread" << endmsg;
ret += -1;
}
}
_jack_threads.clear();
return ret; return ret;
} }
@ -882,6 +876,12 @@ JACKAudioBackend::in_process_thread ()
return false; return false;
} }
uint32_t
JACKAudioBackend::process_thread_count ()
{
return _jack_threads.size();
}
void* void*
JACKAudioBackend::_start_process_thread (void* arg) JACKAudioBackend::_start_process_thread (void* arg)
{ {

View file

@ -103,9 +103,10 @@ class JACKAudioBackend : public AudioBackend {
size_t raw_buffer_size (DataType t); size_t raw_buffer_size (DataType t);
int create_process_thread (boost::function<void()> func, AudioBackendThread*, size_t stacksize); int create_process_thread (boost::function<void()> func);
int join_process_thread (AudioBackendThread*); int join_process_threads ();
bool in_process_thread (); bool in_process_thread ();
uint32_t process_thread_count ();
void transport_start (); void transport_start ();
void transport_stop (); void transport_stop ();
@ -185,6 +186,8 @@ class JACKAudioBackend : public AudioBackend {
bool _freewheeling; bool _freewheeling;
std::map<DataType,size_t> _raw_buffer_sizes; std::map<DataType,size_t> _raw_buffer_sizes;
std::vector<jack_native_thread_t> _jack_threads;
static int _xrun_callback (void *arg); static int _xrun_callback (void *arg);
static void* _process_thread (void *arg); static void* _process_thread (void *arg);
static int _sample_rate_callback (pframes_t nframes, void *arg); static int _sample_rate_callback (pframes_t nframes, void *arg);