From df363a4fb3057253c1530941176cac49a7ffd409 Mon Sep 17 00:00:00 2001 From: Tim Mayberry Date: Wed, 14 Aug 2013 20:30:09 +1000 Subject: Add AudioBackendThread class to support different thread type on windows --- libs/ardour/ardour/audio_backend.h | 8 ++++-- libs/ardour/ardour/audio_backend_thread.h | 32 +++++++++++++++++++++ libs/ardour/ardour/audioengine.h | 9 ++++-- libs/ardour/ardour/graph.h | 6 ++-- libs/ardour/ardour/types.h | 10 ------- libs/ardour/audioengine.cc | 19 ++++++++---- libs/ardour/graph.cc | 21 ++++++-------- libs/backends/jack/jack_audiobackend.cc | 48 +++++++++++++++++++++++++++---- libs/backends/jack/jack_audiobackend.h | 5 ++-- 9 files changed, 115 insertions(+), 43 deletions(-) create mode 100644 libs/ardour/ardour/audio_backend_thread.h diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 9052acd530..3d65af481d 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -399,13 +399,17 @@ class AudioBackend : public PortEngine { * stacksize. The thread will begin executing @param func, and will exit * when that function returns. */ - virtual int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize) = 0; + virtual int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize) = 0; /** Wait for the thread specified by @param thread to exit. * * Return zero on success, non-zero on failure. */ - virtual int wait_for_process_thread_exit (AudioBackendNativeThread thread) = 0; + virtual int join_process_thread (AudioBackendThread* thread) = 0; + + /** Return true if execution context is in a backend thread + */ + virtual bool in_process_thread () = 0; virtual void update_latencies () = 0; diff --git a/libs/ardour/ardour/audio_backend_thread.h b/libs/ardour/ardour/audio_backend_thread.h new file mode 100644 index 0000000000..90efecbc94 --- /dev/null +++ b/libs/ardour/ardour/audio_backend_thread.h @@ -0,0 +1,32 @@ +/* + 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 diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 201d960479..82364ca191 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -58,6 +58,7 @@ class Session; class ProcessThread; class AudioBackend; class AudioBackendInfo; +class AudioBackendThread; class AudioEngine : public SessionHandlePtr, public PortManager { @@ -100,8 +101,12 @@ public: pframes_t sample_time_at_cycle_start (); pframes_t samples_since_cycle_start (); bool get_sync_offset (pframes_t& offset) const; - int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize); - int wait_for_process_thread_exit (AudioBackendNativeThread); + + int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); + int join_process_thread (AudioBackendThread*); + + bool in_process_thread (); + bool is_realtime() const; bool connected() const; diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h index 08af6fb721..ed9e22de31 100644 --- a/libs/ardour/ardour/graph.h +++ b/libs/ardour/ardour/graph.h @@ -31,8 +31,6 @@ #include #include -#include - #include "pbd/semutils.h" #include "ardour/types.h" @@ -49,6 +47,8 @@ class Route; class Session; class GraphEdges; +class AudioBackendThread; + typedef boost::shared_ptr node_ptr_t; typedef std::list< node_ptr_t > node_list_t; @@ -93,7 +93,7 @@ protected: virtual void session_going_away (); private: - std::list _thread_list; + std::list _thread_list; volatile bool _quit_threads; void reset_thread_list (); diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 526a71c58b..ee43d1f30f 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -615,16 +615,6 @@ namespace ARDOUR { uint32_t max; //< samples }; -/* PLATFORM SPECIFIC #ifdef's here */ - - /** Define the native thread type used on the platform */ - typedef pthread_t AudioBackendNativeThread; - static inline bool self_thread_equal (AudioBackendNativeThread thr) { - return pthread_equal (thr, pthread_self()); - } - -/* PLATFORM SPECIFIC #endif's here */ - } // namespace ARDOUR diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 465f88de56..38e9ad0b86 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -826,21 +826,30 @@ AudioEngine::get_sync_offset (pframes_t& offset) const } int -AudioEngine::create_process_thread (boost::function func, AudioBackendNativeThread* thr, size_t stacksize) +AudioEngine::create_process_thread (boost::function func, AudioBackendThread* thread, size_t stacksize) { if (!_backend) { return -1; } - return _backend->create_process_thread (func, thr, stacksize); + return _backend->create_process_thread (func, thread, stacksize); } int -AudioEngine::wait_for_process_thread_exit (AudioBackendNativeThread thr) +AudioEngine::join_process_thread (AudioBackendThread* thr) { if (!_backend) { - return 0; + return -1; + } + return _backend->join_process_thread (thr); +} + +bool +AudioEngine::in_process_thread () +{ + if (!_backend) { + return false; } - return _backend->wait_for_process_thread_exit (thr); + return _backend->in_process_thread (); } int diff --git a/libs/ardour/graph.cc b/libs/ardour/graph.cc index c8e374cddc..8b3d24031b 100644 --- a/libs/ardour/graph.cc +++ b/libs/ardour/graph.cc @@ -101,24 +101,24 @@ Graph::reset_thread_list () } Glib::Threads::Mutex::Lock lm (_session.engine().process_lock()); - AudioBackendNativeThread a_thread; + AudioBackendThread* backend_thread; if (!_thread_list.empty()) { drop_threads (); } - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), &a_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::main_thread, this), backend_thread, 100000) != 0) { throw failed_constructor (); } - _thread_list.push_back (a_thread); + _thread_list.push_back (backend_thread); for (uint32_t i = 1; i < num_threads; ++i) { - if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), &a_thread, 100000) != 0) { + if (AudioEngine::instance()->create_process_thread (boost::bind (&Graph::helper_thread, this), backend_thread, 100000) != 0) { throw failed_constructor (); } - _thread_list.push_back (a_thread); + _thread_list.push_back (backend_thread); } } @@ -146,8 +146,8 @@ Graph::drop_threads () _callback_start_sem.signal (); - for (list::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { - AudioEngine::instance()->wait_for_process_thread_exit (*i); + for (list::iterator i = _thread_list.begin(); i != _thread_list.end(); ++i) { + AudioEngine::instance()->join_process_thread (*i); } _thread_list.clear (); @@ -583,10 +583,5 @@ Graph::process_one_route (Route* route) bool Graph::in_process_thread () const { - for (list::const_iterator i = _thread_list.begin (); i != _thread_list.end(); ++i) { - if (self_thread_equal (*i)) { - return true; - } - } - return false; + return AudioEngine::instance()->in_process_thread (); } diff --git a/libs/backends/jack/jack_audiobackend.cc b/libs/backends/jack/jack_audiobackend.cc index c6a523f4d2..cd4874e85a 100644 --- a/libs/backends/jack/jack_audiobackend.cc +++ b/libs/backends/jack/jack_audiobackend.cc @@ -33,6 +33,7 @@ #include "ardour/audioengine.h" #include "ardour/session.h" #include "ardour/types.h" +#include "ardour/audio_backend_thread.h" #include "jack_audiobackend.h" #include "jack_connection.h" @@ -45,6 +46,17 @@ using namespace PBD; using std::string; 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_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } @@ -825,25 +837,49 @@ JACKAudioBackend::_latency_callback (jack_latency_callback_mode_t mode, void* ar } int -JACKAudioBackend::create_process_thread (boost::function f, pthread_t* thread, size_t stacksize) +JACKAudioBackend::create_process_thread (boost::function f, AudioBackendThread* backend_thread, size_t stacksize) { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + + jack_native_thread_t thread_id; ThreadData* td = new ThreadData (this, f, stacksize); - if (jack_client_create_thread (_priv_jack, thread, 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)) { return -1; } - return 0; + backend_thread = new JACKAudioBackendThread(thread_id); + return 0; } int -JACKAudioBackend::wait_for_process_thread_exit (AudioBackendNativeThread thr) +JACKAudioBackend::join_process_thread (AudioBackendThread* backend_thread) { + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + + JACKAudioBackendThread * jack_thread = dynamic_cast(backend_thread); + int ret = 0; + +#if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS) + if (jack_client_stop_thread (_priv_jack, jack_thread->thread_id) != 0) { + error << "AudioEngine: cannot stop process thread" << endmsg; + ret = -1; + } +#else void* status; - /* this doesn't actively try to stop the thread, it just waits till it exits */ - return pthread_join (thr, &status); + ret = pthread_join (jack_thread->thread_id, &status); +#endif + delete jack_thread; + return ret; +} + +bool +JACKAudioBackend::in_process_thread () +{ + // XXX TODO + + return false; } void* diff --git a/libs/backends/jack/jack_audiobackend.h b/libs/backends/jack/jack_audiobackend.h index 9ab545f3ee..822dc71053 100644 --- a/libs/backends/jack/jack_audiobackend.h +++ b/libs/backends/jack/jack_audiobackend.h @@ -103,8 +103,9 @@ class JACKAudioBackend : public AudioBackend { size_t raw_buffer_size (DataType t); - int create_process_thread (boost::function func, AudioBackendNativeThread*, size_t stacksize); - int wait_for_process_thread_exit (AudioBackendNativeThread); + int create_process_thread (boost::function func, AudioBackendThread*, size_t stacksize); + int join_process_thread (AudioBackendThread*); + bool in_process_thread (); void transport_start (); void transport_stop (); -- cgit v1.2.3