style-guide-ification
[ardour.git] / libs / ardour / graph.cc
1 /*
2   Copyright (C) 2010 Paul Davis
3   Author: Torben Hohn
4
5   This program is free software; you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 2 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #ifdef __linux__
22 #include <unistd.h>
23 #elif defined(__APPLE__) || defined(__FreeBSD__)
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
26 #endif
27
28 #include <stdio.h>
29 #include <cmath>
30
31 #include "pbd/compose.h"
32
33 #include "ardour/debug.h"
34 #include "ardour/graph.h"
35 #include "ardour/types.h"
36 #include "ardour/session.h"
37 #include "ardour/route.h"
38 #include "ardour/process_thread.h"
39 #include "ardour/audioengine.h"
40
41 #include <jack/thread.h>
42
43 #include "i18n.h"
44
45 using namespace ARDOUR;
46 using namespace PBD;
47
48 static unsigned int 
49 hardware_concurrency()
50 {
51 #if defined(PTW32_VERSION) || defined(__hpux)
52         return pthread_num_processors_np();
53 #elif defined(__APPLE__) || defined(__FreeBSD__)
54         int count;
55         size_t size=sizeof(count);
56         return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
57 #elif defined(HAVE_UNISTD) && defined(_SC_NPROCESSORS_ONLN)
58         int const count=sysconf(_SC_NPROCESSORS_ONLN);
59         return (count>0)?count:0;
60 #else
61         return 0;
62 #endif
63 }
64
65 Graph::Graph (Session & session) 
66         : SessionHandleRef (session) 
67 {
68         pthread_mutex_init( &_trigger_mutex, NULL);
69         sem_init( &_execution_sem, 0, 0 );
70
71         sem_init( &_callback_start_sem, 0, 0 );
72         sem_init( &_callback_done_sem,  0, 0 );
73
74         _execution_tokens = 0;
75
76         pthread_mutex_init (&_swap_mutex, NULL);
77         _current_chain = 0;
78         _pending_chain = 0;
79         _setup_chain   = 1;
80         _quit_threads = false;
81         _graph_empty = true;
82
83         int num_cpu = hardware_concurrency();
84         info << string_compose (_("Using %1 CPUs via %1 threads\n"), num_cpu) << endmsg;
85         _thread_list.push_back( Glib::Thread::create( sigc::mem_fun( *this, &Graph::main_thread), 100000, true, true, Glib::THREAD_PRIORITY_NORMAL) );
86         for (int i=1; i<num_cpu; i++)
87                 _thread_list.push_back( Glib::Thread::create( sigc::mem_fun( *this, &Graph::helper_thread), 100000, true, true, Glib::THREAD_PRIORITY_NORMAL) );
88 }
89
90 void
91 Graph::session_going_away()
92 {
93         _quit_threads = true;
94
95         for (unsigned int i=0; i<_thread_list.size(); i++) {
96                 sem_post( &_execution_sem);
97         }
98
99         sem_post( &_callback_start_sem);
100
101         for (std::list<Glib::Thread *>::iterator i=_thread_list.begin(); i!=_thread_list.end(); i++) {
102                 (*i)->join();
103         }
104
105         // now drop all references on the nodes.
106         _nodes.clear();
107         _nodes_rt[0].clear();
108         _nodes_rt[1].clear();
109         _init_trigger_list[0].clear();
110         _init_trigger_list[1].clear();
111         _trigger_queue.clear();
112 }
113
114 void
115 Graph::prep()
116 {
117         node_list_t::iterator i;
118         int chain;
119
120         if (pthread_mutex_trylock (&_swap_mutex) == 0) {
121                 // we got the swap mutex.
122                 if (_current_chain != _pending_chain)
123                 {
124                         //printf ("chain swap ! %d -> %d\n", _current_chain, _pending_chain);
125                         _setup_chain = _current_chain;
126                         _current_chain = _pending_chain;
127                 }
128                 pthread_mutex_unlock (&_swap_mutex);
129         }
130
131         chain = _current_chain;
132
133         _graph_empty = true;
134         for (i=_nodes_rt[chain].begin(); i!=_nodes_rt[chain].end(); i++) {
135                 (*i)->prep( chain);
136                 _graph_empty = false;
137         }
138         _finished_refcount = _init_finished_refcount[chain];
139
140         for (i=_init_trigger_list[chain].begin(); i!=_init_trigger_list[chain].end(); i++) {
141                 this->trigger( i->get() );
142         }
143 }
144
145 void
146 Graph::trigger (GraphNode * n)
147 {
148         pthread_mutex_lock (&_trigger_mutex);
149         _trigger_queue.push_back( n);
150         pthread_mutex_unlock (&_trigger_mutex);
151 }
152
153 void
154 Graph::dec_ref()
155 {
156         if (g_atomic_int_dec_and_test (&_finished_refcount)) {
157
158                 // ok... this cycle is finished now.
159                 // we are the only thread alive.
160         
161                 this->restart_cycle();
162         }
163 }
164
165 void
166 Graph::restart_cycle()
167 {
168         //printf( "cycle_done chain: %d\n", _current_chain);
169
170         // we are through. wakeup our caller.
171   again:
172         sem_post( &_callback_done_sem);
173
174         // block until we are triggered.
175         sem_wait( &_callback_start_sem);
176         if (_quit_threads)
177                 return;
178
179         //printf( "cycle_start\n" );
180
181         this->prep();
182         if (_graph_empty)
183                 goto again;
184         //printf( "cycle_start chain: %d\n", _current_chain);
185
186         // returning will restart the cycle.
187         //  starting with waking up the others.
188 }
189
190 static bool
191 is_feedback (boost::shared_ptr<RouteList> routelist, Route * from, boost::shared_ptr<Route> to)
192 {
193         for (RouteList::iterator ri=routelist->begin(); ri!=routelist->end(); ri++) {
194                 if ((*ri).get() == from)
195                         return false;
196                 if ((*ri) == to)
197                         return true;
198         }
199         assert(0);
200         return false;
201 }
202
203 static bool
204 is_feedback (boost::shared_ptr<RouteList> routelist, boost::shared_ptr<Route> from, Route * to)
205 {
206         for (RouteList::iterator ri=routelist->begin(); ri!=routelist->end(); ri++) {
207                 if ((*ri).get() == to)
208                         return true;
209                 if ((*ri) == from)
210                         return false;
211         }
212         assert(0);
213         return false;
214 }
215
216 void
217 Graph::rechain (boost::shared_ptr<RouteList> routelist)
218 {
219         node_list_t::iterator ni;
220
221         pthread_mutex_lock (&_swap_mutex);
222         int chain = _setup_chain;
223         printf ("============== setup %d\n", chain);
224         // set all refcounts to 0;
225
226         _init_finished_refcount[chain] = 0;
227         _init_trigger_list[chain].clear();
228
229         _nodes_rt[chain].clear();
230
231         for (RouteList::iterator ri=routelist->begin(); ri!=routelist->end(); ri++) {
232                 node_ptr_t n = boost::dynamic_pointer_cast<GraphNode> (*ri);
233
234                 n->_init_refcount[chain] = 0;
235                 n->_activation_set[chain].clear();
236                 _nodes_rt[chain].push_back(n);
237         }
238
239         // now add refs for the connections.
240
241         for (ni=_nodes_rt[chain].begin(); ni!=_nodes_rt[chain].end(); ni++) {
242                 bool has_input  = false;
243                 bool has_output = false;
244
245                 boost::shared_ptr<Route> rp = boost::dynamic_pointer_cast<Route>( *ni);
246
247                 for (RouteList::iterator ri=routelist->begin(); ri!=routelist->end(); ri++)
248                 {
249                         if (rp->direct_feeds (*ri))
250                         {
251                                 if (is_feedback (routelist, rp.get(), *ri))
252                                         continue; 
253                     
254                                 has_output = true;
255                                 (*ni)->_activation_set[chain].insert (boost::dynamic_pointer_cast<GraphNode> (*ri) );
256                         }
257                 }
258
259                 for (Route::FedBy::iterator fi=rp->fed_by().begin(); fi!=rp->fed_by().end(); fi++)
260                 {
261                         if (boost::shared_ptr<Route> r = fi->r.lock())
262                                 if (!is_feedback (routelist, r, rp.get() ))
263                                         has_input = true;
264                 }
265
266                 for (node_set_t::iterator ai=(*ni)->_activation_set[chain].begin(); ai!=(*ni)->_activation_set[chain].end(); ai++)
267                 {
268                         (*ai)->_init_refcount[chain] += 1;
269                 }
270
271                 if (!has_input)
272                         _init_trigger_list[chain].push_back (*ni);
273
274                 if (!has_output)
275                         _init_finished_refcount[chain] += 1;
276         } 
277
278         _pending_chain = chain;
279         dump(chain);
280         pthread_mutex_unlock (&_swap_mutex);
281 }
282
283
284 bool
285 Graph::run_one()
286 {
287         GraphNode * to_run;
288
289         pthread_mutex_lock (&_trigger_mutex);
290         if (_trigger_queue.size()) {
291                 to_run = _trigger_queue.back();
292                 _trigger_queue.pop_back();
293         }
294         else
295                 to_run = 0;
296
297         int wakeup = std::min ((int) _execution_tokens, (int) _trigger_queue.size() );
298         _execution_tokens -= wakeup;
299
300         for (int i=0; i<wakeup; i++ )
301                 sem_post (&_execution_sem);
302
303         while (to_run == 0) {
304                 _execution_tokens += 1;
305                 pthread_mutex_unlock (&_trigger_mutex);
306                 DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 goes to sleep\n", pthread_self()));
307                 sem_wait (&_execution_sem);
308                 if (_quit_threads)
309                         return true;
310                 DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 is awake\n", pthread_self()));
311                 pthread_mutex_lock (&_trigger_mutex);
312                 if (_trigger_queue.size()) {
313                         to_run = _trigger_queue.back();
314                         _trigger_queue.pop_back();
315                 }
316         }
317         pthread_mutex_unlock (&_trigger_mutex);
318
319         to_run->process();
320         to_run->finish (_current_chain);
321
322         return false;
323 }
324
325 static void get_rt()
326 {
327         int priority = jack_client_real_time_priority (AudioEngine::instance()->jack());
328
329         if (priority) {
330                 struct sched_param rtparam;
331         
332                 memset (&rtparam, 0, sizeof (rtparam));
333                 rtparam.sched_priority = priority;
334         
335                 pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam);
336         }
337 }
338
339 void
340 Graph::helper_thread()
341 {
342         ProcessThread *pt = new ProcessThread;
343
344         pt->get_buffers();
345         get_rt();
346
347
348         while(1) {
349                 if (run_one())
350                         break;
351         }
352         pt->drop_buffers();
353 }
354
355 void
356 Graph::main_thread()
357 {
358         ProcessThread *pt = new ProcessThread;
359
360         pt->get_buffers();
361         get_rt();
362
363   again:
364         sem_wait (&_callback_start_sem);
365
366         this->prep();
367
368         if (_graph_empty) {
369                 sem_post (&_callback_done_sem);
370                 goto again;
371         }
372
373         while(1) {
374                 if (run_one())
375                         break;
376         }
377         pt->drop_buffers();
378 }
379
380 void
381 Graph::dump (int chain)
382 {
383 #ifndef NDEBUG
384         node_list_t::iterator ni;
385         node_set_t::iterator ai;
386
387         chain = _pending_chain;
388
389         printf ("--------------------------------------------Graph dump:\n" );
390         for (ni=_nodes_rt[chain].begin(); ni!=_nodes_rt[chain].end(); ni++) {
391                 boost::shared_ptr<Route> rp = boost::dynamic_pointer_cast<Route>( *ni);
392                 printf ("GraphNode: %s  refcount: %d\n", rp->name().c_str(), (*ni)->_init_refcount[chain] );
393                 for (ai=(*ni)->_activation_set[chain].begin(); ai!=(*ni)->_activation_set[chain].end(); ai++) {
394                         printf ("  triggers: %s\n", boost::dynamic_pointer_cast<Route>(*ai)->name().c_str() );
395                 }
396         }
397
398         printf ("------------- trigger list:\n" );
399         for (ni=_init_trigger_list[chain].begin(); ni!=_init_trigger_list[chain].end(); ni++) {
400                 printf ("GraphNode: %s  refcount: %d\n", boost::dynamic_pointer_cast<Route>(*ni)->name().c_str(), (*ni)->_init_refcount[chain] );
401         }
402
403         printf ("final activation refcount: %d\n", _init_finished_refcount[chain] );
404 #endif
405 }
406
407 int
408 Graph::silent_process_routes (nframes_t nframes, sframes_t start_frame, sframes_t end_frame,
409                               bool can_record, bool rec_monitors_input, bool& need_butler)
410 {
411         _process_nframes = nframes;
412         _process_start_frame = start_frame;
413         _process_end_frame = end_frame;
414         _process_can_record = can_record;
415         _process_rec_monitors_input = rec_monitors_input;
416
417         _process_silent = true;
418         _process_noroll = false;
419         _process_retval = 0;
420         _process_need_butler = false;
421
422         if (!_graph_empty) {
423                 sem_post (&_callback_start_sem);
424                 sem_wait (&_callback_done_sem);
425         }
426
427         need_butler = _process_need_butler;
428
429         return _process_retval;
430 }
431
432 int
433 Graph::process_routes (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, int declick,
434                        bool can_record, bool rec_monitors_input, bool& need_butler)
435 {
436         _process_nframes = nframes;
437         _process_start_frame = start_frame;
438         _process_end_frame = end_frame;
439         _process_can_record = can_record;
440         _process_rec_monitors_input = rec_monitors_input;
441         _process_declick = declick;
442
443         _process_silent = false;
444         _process_noroll = false;
445         _process_retval = 0;
446         _process_need_butler = false;
447
448         sem_post (&_callback_start_sem);
449         sem_wait (&_callback_done_sem);
450
451         need_butler = _process_need_butler;
452
453         return _process_retval;
454 }
455
456 int
457 Graph::routes_no_roll (nframes_t nframes, sframes_t start_frame, sframes_t end_frame, 
458                        bool non_rt_pending, bool can_record, int declick)
459 {
460         _process_nframes = nframes;
461         _process_start_frame = start_frame;
462         _process_end_frame = end_frame;
463         _process_can_record = can_record;
464         _process_declick = declick;
465         _process_non_rt_pending = non_rt_pending;
466
467         _process_silent = false;
468         _process_noroll = true;
469         _process_retval = 0;
470         _process_need_butler = false;
471
472         sem_post (&_callback_start_sem);
473         sem_wait (&_callback_done_sem);
474
475         return _process_retval;
476 }
477 void
478 Graph::process_one_route (Route * route)
479 {
480         bool need_butler = false;
481         int retval;
482
483         assert (route);
484
485         DEBUG_TRACE (DEBUG::ProcessThreads, string_compose ("%1 runs route %2\n", pthread_self(), route->name()));
486
487         if (_process_silent) {
488                 retval = route->silent_roll (_process_nframes, _process_start_frame, _process_end_frame, _process_can_record, _process_rec_monitors_input, need_butler);
489         } else if (_process_noroll) {
490                 route->set_pending_declick (_process_declick);
491                 retval = route->no_roll (_process_nframes, _process_start_frame, _process_end_frame, _process_non_rt_pending, _process_can_record, _process_declick);
492         } else {
493                 route->set_pending_declick (_process_declick);
494                 retval = route->roll (_process_nframes, _process_start_frame, _process_end_frame, _process_declick, _process_can_record, _process_rec_monitors_input, need_butler);
495         }
496
497         if (retval) {
498                 _process_retval = retval;
499         }
500     
501         if (need_butler) {
502                 _process_need_butler = true;
503         }
504 }
505
506
507