2 * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "pbd/pthread_utils.h"
22 #include "ardour/audioengine.h"
23 #include "ardour/debug.h"
24 #include "ardour/rt_tasklist.h"
25 #include "ardour/utils.h"
29 using namespace ARDOUR;
31 RTTaskList::RTTaskList ()
33 , _task_run_sem ("rt_task_run", 0)
34 , _task_end_sem ("rt_task_done", 0)
39 RTTaskList::~RTTaskList ()
45 RTTaskList::drop_threads ()
47 Glib::Threads::Mutex::Lock pm (_process_mutex);
48 g_atomic_int_set (&_threads_active, 0);
50 uint32_t nt = _threads.size ();
51 for (uint32_t i = 0; i < nt; ++i) {
52 _task_run_sem.signal ();
54 for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i) {
55 pthread_join (*i, NULL);
58 _task_run_sem.reset ();
59 _task_end_sem.reset ();
63 RTTaskList::_thread_run (void *arg)
65 RTTaskList *d = static_cast<RTTaskList *>(arg);
72 RTTaskList::reset_thread_list ()
76 const uint32_t num_threads = how_many_dsp_threads ();
77 if (num_threads < 2) {
81 Glib::Threads::Mutex::Lock pm (_process_mutex);
83 g_atomic_int_set (&_threads_active, 1);
84 for (uint32_t i = 0; i < num_threads; ++i) {
86 size_t stacksize = 100000;
87 if (!AudioEngine::instance()->is_realtime ()
89 pbd_realtime_pthread_create (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority(), stacksize, &thread_id, _thread_run, this)) {
91 pthread_attr_init (&attr);
92 pthread_attr_setstacksize (&attr, stacksize);
93 if (pthread_create (&thread_id, &attr, _thread_run, this)) {
94 PBD::fatal << _("Cannot create thread for TaskList!") << endmsg;
97 pthread_attr_destroy (&attr);
99 pbd_mach_set_realtime_policy (thread_id, 5. * 1e-5);
100 _threads.push_back (thread_id);
107 Glib::Threads::Mutex::Lock tm (_tasklist_mutex, Glib::Threads::NOT_LOCK);
112 _task_run_sem.wait ();
115 if (0 == g_atomic_int_get (&_threads_active)) {
116 _task_end_sem.signal ();
122 boost::function<void ()> to_run;
124 if (!_tasklist.empty ()) {
125 to_run = _tasklist.front();
126 _tasklist.pop_front ();
130 if (!to_run.empty ()) {
136 _task_end_sem.signal ();
144 RTTaskList::process (TaskList const& tl)
146 Glib::Threads::Mutex::Lock pm (_process_mutex);
147 Glib::Threads::Mutex::Lock tm (_tasklist_mutex, Glib::Threads::NOT_LOCK);
161 RTTaskList::process_tasklist ()
163 // if (0 == g_atomic_int_get (&_threads_active) || _threads.size () == 0) {
165 for (TaskList::iterator i = _tasklist.begin (); i != _tasklist.end(); ++i) {
171 uint32_t nt = std::min (_threads.size (), _tasklist.size ());
173 for (uint32_t i = 0; i < nt; ++i) {
174 _task_run_sem.signal ();
176 for (uint32_t i = 0; i < nt; ++i) {
177 _task_end_sem.wait ();