Add a RT-Tasklist
authorRobin Gareus <robin@gareus.org>
Mon, 30 Oct 2017 04:52:18 +0000 (05:52 +0100)
committerRobin Gareus <robin@gareus.org>
Mon, 30 Oct 2017 15:31:38 +0000 (16:31 +0100)
libs/ardour/ardour/rt_tasklist.h [new file with mode: 0644]
libs/ardour/rt_tasklist.cc [new file with mode: 0644]
libs/ardour/wscript

diff --git a/libs/ardour/ardour/rt_tasklist.h b/libs/ardour/ardour/rt_tasklist.h
new file mode 100644 (file)
index 0000000..2924705
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef _ardour_rt_tasklist_h_
+#define _ardour_rt_tasklist_h_
+
+#include <list>
+#include <boost/function.hpp>
+
+#include "pbd/semutils.h"
+
+#include "ardour/libardour_visibility.h"
+#include "ardour/types.h"
+#include "ardour/audio_backend.h"
+#include "ardour/session_handle.h"
+
+namespace ARDOUR {
+
+class LIBARDOUR_API RTTaskList
+{
+public:
+       RTTaskList ();
+       ~RTTaskList ();
+
+       // TODO use dedicated allocator of a boost::intrusive::list
+       typedef std::list<boost::function<void ()> > TaskList;
+
+       /** process tasks in list in parallel, wait for them to complete */
+       void process (TaskList const&);
+
+private:
+       gint _threads_active;
+       std::vector<pthread_t> _threads;
+
+       void reset_thread_list ();
+       void drop_threads ();
+
+       void process_tasklist ();
+
+       static void* _thread_run (void *arg);
+       void run ();
+
+       Glib::Threads::Mutex _process_mutex;
+       Glib::Threads::Mutex _tasklist_mutex;
+       PBD::Semaphore _task_run_sem;
+       PBD::Semaphore _task_end_sem;
+
+       TaskList _tasklist;
+};
+
+} // namespace ARDOUR
+#endif
diff --git a/libs/ardour/rt_tasklist.cc b/libs/ardour/rt_tasklist.cc
new file mode 100644 (file)
index 0000000..db2a330
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2017 Robin Gareus <robin@gareus.org>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include "pbd/pthread_utils.h"
+
+#include "ardour/audioengine.h"
+#include "ardour/debug.h"
+#include "ardour/rt_tasklist.h"
+#include "ardour/utils.h"
+
+#include "pbd/i18n.h"
+
+using namespace ARDOUR;
+
+RTTaskList::RTTaskList ()
+       : _threads_active (0)
+       , _task_run_sem ("rt_task_run", 0)
+       , _task_end_sem ("rt_task_done", 0)
+{
+       reset_thread_list ();
+}
+
+RTTaskList::~RTTaskList ()
+{
+       drop_threads ();
+}
+
+void
+RTTaskList::drop_threads ()
+{
+       Glib::Threads::Mutex::Lock pm (_process_mutex);
+       g_atomic_int_set (&_threads_active, 0);
+
+       uint32_t nt = _threads.size ();
+       for (uint32_t i = 0; i < nt; ++i) {
+               _task_run_sem.signal ();
+       }
+       for (std::vector<pthread_t>::const_iterator i = _threads.begin (); i != _threads.end (); ++i)
+       {
+               pthread_join (*i, NULL);
+       }
+       _threads.clear ();
+       _task_run_sem.reset ();
+       _task_end_sem.reset ();
+}
+
+/*static*/ void*
+RTTaskList::_thread_run (void *arg)
+{
+       RTTaskList *d = static_cast<RTTaskList *>(arg);
+       d->run ();
+       pthread_exit (0);
+       return 0;
+}
+
+void
+RTTaskList::reset_thread_list ()
+{
+       drop_threads ();
+
+       const uint32_t num_threads = how_many_dsp_threads ();
+       if (num_threads < 2) {
+               return;
+       }
+
+       Glib::Threads::Mutex::Lock pm (_process_mutex);
+
+       g_atomic_int_set (&_threads_active, 1);
+       for (uint32_t i = 0; i < num_threads; ++i) {
+               pthread_t thread_id;
+               size_t stacksize = 100000;
+               if (!AudioEngine::instance()->is_realtime ()
+                   ||
+                   pbd_realtime_pthread_create (PBD_SCHED_FIFO, -22, stacksize, &thread_id, _thread_run, this)) {
+                       pthread_attr_t attr;
+                       pthread_attr_init (&attr);
+                       pthread_attr_setstacksize (&attr, stacksize);
+                       if (pthread_create (&thread_id, &attr, _thread_run, this)) {
+                               PBD::fatal << _("Cannot create thread for TaskList!") << endmsg;
+                               /* NOT REACHED */
+                       }
+                       pthread_attr_destroy (&attr);
+               }
+               pbd_mach_set_realtime_policy (thread_id, 5. * 1e-5);
+               _threads.push_back (thread_id);
+       }
+}
+
+void
+RTTaskList::run ()
+{
+       Glib::Threads::Mutex::Lock tm (_tasklist_mutex, Glib::Threads::NOT_LOCK);
+       bool wait = true;
+
+       while (true) {
+               if (wait) {
+                       _task_run_sem.wait ();
+               }
+
+               if (0 == g_atomic_int_get (&_threads_active)) {
+                       _task_end_sem.signal ();
+                       break;
+               }
+
+               wait = false;
+
+               boost::function<void ()> to_run;
+               tm.acquire ();
+               if (_tasklist.size () > 0) {
+                       to_run = _tasklist.front();
+                       _tasklist.pop_front ();
+               }
+               tm.release ();
+
+               if (!to_run.empty ()) {
+                       to_run ();
+                       continue;
+               }
+
+               if (!wait) {
+                       _task_end_sem.signal ();
+               }
+
+               wait = true;
+       }
+}
+
+void
+RTTaskList::process (TaskList const& tl)
+{
+       Glib::Threads::Mutex::Lock pm (_process_mutex);
+       _tasklist = tl;
+       process_tasklist ();
+       _tasklist.clear ();
+}
+
+void
+RTTaskList::process_tasklist ()
+{
+       if (0 == g_atomic_int_get (&_threads_active) || _threads.size () == 0) {
+               for (TaskList::iterator i = _tasklist.begin (); i != _tasklist.end(); ++i) {
+                       (*i)();
+               }
+               return;
+       }
+
+       uint32_t nt = std::min (_threads.size (), _tasklist.size ());
+
+       for (uint32_t i = 0; i < nt; ++i) {
+               _task_run_sem.signal ();
+       }
+       for (uint32_t i = 0; i < nt; ++i) {
+               _task_end_sem.wait ();
+       }
+}
index 16048038845e93bba406e67805ad0b92e86258a3..f5d30f147bdaa04287b7c7adc4d759cc68b7d15d 100644 (file)
@@ -192,6 +192,7 @@ libardour_sources = [
         'route_group.cc',
         'route_group_member.cc',
         'rb_effect.cc',
+        'rt_tasklist.cc',
         'scene_change.cc',
         'search_paths.cc',
         'selection.cc',