4 #include "pbd/stacktrace.h"
5 #include "pbd/abstract_ui.h"
6 #include "pbd/pthread_utils.h"
7 #include "pbd/failed_constructor.h"
13 static void do_not_delete_the_request_buffer (void*) { }
16 Glib::StaticPrivate<typename AbstractUI<R>::RequestBuffer> AbstractUI<R>::per_thread_request_buffer;
18 template <typename RequestObject>
19 AbstractUI<RequestObject>::AbstractUI (const string& name)
22 void (AbstractUI<RequestObject>::*pmf)(string,pthread_t,string,uint32_t) = &AbstractUI<RequestObject>::register_thread;
24 /* better to make this connect a handler that runs in the UI event loop but the syntax seems hard, and
25 register_thread() is thread safe anyway.
28 PBD::ThreadCreatedWithRequestSize.connect_same_thread (new_thread_connection, boost::bind (pmf, this, _1, _2, _3, _4));
31 template <typename RequestObject> void
32 AbstractUI<RequestObject>::register_thread (string target_gui, pthread_t thread_id, string /*thread name*/, uint32_t num_requests)
34 if (target_gui != name()) {
38 RequestBuffer* b = new RequestBuffer (num_requests);
41 Glib::Mutex::Lock lm (request_buffer_map_lock);
42 request_buffers[thread_id] = b;
45 per_thread_request_buffer.set (b, do_not_delete_the_request_buffer);
48 template <typename RequestObject> RequestObject*
49 AbstractUI<RequestObject>::get_request (RequestType rt)
51 RequestBuffer* rbuf = per_thread_request_buffer.get ();
52 RequestBufferVector vec;
55 /* we have a per-thread FIFO, use it */
57 rbuf->get_write_vector (&vec);
59 if (vec.len[0] == 0) {
63 vec.buf[0]->type = rt;
64 vec.buf[0]->valid = true;
68 RequestObject* req = new RequestObject;
74 template <typename RequestObject> void
75 AbstractUI<RequestObject>::handle_ui_requests ()
77 RequestBufferMapIterator i;
78 RequestBufferVector vec;
80 /* per-thread buffers first */
82 request_buffer_map_lock.lock ();
84 for (i = request_buffers.begin(); i != request_buffers.end(); ++i) {
88 /* we must process requests 1 by 1 because
89 the request may run a recursive main
90 event loop that will itself call
91 handle_ui_requests. when we return
92 from the request handler, we cannot
93 expect that the state of queued requests
94 is even remotely consistent with
95 the condition before we called it.
98 i->second->get_read_vector (&vec);
100 if (vec.len[0] == 0) {
103 if (vec.buf[0]->valid) {
104 request_buffer_map_lock.unlock ();
105 do_request (vec.buf[0]);
106 request_buffer_map_lock.lock ();
107 if (vec.buf[0]->invalidation) {
108 vec.buf[0]->invalidation->requests.remove (vec.buf[0]);
110 i->second->increment_read_ptr (1);
116 request_buffer_map_lock.unlock ();
118 /* and now, the generic request buffer. same rules as above apply */
120 Glib::Mutex::Lock lm (request_list_lock);
122 while (!request_list.empty()) {
123 RequestObject* req = request_list.front ();
124 request_list.pop_front ();
126 /* We need to use this lock, because its the one
127 returned by slot_invalidation_mutex() and protects
128 against request invalidation.
131 request_buffer_map_lock.lock ();
134 request_buffer_map_lock.unlock ();
138 /* we're about to execute this request, so its
139 too late for any invalidation. mark
140 the request as "done" before we start.
143 if (req->invalidation) {
144 req->invalidation->requests.remove (req);
147 request_buffer_map_lock.unlock ();
159 template <typename RequestObject> void
160 AbstractUI<RequestObject>::send_request (RequestObject *req)
162 if (base_instance() == 0) {
163 return; /* XXX is this the right thing to do ? */
166 if (caller_is_self ()) {
169 RequestBuffer* rbuf = per_thread_request_buffer.get ();
172 rbuf->increment_write_ptr (1);
174 /* no per-thread buffer, so just use a list with a lock so that it remains
175 single-reader/single-writer semantics
177 Glib::Mutex::Lock lm (request_list_lock);
178 request_list.push_back (req);
181 request_channel.wakeup ();
185 template<typename RequestObject> void
186 AbstractUI<RequestObject>::call_slot (InvalidationRecord* invalidation, const boost::function<void()>& f)
188 if (caller_is_self()) {
193 RequestObject *req = get_request (BaseUI::CallSlot);
200 req->invalidation = invalidation;
203 invalidation->requests.push_back (req);
204 invalidation->event_loop = this;