3 #include <pbd/abstract_ui.h>
4 #include <pbd/pthread_utils.h>
5 #include <pbd/failed_constructor.h>
7 template <typename RequestObject>
8 AbstractUI<RequestObject>::AbstractUI (string name, bool with_signal_pipes)
9 : BaseUI (name, with_signal_pipes)
11 if (pthread_key_create (&thread_request_buffer_key, 0)) {
12 cerr << _("cannot create thread request buffer key") << endl;
13 throw failed_constructor();
16 PBD::ThreadCreated.connect (mem_fun (*this, &AbstractUI<RequestObject>::register_thread));
17 PBD::ThreadCreatedWithRequestSize.connect (mem_fun (*this, &AbstractUI<RequestObject>::register_thread_with_request_count));
20 template <typename RequestObject> void
21 AbstractUI<RequestObject>::register_thread (pthread_t thread_id, string name)
23 register_thread_with_request_count (thread_id, name, 256);
26 template <typename RequestObject> void
27 AbstractUI<RequestObject>::register_thread_with_request_count (pthread_t thread_id, string thread_name, uint32_t num_requests)
29 RequestBuffer* b = new RequestBuffer (num_requests);
32 Glib::Mutex::Lock lm (request_buffer_map_lock);
33 request_buffers[thread_id] = b;
36 pthread_setspecific (thread_request_buffer_key, b);
39 template <typename RequestObject> RequestObject*
40 AbstractUI<RequestObject>::get_request (RequestType rt)
42 RequestBuffer* rbuf = static_cast<RequestBuffer*>(pthread_getspecific (thread_request_buffer_key));
45 /* Cannot happen, but if it does we can't use the error reporting mechanism */
46 cerr << _("programming error: ")
47 << string_compose (X_("no %1-UI request buffer found for thread %2"), name(), pthread_name())
52 RequestBufferVector vec;
54 rbuf->get_write_vector (&vec);
56 if (vec.len[0] == 0) {
57 if (vec.len[1] == 0) {
58 cerr << string_compose (X_("no space in %1-UI request buffer for thread %2"), name(), pthread_name())
62 vec.buf[1]->type = rt;
66 vec.buf[0]->type = rt;
71 template <typename RequestObject> void
72 AbstractUI<RequestObject>::handle_ui_requests ()
74 RequestBufferMapIterator i;
76 request_buffer_map_lock.lock ();
78 for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
80 RequestBufferVector vec;
84 /* we must process requests 1 by 1 because
85 the request may run a recursive main
86 event loop that will itself call
87 handle_ui_requests. when we return
88 from the request handler, we cannot
89 expect that the state of queued requests
90 is even remotely consistent with
91 the condition before we called it.
94 i->second->get_read_vector (&vec);
96 if (vec.len[0] == 0) {
99 /* request_factory/copy constructor does a deep
100 copy of the Request object,
101 unlike Ringbuffer::read()
104 RequestObject req (*vec.buf[0]);
105 i->second->increment_read_ptr (1);
106 request_buffer_map_lock.unlock ();
108 request_buffer_map_lock.lock ();
113 request_buffer_map_lock.unlock ();
116 template <typename RequestObject> void
117 AbstractUI<RequestObject>::send_request (RequestObject *req)
119 if (base_instance() == 0) {
120 return; /* XXX is this the right thing to do ? */
123 if (caller_is_ui_thread()) {
124 // cerr << "GUI thread sent request " << req << " type = " << req->type << endl;
127 RequestBuffer* rbuf = static_cast<RequestBuffer*> (pthread_getspecific (thread_request_buffer_key));
130 /* can't use the error system to report this, because this
131 thread isn't registered!
133 cerr << _("programming error: ")
134 << string_compose (X_("AbstractUI::send_request() called from %1, but no request buffer exists for that thread"), pthread_name())
139 // cerr << "thread " << pthread_self() << " sent request " << req << " type = " << req->type << endl;
141 rbuf->increment_write_ptr (1);
143 if (signal_pipe[1] >= 0) {
145 write (signal_pipe[1], &c, 1);