#include #include "pbd/abstract_ui.h" #include "pbd/pthread_utils.h" #include "pbd/failed_constructor.h" #include "i18n.h" using namespace std; template AbstractUI::AbstractUI (string name, bool with_signal_pipes) : BaseUI (name, with_signal_pipes) { if (pthread_key_create (&thread_request_buffer_key, 0)) { cerr << _("cannot create thread request buffer key") << endl; throw failed_constructor(); } PBD::ThreadCreatedWithRequestSize.connect (mem_fun (*this, &AbstractUI::register_thread_with_request_count)); } template void AbstractUI::register_thread (pthread_t thread_id, string name) { register_thread_with_request_count (thread_id, name, 256); } template void AbstractUI::register_thread_with_request_count (pthread_t thread_id, string /*thread_name*/, uint32_t num_requests) { RequestBuffer* b = new RequestBuffer (num_requests); { Glib::Mutex::Lock lm (request_buffer_map_lock); request_buffers[thread_id] = b; } pthread_setspecific (thread_request_buffer_key, b); } template RequestObject* AbstractUI::get_request (RequestType rt) { RequestBuffer* rbuf = static_cast(pthread_getspecific (thread_request_buffer_key)); if (rbuf == 0) { /* Cannot happen, but if it does we can't use the error reporting mechanism */ cerr << _("programming error: ") << string_compose ("no %1-UI request buffer found for thread %2", name(), pthread_name()) << endl; abort (); } RequestBufferVector vec; vec.buf[0] = 0; vec.buf[1] = 0; rbuf->get_write_vector (&vec); if (vec.len[0] == 0) { if (vec.len[1] == 0) { cerr << string_compose ("no space in %1-UI request buffer for thread %2", name(), pthread_name()) << endl; return 0; } else { vec.buf[1]->type = rt; return vec.buf[1]; } } else { vec.buf[0]->type = rt; return vec.buf[0]; } } template void AbstractUI::handle_ui_requests () { RequestBufferMapIterator i; request_buffer_map_lock.lock (); for (i = request_buffers.begin(); i != request_buffers.end(); ++i) { RequestBufferVector vec; while (true) { /* we must process requests 1 by 1 because the request may run a recursive main event loop that will itself call handle_ui_requests. when we return from the request handler, we cannot expect that the state of queued requests is even remotely consistent with the condition before we called it. */ i->second->get_read_vector (&vec); if (vec.len[0] == 0) { break; } else { request_buffer_map_lock.unlock (); do_request (vec.buf[0]); request_buffer_map_lock.lock (); i->second->increment_read_ptr (1); } } } request_buffer_map_lock.unlock (); } template void AbstractUI::send_request (RequestObject *req) { if (base_instance() == 0) { return; /* XXX is this the right thing to do ? */ } if (caller_is_ui_thread()) { // cerr << "GUI thread sent request " << req << " type = " << req->type << endl; do_request (req); } else { RequestBuffer* rbuf = static_cast (pthread_getspecific (thread_request_buffer_key)); if (rbuf == 0) { /* can't use the error system to report this, because this thread isn't registered! */ cerr << _("programming error: ") << string_compose ("AbstractUI::send_request() called from %1 (%2), but no request buffer exists for that thread", name(), pthread_name()) << endl; abort (); } // cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl; rbuf->increment_write_ptr (1); if (signal_pipe[1] >= 0) { const char c = 0; write (signal_pipe[1], &c, 1); } } }