2013-01-16 18:15:38 +00:00
/*
2015-10-04 14:51:05 -04:00
Copyright ( C ) 2012 Paul Davis
2013-01-16 18:15:38 +00:00
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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
2015-12-28 10:14:17 -05:00
# include "pbd/compose.h"
2016-01-13 21:13:55 -05:00
# include "pbd/debug.h"
2009-12-21 18:23:07 +00:00
# include "pbd/event_loop.h"
2015-12-28 10:14:17 -05:00
# include "pbd/error.h"
2010-03-30 15:18:43 +00:00
# include "pbd/stacktrace.h"
2009-12-21 18:23:07 +00:00
2015-12-28 10:14:17 -05:00
# include "i18n.h"
2009-12-21 18:23:07 +00:00
using namespace PBD ;
2010-03-30 15:18:43 +00:00
using namespace std ;
2009-12-21 18:23:07 +00:00
static void do_not_delete_the_loop_pointer ( void * ) { }
2015-10-04 14:51:05 -04:00
Glib : : Threads : : Private < EventLoop > EventLoop : : thread_event_loop ( do_not_delete_the_loop_pointer ) ;
2012-07-25 17:48:55 +00:00
2015-12-28 10:14:17 -05:00
Glib : : Threads : : RWLock EventLoop : : thread_buffer_requests_lock ;
EventLoop : : ThreadRequestBufferList EventLoop : : thread_buffer_requests ;
EventLoop : : RequestBufferSuppliers EventLoop : : request_buffer_suppliers ;
2015-12-12 10:55:40 -05:00
EventLoop : : EventLoop ( string const & name )
: _name ( name )
{
}
2015-10-04 14:51:05 -04:00
EventLoop *
2015-12-28 10:14:17 -05:00
EventLoop : : get_event_loop_for_thread ( )
{
2009-12-21 18:23:07 +00:00
return thread_event_loop . get ( ) ;
}
2015-10-04 14:51:05 -04:00
void
EventLoop : : set_event_loop_for_thread ( EventLoop * loop )
2009-12-21 18:23:07 +00:00
{
2012-07-25 17:48:55 +00:00
thread_event_loop . set ( loop ) ;
2009-12-21 18:23:07 +00:00
}
2015-10-04 14:51:05 -04:00
void *
2010-03-30 15:18:43 +00:00
EventLoop : : invalidate_request ( void * data )
{
InvalidationRecord * ir = ( InvalidationRecord * ) data ;
2012-04-24 16:45:38 +00:00
/* Some of the requests queued with an EventLoop may involve functors
* that make method calls to objects whose lifetime is shorter
* than the EventLoop ' s . We do not want to make those calls if the
2015-10-04 14:51:05 -04:00
* object involve has been destroyed . To prevent this , we
2012-04-24 16:45:38 +00:00
* provide a way to invalidate those requests when the object is
* destroyed .
*
* An object was passed to __invalidator ( ) which added a callback to
* EventLoop : : invalidate_request ( ) to its " notify when destroyed "
* list . __invalidator ( ) returned an InvalidationRecord that has been
* to passed to this function as data .
*
* The object is currently being destroyed and so we want to
* mark all requests involving this object that are queued with
2015-10-04 14:51:05 -04:00
* any EventLoop as invalid .
2012-04-24 16:45:38 +00:00
*
* As of April 2012 , we are usign sigc : : trackable as the base object
* used to queue calls to : : invalidate_request ( ) to be made upon
* destruction , via its : : add_destroy_notify_callback ( ) API . This is
* not necessarily ideal , but it is very close to precisely what we
* want , and many of the objects we want to do this with already
* inherit ( indirectly ) from sigc : : trackable .
*/
2015-10-05 16:17:49 +02:00
2010-03-30 15:18:43 +00:00
if ( ir - > event_loop ) {
2012-07-25 17:48:55 +00:00
Glib : : Threads : : Mutex : : Lock lm ( ir - > event_loop - > slot_invalidation_mutex ( ) ) ;
2010-04-03 00:42:39 +00:00
for ( list < BaseRequestObject * > : : iterator i = ir - > requests . begin ( ) ; i ! = ir - > requests . end ( ) ; + + i ) {
( * i ) - > valid = false ;
( * i ) - > invalidation = 0 ;
}
delete ir ;
2015-10-04 14:51:05 -04:00
}
2010-03-30 15:18:43 +00:00
return 0 ;
}
2015-12-28 10:14:17 -05:00
vector < EventLoop : : ThreadBufferMapping >
EventLoop : : get_request_buffers_for_target_thread ( const std : : string & target_thread )
{
vector < ThreadBufferMapping > ret ;
Glib : : Threads : : RWLock : : WriterLock lm ( thread_buffer_requests_lock ) ;
for ( ThreadRequestBufferList : : const_iterator x = thread_buffer_requests . begin ( ) ;
x ! = thread_buffer_requests . end ( ) ; + + x ) {
if ( x - > second . target_thread_name = = target_thread ) {
ret . push_back ( x - > second ) ;
}
}
2016-01-13 21:13:55 -05:00
DEBUG_TRACE ( PBD : : DEBUG : : EventLoop , string_compose ( " for thread \" %1 \" , found %2 request buffers \n " , target_thread , ret . size ( ) ) ) ;
2015-12-28 10:14:17 -05:00
return ret ;
}
void
EventLoop : : register_request_buffer_factory ( const string & target_thread_name ,
void * ( * factory ) ( uint32_t ) )
{
RequestBufferSupplier trs ;
trs . name = target_thread_name ;
trs . factory = factory ;
{
Glib : : Threads : : RWLock : : WriterLock lm ( thread_buffer_requests_lock ) ;
request_buffer_suppliers . push_back ( trs ) ;
}
}
void
EventLoop : : pre_register ( const string & emitting_thread_name , uint32_t num_requests )
{
/* Threads that need to emit signals "towards" other threads, but with
RT safe behavior may be created before the receiving threads
exist . This makes it impossible for them to use the
ThreadCreatedWithRequestSize signal to notify receiving threads of
their existence .
This function creates a request buffer for them to use with
the ( not yet ) created threads , and stores it where the receiving
thread can find it later .
*/
ThreadBufferMapping mapping ;
Glib : : Threads : : RWLock : : ReaderLock lm ( thread_buffer_requests_lock ) ;
for ( RequestBufferSuppliers : : iterator trs = request_buffer_suppliers . begin ( ) ; trs ! = request_buffer_suppliers . end ( ) ; + + trs ) {
if ( ! trs - > factory ) {
/* no factory - no request buffer required or expected */
continue ;
}
if ( emitting_thread_name = = trs - > name ) {
/* no need to register an emitter with itself */
continue ;
}
mapping . emitting_thread = pthread_self ( ) ;
mapping . target_thread_name = trs - > name ;
/* Allocate a suitably sized request buffer. This will set the
* thread - local variable that holds a pointer to this request
* buffer .
*/
mapping . request_buffer = trs - > factory ( num_requests ) ;
/* now store it where the receiving thread (trs->name) can find
it if and when it is created . ( Discovery happens in the
AbstractUI constructor . Note that if
*/
/* make a key composed of the emitter and receiver thread names */
string key = emitting_thread_name ;
key + = ' / ' ;
key + = mapping . target_thread_name ;
/* if the emitting thread was killed and recreated (with the
* same name ) , this will replace the entry in
* thread_buffer_requests . The old entry will be lazily deleted
* when the target thread finds the request buffer and realizes
* that it is dead .
*
* If the request buffer is replaced before the target thread
* ever finds the dead version , we will leak the old request
* buffer .
*/
thread_buffer_requests [ key ] = mapping ;
2016-01-13 21:13:55 -05:00
DEBUG_TRACE ( PBD : : DEBUG : : EventLoop , string_compose ( " pre-registered request buffer for \" %1 \" to send to \" %2 \" , buffer @ %3 \n " , emitting_thread_name , trs - > name , mapping . request_buffer ) ) ;
2015-12-28 10:14:17 -05:00
}
}