Fix typos in AU channel-count calc
[ardour.git] / libs / ardour / rt_tasklist.cc
1 /*
2  * Copyright (C) 2017-2018 Robin Gareus <robin@gareus.org>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19
20 #include "pbd/pthread_utils.h"
21
22 #include "ardour/audioengine.h"
23 #include "ardour/debug.h"
24 #include "ardour/rt_tasklist.h"
25 #include "ardour/utils.h"
26
27 #include "pbd/i18n.h"
28
29 using namespace ARDOUR;
30
31 RTTaskList::RTTaskList ()
32         : _threads_active (0)
33         , _task_run_sem ("rt_task_run", 0)
34         , _task_end_sem ("rt_task_done", 0)
35 {
36         reset_thread_list ();
37 }
38
39 RTTaskList::~RTTaskList ()
40 {
41         drop_threads ();
42 }
43
44 void
45 RTTaskList::drop_threads ()
46 {
47         Glib::Threads::Mutex::Lock pm (_process_mutex);
48         g_atomic_int_set (&_threads_active, 0);
49
50         uint32_t nt = _threads.size ();
51         for (uint32_t i = 0; i < nt; ++i) {
52                 _task_run_sem.signal ();
53         }
54         for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i) {
55                 pthread_join (*i, NULL);
56         }
57         _threads.clear ();
58         _task_run_sem.reset ();
59         _task_end_sem.reset ();
60 }
61
62 /*static*/ void*
63 RTTaskList::_thread_run (void *arg)
64 {
65         RTTaskList *d = static_cast<RTTaskList *>(arg);
66         d->run ();
67         pthread_exit (0);
68         return 0;
69 }
70
71 void
72 RTTaskList::reset_thread_list ()
73 {
74         drop_threads ();
75
76         const uint32_t num_threads = how_many_dsp_threads ();
77         if (num_threads < 2) {
78                 return;
79         }
80
81         Glib::Threads::Mutex::Lock pm (_process_mutex);
82
83         g_atomic_int_set (&_threads_active, 1);
84         for (uint32_t i = 0; i < num_threads; ++i) {
85                 pthread_t thread_id;
86                 size_t stacksize = 100000;
87                 if (!AudioEngine::instance()->is_realtime ()
88                     ||
89                     pbd_realtime_pthread_create (PBD_SCHED_FIFO, AudioEngine::instance()->client_real_time_priority(), stacksize, &thread_id, _thread_run, this)) {
90                         pthread_attr_t attr;
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;
95                                 /* NOT REACHED */
96                         }
97                         pthread_attr_destroy (&attr);
98                 }
99                 pbd_mach_set_realtime_policy (thread_id, 5. * 1e-5);
100                 _threads.push_back (thread_id);
101         }
102 }
103
104 void
105 RTTaskList::run ()
106 {
107         Glib::Threads::Mutex::Lock tm (_tasklist_mutex, Glib::Threads::NOT_LOCK);
108         bool wait = true;
109
110         while (true) {
111                 if (wait) {
112                         _task_run_sem.wait ();
113                 }
114
115                 if (0 == g_atomic_int_get (&_threads_active)) {
116                         _task_end_sem.signal ();
117                         break;
118                 }
119
120                 wait = false;
121
122                 boost::function<void ()> to_run;
123                 tm.acquire ();
124                 if (!_tasklist.empty ()) {
125                         to_run = _tasklist.front();
126                         _tasklist.pop_front ();
127                 }
128                 tm.release ();
129
130                 if (!to_run.empty ()) {
131                         to_run ();
132                         continue;
133                 }
134
135                 if (!wait) {
136                         _task_end_sem.signal ();
137                 }
138
139                 wait = true;
140         }
141 }
142
143 void
144 RTTaskList::process (TaskList const& tl)
145 {
146         Glib::Threads::Mutex::Lock pm (_process_mutex);
147         Glib::Threads::Mutex::Lock tm (_tasklist_mutex, Glib::Threads::NOT_LOCK);
148
149         tm.acquire ();
150         _tasklist = tl;
151         tm.release ();
152
153         process_tasklist ();
154
155         tm.acquire ();
156         _tasklist.clear ();
157         tm.release ();
158 }
159
160 void
161 RTTaskList::process_tasklist ()
162 {
163 //      if (0 == g_atomic_int_get (&_threads_active) || _threads.size () == 0) {
164
165                 for (TaskList::iterator i = _tasklist.begin (); i != _tasklist.end(); ++i) {
166                         (*i)();
167                 }
168                 return;
169 //      }
170
171         uint32_t nt = std::min (_threads.size (), _tasklist.size ());
172
173         for (uint32_t i = 0; i < nt; ++i) {
174                 _task_run_sem.signal ();
175         }
176         for (uint32_t i = 0; i < nt; ++i) {
177                 _task_end_sem.wait ();
178         }
179 }