diff options
26 files changed, 232 insertions, 48 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 50aea1c24c..0607a03e54 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -264,6 +264,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[]) GainMeter::setup_slider_pix (); RouteTimeAxisView::setup_slider_pix (); SendProcessorEntry::setup_slider_pix (); + SessionEvent::create_per_thread_pool ("GUI", 512); } catch (failed_constructor& err) { error << _("could not initialize Ardour.") << endmsg; diff --git a/gtk2_ardour/editor_audio_import.cc b/gtk2_ardour/editor_audio_import.cc index 833d26168a..f8b6d7c141 100644 --- a/gtk2_ardour/editor_audio_import.cc +++ b/gtk2_ardour/editor_audio_import.cc @@ -880,6 +880,7 @@ void * Editor::_import_thread (void *arg) { PBD::notify_gui_about_thread_creation (pthread_self(), X_("Import")); + SessionEvent::create_per_thread_pool ("import events", 64); Editor *ed = (Editor *) arg; return ed->import_thread (); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index fe003d231c..3b60f3c903 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -3653,6 +3653,8 @@ void* Editor::_freeze_thread (void* arg) { PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freeze")); + SessionEvent::create_per_thread_pool ("freeze events", 64); + return static_cast<Editor*>(arg)->freeze_thread (); } diff --git a/gtk2_ardour/editor_timefx.cc b/gtk2_ardour/editor_timefx.cc index de1883330b..b52121f9c5 100644 --- a/gtk2_ardour/editor_timefx.cc +++ b/gtk2_ardour/editor_timefx.cc @@ -338,6 +338,7 @@ void* Editor::timefx_thread (void *arg) { PBD::notify_gui_about_thread_creation (pthread_self(), X_("TimeFX")); + SessionEvent::create_per_thread_pool ("timefx events", 64); TimeFXDialog* tsd = static_cast<TimeFXDialog*>(arg); diff --git a/gtk2_ardour/sfdb_ui.cc b/gtk2_ardour/sfdb_ui.cc index 3328b71225..aa8d7b77f2 100644 --- a/gtk2_ardour/sfdb_ui.cc +++ b/gtk2_ardour/sfdb_ui.cc @@ -734,6 +734,7 @@ void* freesound_search_thread_entry (void* arg) { PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freesound Search")); + SessionEvent::create_per_thread_pool ("freesound events", 64); static_cast<SoundFileBrowser*>(arg)->freesound_search_thread (); @@ -763,6 +764,10 @@ SoundFileBrowser::freesound_search_clicked () void SoundFileBrowser::freesound_search_thread() { +#if 0 + + THIS IS ALL TOTALLY THREAD-ILLEGAL ... YOU CANNOT DO GTK STUFF IN THIS THREAD + #ifdef FREESOUND freesound_list->clear(); @@ -810,6 +815,8 @@ SoundFileBrowser::freesound_search_thread() canceling = false; freesound_search_btn.set_label(_("Start Downloading")); #endif +#endif + } vector<ustring> diff --git a/libs/ardour/analyser.cc b/libs/ardour/analyser.cc index 2e68cfed83..8e2ec99f27 100644 --- a/libs/ardour/analyser.cc +++ b/libs/ardour/analyser.cc @@ -19,6 +19,7 @@ #include "ardour/analyser.h" #include "ardour/audiofilesource.h" +#include "ardour/session_event.h" #include "ardour/transient_detector.h" #include "pbd/pthread_utils.h" @@ -76,6 +77,7 @@ void Analyser::work () { PBD::notify_gui_about_thread_creation (pthread_self(), string ("analyser-") + to_string (pthread_self(), std::dec)); + SessionEvent::create_per_thread_pool ("Analyser", 64); while (true) { analysis_queue_lock.lock (); diff --git a/libs/ardour/ardour/session_event.h b/libs/ardour/ardour/session_event.h index 767c374988..07c795257f 100644 --- a/libs/ardour/ardour/session_event.h +++ b/libs/ardour/ardour/session_event.h @@ -98,18 +98,17 @@ struct SessionEvent { return e1->before (*e2); } - void *operator new (size_t) { - return pool.alloc (); - } - - void operator delete (void *ptr, size_t /*size*/) { - pool.release (ptr); - } + void* operator new (size_t); + void operator delete (void *ptr, size_t /*size*/); static const nframes_t Immediate = 0; + static void create_per_thread_pool (const std::string& n, unsigned long nitems); + static void init_event_pool (); + private: - static MultiAllocSingleReleasePool pool; + static PerThreadPool* pool; + CrossThreadPool* own_pool; }; class SessionEventManager { @@ -120,8 +119,8 @@ class SessionEventManager { void add_event (nframes64_t action_frame, SessionEvent::Type type, nframes64_t target_frame = 0); void remove_event (nframes64_t frame, SessionEvent::Type type); void clear_events (SessionEvent::Type type); - - + + protected: RingBuffer<SessionEvent*> pending_events; typedef std::list<SessionEvent *> Events; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 2f344eb8ba..b69b06c4db 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -136,6 +136,8 @@ _thread_init_callback (void * /*arg*/) */ PBD::notify_gui_about_thread_creation (pthread_self(), X_("Audioengine"), 4096); + SessionEvent::create_per_thread_pool (X_("Audioengine"), 512); + MIDI::JACK_MidiPort::set_process_thread (pthread_self()); } diff --git a/libs/ardour/butler.cc b/libs/ardour/butler.cc index 3d43c11e38..76a7fb2424 100644 --- a/libs/ardour/butler.cc +++ b/libs/ardour/butler.cc @@ -114,6 +114,7 @@ void * Butler::_thread_work (void* arg) { PBD::notify_gui_about_thread_creation (pthread_self(), X_("Butler")); + SessionEvent::create_per_thread_pool ("butler events", 64); return ((Butler *) arg)->thread_work (); } diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index aa7dda9e50..0676973e53 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -43,6 +43,8 @@ using namespace PBD; using namespace ARDOUR; using namespace MIDI; +namespace ARDOUR { + void setup_enum_writer () { @@ -584,6 +586,8 @@ setup_enum_writer () } +} /* namespace ARDOUR */ + /* deserializing types from ardour/types.h */ std::istream& operator>>(std::istream& o, HeaderFormat& var) @@ -795,3 +799,5 @@ std::ostream& operator<<(std::ostream& o, const WaveformShape& var) std::string s = enum_2_string (var); return o << s; } + + diff --git a/libs/ardour/export_channel_configuration.cc b/libs/ardour/export_channel_configuration.cc index 47bbbd276c..047aadc671 100644 --- a/libs/ardour/export_channel_configuration.cc +++ b/libs/ardour/export_channel_configuration.cc @@ -177,6 +177,7 @@ void * ExportChannelConfiguration::_write_files (void *arg) { notify_gui_about_thread_creation (pthread_self(), "Export post-processing"); + SessionEvent::create_per_thread_pool ("exporter events", 64); // cc can be trated like 'this' WriterThread & cc (*((WriterThread *) arg)); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 6e6ae9bf80..9953524c34 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -72,6 +72,7 @@ #include "ardour/rc_configuration.h" #include "ardour/runtime_functions.h" #include "ardour/session.h" +#include "ardour/session_event.h" #include "ardour/source_factory.h" #include "ardour/utils.h" @@ -110,6 +111,8 @@ mix_buffers_no_gain_t ARDOUR::mix_buffers_no_gain = 0; sigc::signal<void,std::string> ARDOUR::BootMessage; +void ARDOUR::setup_enum_writer (); + int ARDOUR::setup_midi () { @@ -283,14 +286,15 @@ lotsa_files_please () int ARDOUR::init (bool use_vst, bool try_optimization) { - if (!Glib::thread_supported()) + if (!Glib::thread_supported()) { Glib::thread_init(); + } - PBD::ID::init (); + (void) bindtextdomain(PACKAGE, LOCALEDIR); - extern void setup_enum_writer (); + PBD::ID::init (); + SessionEvent::init_event_pool (); - (void) bindtextdomain(PACKAGE, LOCALEDIR); /* provide a state version for the few cases that need it and are not driven by reading state from disk (e.g. undo/redo) diff --git a/libs/ardour/session_events.cc b/libs/ardour/session_events.cc index 98620e269f..8818436ed7 100644 --- a/libs/ardour/session_events.cc +++ b/libs/ardour/session_events.cc @@ -37,7 +37,45 @@ using namespace std; using namespace ARDOUR; using namespace PBD; -MultiAllocSingleReleasePool SessionEvent::pool ("event", sizeof (SessionEvent), 512); +PerThreadPool* SessionEvent::pool; + +void +SessionEvent::init_event_pool () +{ + pool = new PerThreadPool; +} + +void +SessionEvent::create_per_thread_pool (const std::string& name, unsigned long nitems) +{ + /* this is a per-thread call that simply creates a thread-private ptr to + a CrossThreadPool for use by this thread whenever events are allocated/released + from SessionEvent::pool() + */ + pool->create_per_thread_pool (name, sizeof (SessionEvent), nitems); +} + +void * +SessionEvent::operator new (size_t) +{ + CrossThreadPool* p = pool->per_thread_pool (); + SessionEvent* ev = static_cast<SessionEvent*> (p->alloc ()); + ev->own_pool = p; + return ev; +} + +void +SessionEvent::operator delete (void *ptr, size_t /*size*/) +{ + Pool* p = pool->per_thread_pool (); + SessionEvent* ev = static_cast<SessionEvent*> (ptr); + + if (p == ev->own_pool) { + p->release (ptr); + } else { + ev->own_pool->push (ev); + } +} void SessionEventManager::add_event (nframes64_t frame, SessionEvent::Type type, nframes64_t target_frame) diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index b05cfc83a2..fe332b71c2 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -1094,6 +1094,7 @@ Session::midi_thread_work () vector<MIDI::Port*> ports; PBD::notify_gui_about_thread_creation (pthread_self(), X_("MIDI"), 2048); + SessionEvent::create_per_thread_pool (X_("MIDI I/O"), 128); memset (&rtparam, 0, sizeof (rtparam)); rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */ diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc index 6753a0738f..b85f5b67a0 100644 --- a/libs/ardour/source_factory.cc +++ b/libs/ardour/source_factory.cc @@ -59,6 +59,7 @@ static void peak_thread_work () { PBD::notify_gui_about_thread_creation (pthread_self(), string ("peakbuilder-") + to_string (pthread_self(), std::dec)); + SessionEvent::create_per_thread_pool (X_("PeakFile Builder "), 64); while (true) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 22d86ffd3c..67998ff5fb 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -263,7 +263,7 @@ def build(bld): obj.includes = ['.', '../surfaces/control_protocol', '..'] obj.name = 'libardour' obj.target = 'ardour' - obj.uselib = 'GLIBMM AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX' + obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX' obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband' obj.vnum = LIBARDOUR_LIB_VERSION obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') @@ -324,7 +324,7 @@ def build(bld): test/testrunner.cpp '''.split() testobj.includes = obj.includes + ['../pbd/'] - testobj.uselib = 'CPPUNIT SIGCPP JACK GLIBMM SAMPLERATE XML LRDF' + testobj.uselib = 'CPPUNIT SIGCPP JACK GLIBMM GTHREAD SAMPLERATE XML LRDF' testobj.uselib_local = 'libpbd libmidipp libardour' testobj.name = 'libardour-tests' testobj.target = 'run-tests' diff --git a/libs/pbd/pbd/pool.h b/libs/pbd/pbd/pool.h index 66a87abf96..e8ad780dc2 100644 --- a/libs/pbd/pbd/pool.h +++ b/libs/pbd/pbd/pool.h @@ -38,9 +38,11 @@ class Pool std::string name() const { return _name; } - private: - RingBuffer<void*>* free_list; + protected: + RingBuffer<void*> free_list; std::string _name; + + private: void *block; }; @@ -71,4 +73,33 @@ class MultiAllocSingleReleasePool : public Pool Glib::Mutex* m_lock; }; +class CrossThreadPool : public Pool +{ + public: + CrossThreadPool (std::string n, unsigned long isize, unsigned long nitems); + + void* alloc (); + void push (void *); + + private: + RingBuffer<void*> pending; +}; + +class PerThreadPool +{ + public: + PerThreadPool (); + + GPrivate* key() const { return _key; } + + void create_per_thread_pool (std::string name, unsigned long item_size, unsigned long nitems); + CrossThreadPool* per_thread_pool (); + + private: + GPrivate* _key; + std::string _name; + unsigned long _item_size; + unsigned long _nitems; +}; + #endif // __qm_pool_h__ diff --git a/libs/pbd/pool.cc b/libs/pbd/pool.cc index 2a9022542a..af57871da9 100644 --- a/libs/pbd/pool.cc +++ b/libs/pbd/pool.cc @@ -30,11 +30,11 @@ using namespace std; using namespace PBD; Pool::Pool (string n, unsigned long item_size, unsigned long nitems) + : free_list (nitems) + , _name (n) { _name = n; - free_list = new RingBuffer<void*> (nitems); - /* since some overloaded ::operator new() might use this, its important that we use a "lower level" allocator to get more space. @@ -48,8 +48,7 @@ Pool::Pool (string n, unsigned long item_size, unsigned long nitems) ptrlist[i] = static_cast<void *> (static_cast<char*>(block) + (i * item_size)); } - free_list->write (ptrlist, nitems); - + free_list.write (ptrlist, nitems); free (ptrlist); } @@ -65,7 +64,7 @@ Pool::alloc () // cerr << _name << " pool " << " alloc, thread = " << pthread_name() << " space = " << free_list->read_space() << endl; - if (free_list->read (&ptr, 1) < 1) { + if (free_list.read (&ptr, 1) < 1) { fatal << "CRITICAL: " << _name << " POOL OUT OF MEMORY - RECOMPILE WITH LARGER SIZE!!" << endmsg; /*NOTREACHED*/ return 0; @@ -77,7 +76,7 @@ Pool::alloc () void Pool::release (void *ptr) { - free_list->write (&ptr, 1); + free_list.write (&ptr, 1); // cerr << _name << ": release, now has " << free_list->read_space() << endl; } @@ -144,3 +143,64 @@ SingleAllocMultiReleasePool::release (void* ptr) Pool::release (ptr); } +/*-------------------------------------------------------*/ + +static void +free_per_thread_pool (void* ptr) +{ + cerr << "Deleting a per thread pool @ " << ptr << endl; + Pool* pptr = static_cast<Pool*>(ptr); + delete pptr; +} + +PerThreadPool::PerThreadPool () +{ + { + /* for some reason this appears necessary to get glib's thread private stuff to work */ + GPrivate* key; + key = g_private_new (NULL); + } + + _key = g_private_new (free_per_thread_pool); +} + +void +PerThreadPool::create_per_thread_pool (string n, unsigned long isize, unsigned long nitems) +{ + Pool* p = new CrossThreadPool (n, isize, nitems); + g_private_set (_key, p); +} + +CrossThreadPool* +PerThreadPool::per_thread_pool () +{ + CrossThreadPool* p = static_cast<CrossThreadPool*> (g_private_get (_key)); + if (!p) { + fatal << "programming error: no per-thread pool \"" << _name << "\" for thread " << pthread_self() << endmsg; + /*NOTREACHED*/ + } + return p; +} + +CrossThreadPool::CrossThreadPool (string n, unsigned long isize, unsigned long nitems) + : Pool (n, isize, nitems) + , pending (nitems) +{ + +} + +void* +CrossThreadPool::alloc () +{ + void* ptr; + while (pending.read (&ptr, 1) == 1) { + free_list.write (&ptr, 1); + } + return Pool::alloc (); +} + +void +CrossThreadPool::push (void* t) +{ + pending.write (&t, 1); +} diff --git a/libs/surfaces/control_protocol/basic_ui.cc b/libs/surfaces/control_protocol/basic_ui.cc index af457fe5a4..3d336adb47 100644 --- a/libs/surfaces/control_protocol/basic_ui.cc +++ b/libs/surfaces/control_protocol/basic_ui.cc @@ -50,7 +50,11 @@ BasicUI::~BasicUI () void BasicUI::register_thread (std::string name) { + std::string pool_name = name; + pool_name += " events"; + PBD::notify_gui_about_thread_creation (pthread_self(), name); + SessionEvent::create_per_thread_pool (pool_name, 64); } void diff --git a/libs/surfaces/mackie/mackie_control_protocol_poll.cc b/libs/surfaces/mackie/mackie_control_protocol_poll.cc index 867a7d784a..f6171c7f0e 100644 --- a/libs/surfaces/mackie/mackie_control_protocol_poll.cc +++ b/libs/surfaces/mackie/mackie_control_protocol_poll.cc @@ -42,7 +42,7 @@ bool MackieControlProtocol::probe() void * MackieControlProtocol::monitor_work() { - PBD::notify_gui_about_thread_creation (pthread_self(), X_("Mackie")); + register_thread (X_("MCU")); pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); diff --git a/libs/surfaces/osc/osc.cc b/libs/surfaces/osc/osc.cc index d5a28a38ce..af067f65bc 100644 --- a/libs/surfaces/osc/osc.cc +++ b/libs/surfaces/osc/osc.cc @@ -374,9 +374,8 @@ OSC::get_unix_server_url() void * OSC::_osc_receiver(void * arg) { - PBD::notify_gui_about_thread_creation (pthread_self(), X_("OSC")); - - static_cast<OSC*> (arg)->osc_receiver(); + static_cast<OSC*>(arg)->register_thread (X_("OSC")); + static_cast<OSC*>(arg)->osc_receiver(); return 0; } diff --git a/libs/surfaces/powermate/i18n.h b/libs/surfaces/powermate/i18n.h new file mode 100644 index 0000000000..dcbbfcf52e --- /dev/null +++ b/libs/surfaces/powermate/i18n.h @@ -0,0 +1,16 @@ +#ifndef __i18n_h__ +#define __i18n_h__ + +#include "pbd/compose.h" +#include "pbd/convert.h" +#include "gettext.h" + +#include <vector> +#include <string> + +#define _(Text) dgettext (PACKAGE,Text) +#define N_(Text) gettext_noop (Text) +#define X_(Text) Text +#define I18N(Array) PBD::internationalize (PACKAGE, Array) + +#endif // __i18n_h__ diff --git a/libs/surfaces/powermate/powermate.cc b/libs/surfaces/powermate/powermate.cc index a32c4696ae..0cdfba6f3a 100644 --- a/libs/surfaces/powermate/powermate.cc +++ b/libs/surfaces/powermate/powermate.cc @@ -12,12 +12,14 @@ #include <unistd.h> #include <fcntl.h> -#include <i18n.h> -#include <pbd/xml++.h> -#include <pbd/error.h> #include <glibmm.h> +#include "pbd/pthread_utils.h" +#include "pbd/xml++.h" +#include "pbd/error.h" + #include "powermate.h" +#include "i18n.h" using namespace ARDOUR; using namespace std; @@ -72,17 +74,18 @@ int open_powermate (const char *dev, int mode) int find_powermate(int mode) { - char devname[256]; - int i, r; - - for(i=0; i<NUM_EVENT_DEVICES; i++){ - sprintf(devname, "/dev/input/event%d", i); - r = open_powermate(devname, mode); - if(r >= 0) - return r; - } - - return -1; + char devname[256]; + int i, r; + + for (i = 0; i < NUM_EVENT_DEVICES; i++) { + sprintf (devname, "/dev/input/event%d", i); + r = open_powermate (devname, mode); + if (r >= 0) { + return r; + } + } + + return -1; } PowermateControlProtocol::PowermateControlProtocol (Session& s) @@ -126,7 +129,7 @@ PowermateControlProtocol::set_active (bool inActivate) return -1; } - if (pthread_create (&mThread, 0, SerialThreadEntry, this) == 0) { + if (pthread_create_and_store ("Powermate", &mThread, 0, SerialThreadEntry, this) == 0) { _active = true; } else { return -1; @@ -163,6 +166,7 @@ PowermateControlProtocol::set_state (const XMLNode& /*node*/, int /*version*/) void* PowermateControlProtocol::SerialThreadEntry (void* arg) { + static_cast<PowermateControlProtocol*>(arg)->register_thread ("Powermate"); return static_cast<PowermateControlProtocol*>(arg)->SerialThread (); } diff --git a/libs/surfaces/tranzport/init.cc b/libs/surfaces/tranzport/init.cc index 726cb60d49..910d37a5de 100644 --- a/libs/surfaces/tranzport/init.cc +++ b/libs/surfaces/tranzport/init.cc @@ -173,7 +173,7 @@ TranzportControlProtocol::monitor_work () bool first_time = true; uint8_t offline = 0; - PBD::notify_gui_about_thread_creation (pthread_self(), X_("Tranzport")); + register_thread (X_("Tranzport")); pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0); pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0); rtpriority_set(); diff --git a/libs/surfaces/wiimote/wiimote.cc b/libs/surfaces/wiimote/wiimote.cc index 8864a5019f..867e1c38e4 100644 --- a/libs/surfaces/wiimote/wiimote.cc +++ b/libs/surfaces/wiimote/wiimote.cc @@ -35,10 +35,10 @@ WiimoteControlProtocol::~WiimoteControlProtocol() if (wiimote_handle) { cwiid_close(wiimote_handle); } + std::cerr << "Wiimote: closed" << std::endl; } - bool WiimoteControlProtocol::probe() { @@ -166,11 +166,12 @@ WiimoteControlProtocol::update_led_state() } void -WiimoteControlProtocol::wiimote_main() +WiimoteControlProtocol::_wiimote_main () { bdaddr_t bdaddr; unsigned char rpt_mode = 0; - register_thread("Wiimote Discovery and Callback Thread"); + + register_thread ("Wiimote"); wiimote_discovery: @@ -261,6 +262,7 @@ wiimote_discovery: std::cerr << "Wiimote: main thread stopped" << std::endl; + return 0; } @@ -465,6 +465,7 @@ def configure(conf): define_name = 'HAVE_AUDIOUNITS', linkflags = [ '-framework', 'AudioUnit' ]) autowaf.check_pkg(conf, 'glib-2.0', uselib_store='GLIB', atleast_version='2.2') + autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD', atleast_version='2.2') autowaf.check_pkg(conf, 'glibmm-2.4', uselib_store='GLIBMM', atleast_version='2.14.0') if sys.platform == 'darwin': sub_config_and_use(conf, 'libs/appleutility') |