1 /* 2 * Copyright (C) 2009-2016 Paul Davis <paul@linuxaudiosystems.com> 3 * Copyright (C) 2015-2017 Robin Gareus <robin@gareus.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #ifndef __pbd_event_loop_h__ 21 #define __pbd_event_loop_h__ 22 23 #include <string> 24 #include <vector> 25 #include <map> 26 #include <boost/function.hpp> 27 #include <boost/bind.hpp> /* we don't need this here, but anything calling call_slot() probably will, so this is convenient */ 28 #include <stdint.h> 29 #include <pthread.h> 30 #include <glibmm/threads.h> 31 32 #include "pbd/libpbd_visibility.h" 33 34 namespace PBD 35 { 36 37 /** An EventLoop is as basic abstraction designed to be used with any "user 38 * interface" (not necessarily graphical) that needs to wait on 39 * events/requests and dispatch/process them as they arrive. 40 * 41 * This is a very basic class that doesn't by itself provide an actual 42 * event loop or thread. See BaseUI for the "real" object to be used 43 * when something like this is needed (it inherits from EventLoop). 44 */ 45 46 class LIBPBD_API EventLoop 47 { 48 public: 49 EventLoop (std::string const&); 50 virtual ~EventLoop(); 51 52 enum RequestType { 53 range_guarantee = ~0 54 }; 55 56 struct BaseRequestObject; 57 58 struct InvalidationRecord { 59 std::list<BaseRequestObject*> requests; 60 PBD::EventLoop* event_loop; 61 gint _valid; 62 gint _ref; 63 const char* file; 64 int line; 65 InvalidationRecordInvalidationRecord66 InvalidationRecord() : event_loop (0), _valid (1), _ref (0) {} invalidateInvalidationRecord67 void invalidate () { g_atomic_int_set (&_valid, 0); } validInvalidationRecord68 bool valid () { return g_atomic_int_get (&_valid) == 1; } 69 refInvalidationRecord70 void ref () { g_atomic_int_inc (&_ref); } unrefInvalidationRecord71 void unref () { (void) g_atomic_int_dec_and_test (&_ref); } in_useInvalidationRecord72 bool in_use () { return g_atomic_int_get (&_ref) > 0; } use_countInvalidationRecord73 int use_count () { return g_atomic_int_get (&_ref); } 74 }; 75 76 static void* invalidate_request (void* data); 77 78 struct BaseRequestObject { 79 RequestType type; 80 InvalidationRecord* invalidation; 81 boost::function<void()> the_slot; 82 BaseRequestObjectBaseRequestObject83 BaseRequestObject() : invalidation (0) {} ~BaseRequestObjectBaseRequestObject84 ~BaseRequestObject() { 85 if (invalidation) { 86 invalidation->unref (); 87 } 88 } 89 }; 90 91 virtual void call_slot (InvalidationRecord*, const boost::function<void()>&) = 0; 92 virtual Glib::Threads::Mutex& slot_invalidation_mutex() = 0; 93 event_loop_name()94 std::string event_loop_name() const { return _name; } 95 96 static EventLoop* get_event_loop_for_thread(); 97 static void set_event_loop_for_thread (EventLoop* ui); 98 99 struct ThreadBufferMapping { 100 pthread_t emitting_thread; 101 std::string target_thread_name; 102 void* request_buffer; 103 }; 104 105 static std::vector<ThreadBufferMapping> get_request_buffers_for_target_thread (const std::string&); 106 107 static void register_request_buffer_factory (const std::string& target_thread_name, void* (*factory) (uint32_t)); 108 static void pre_register (const std::string& emitting_thread_name, uint32_t num_requests); 109 static void remove_request_buffer_from_map (void* ptr); 110 111 std::list<InvalidationRecord*> trash; 112 113 private: 114 static Glib::Threads::Private<EventLoop> thread_event_loop; 115 std::string _name; 116 117 typedef std::map<std::string,ThreadBufferMapping> ThreadRequestBufferList; 118 static ThreadRequestBufferList thread_buffer_requests; 119 static Glib::Threads::RWLock thread_buffer_requests_lock; 120 121 struct RequestBufferSupplier { 122 123 /* @param name : name of object/entity that will/may accept 124 * requests from other threads, via a request buffer. 125 */ 126 std::string name; 127 128 /* @param factory : a function that can be called (with an 129 * argument specifying the @param number_of_requests) to create and 130 * return a request buffer for communicating with @param name) 131 */ 132 void* (*factory)(uint32_t nunber_of_requests); 133 }; 134 typedef std::vector<RequestBufferSupplier> RequestBufferSuppliers; 135 static RequestBufferSuppliers request_buffer_suppliers; 136 }; 137 138 } 139 140 #define MISSING_INVALIDATOR 0 // used to mark places where we fail to provide an invalidator 141 142 #endif /* __pbd_event_loop_h__ */ 143