+
+
+
+/* dedicated thread for signal emission.
+ *
+ * while sending cross-thread signals from the process thread
+ * is fine in general, PBD::Signal's use of boost::function and
+ * boost:bind can produce a vast overhead which is not
+ * acceptable for low latency.
+ *
+ * This works around the issue by moving the boost overhead
+ * out of the RT thread. The overall load is probably higher but
+ * the realtime thread remains unaffected.
+ */
+
+void
+Session::emit_route_signals ()
+{
+ // TODO use RAII to allow using these signals in other places
+ BatchUpdateStart(); /* EMIT SIGNAL */
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ for (RouteList::const_iterator ci = r->begin(); ci != r->end(); ++ci) {
+ (*ci)->emit_pending_signals ();
+ }
+ BatchUpdateEnd(); /* EMIT SIGNAL */
+}
+
+void
+Session::emit_thread_start ()
+{
+ if (_rt_thread_active) {
+ return;
+ }
+ _rt_thread_active = true;
+
+ if (pthread_create (&_rt_emit_thread, NULL, emit_thread, this)) {
+ _rt_thread_active = false;
+ }
+}
+
+void
+Session::emit_thread_terminate ()
+{
+ if (!_rt_thread_active) {
+ return;
+ }
+ _rt_thread_active = false;
+
+ if (pthread_mutex_lock (&_rt_emit_mutex) == 0) {
+ pthread_cond_signal (&_rt_emit_cond);
+ pthread_mutex_unlock (&_rt_emit_mutex);
+ }
+
+ void *status;
+ pthread_join (_rt_emit_thread, &status);
+}
+
+void *
+Session::emit_thread (void *arg)
+{
+ Session *s = static_cast<Session *>(arg);
+ s->emit_thread_run ();
+ pthread_exit (0);
+ return 0;
+}
+
+void
+Session::emit_thread_run ()
+{
+ pthread_mutex_lock (&_rt_emit_mutex);
+ while (_rt_thread_active) {
+ emit_route_signals();
+ pthread_cond_wait (&_rt_emit_cond, &_rt_emit_mutex);
+ }
+ pthread_mutex_unlock (&_rt_emit_mutex);
+}