Fix crash on startup if an LV2 plugin has a bad .ttl file.
[ardour.git] / libs / glibmm2 / glib / src / thread.ccg
1 // -*- c++ -*-
2 /* $Id: thread.ccg,v 1.9 2006/05/12 08:08:44 murrayc Exp $ */
3
4 /* Copyright (C) 2002 The gtkmm Development Team
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the Free
18  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include <glibmm/exceptionhandler.h>
22 #include <glib.h>
23
24
25 namespace
26 {
27
28 extern "C"
29 {
30
31 static void* call_thread_entry_slot(void* data)
32 {
33   sigc::slot_base *const slot = reinterpret_cast<sigc::slot_base*>(data);
34
35   #ifdef GLIBMM_EXCEPTIONS_ENABLED
36   try
37   {
38   #endif //GLIBMM_EXCEPTIONS_ENABLED
39     // Recreate the specific slot, and drop the reference obtained by create().
40     (*static_cast<sigc::slot<void>*>(slot))();
41   #ifdef GLIBMM_EXCEPTIONS_ENABLED
42   }
43   catch(Glib::Thread::Exit&)
44   {
45     // Just exit from the thread.  The Thread::Exit exception
46     // is our sane C++ replacement of g_thread_exit().
47   }
48   catch(...)
49   {
50     Glib::exception_handlers_invoke();
51   }
52   #endif //GLIBMM_EXCEPTIONS_ENABLED
53
54   delete slot;
55   return 0;
56 }
57
58 } //extern "C"
59
60 } // anonymous namespace
61
62
63 namespace Glib
64 {
65
66 // internal
67 void thread_init_impl()
68 {
69   // Make sure the exception map is initialized before creating any thread.
70   Glib::Error::register_init();
71 }
72
73
74 /**** Glib::Thread *********************************************************/
75
76 // static
77 Thread* Thread::create(const sigc::slot<void>& slot, bool joinable)
78 {
79   // Make a copy of slot on the heap
80   sigc::slot_base *const slot_copy = new sigc::slot<void>(slot);
81
82   GError* error = 0;
83
84   GThread *const thread = g_thread_create(
85       &call_thread_entry_slot, slot_copy, joinable, &error);
86
87   if(error)
88   {
89     delete slot_copy;
90     Glib::Error::throw_exception(error);
91   }
92
93   return reinterpret_cast<Thread*>(thread);
94 }
95
96 // static
97 Thread* Thread::create(const sigc::slot<void>& slot, unsigned long stack_size,
98                        bool joinable, bool bound, ThreadPriority priority)
99 {
100   // Make a copy of slot on the heap
101   sigc::slot_base *const slot_copy = new sigc::slot<void>(slot);
102
103   GError* error = 0;
104
105   GThread *const thread = g_thread_create_full(
106       &call_thread_entry_slot, slot_copy, stack_size, joinable,
107       bound, (GThreadPriority) priority, &error);
108
109   if(error)
110   {
111     delete slot_copy;
112     Glib::Error::throw_exception(error);
113   }
114
115   return reinterpret_cast<Thread*>(thread);
116 }
117
118 // static
119 Thread* Thread::self()
120 {
121   return reinterpret_cast<Thread*>(g_thread_self());
122 }
123
124 bool Thread::joinable() const
125 {
126   return gobject_.joinable;
127 }
128
129 void Thread::join()
130 {
131   g_thread_join(&gobject_);
132 }
133
134 void Thread::set_priority(ThreadPriority priority)
135 {
136   g_thread_set_priority(&gobject_, (GThreadPriority) priority);
137 }
138
139 ThreadPriority Thread::get_priority() const
140 {
141   return (ThreadPriority) gobject_.priority;
142 }
143
144 // static
145 void Thread::yield()
146 {
147   g_thread_yield();
148 }
149
150 Thread* wrap(GThread* gobject)
151 {
152   return reinterpret_cast<Thread*>(gobject);
153 }
154
155
156 /**** Glib::StaticMutex ****************************************************/
157
158 void StaticMutex::lock()
159 {
160   g_static_mutex_lock(&gobject_);
161 }
162
163 bool StaticMutex::trylock()
164 {
165   return g_static_mutex_trylock(&gobject_);
166 }
167
168 void StaticMutex::unlock()
169 {
170   g_static_mutex_unlock(&gobject_);
171 }
172
173 StaticMutex::operator Mutex&()
174 {
175   // If GStaticMutex is implemented as struct (e.g. on Linux), its first struct
176   // member (runtime_mutex) is a GMutex pointer.  If the gthread implementation
177   // is native (i.e. the vtable pointer passed to g_thread_init() was 0), then
178   // the runtime_mutex pointer is unused, and the rest of the GStaticMutex
179   // struct resembles the mutex data.
180   //
181   // On Win32, GStaticMutex is just a typedef to struct _GMutex*.  Either way,
182   // the first sizeof(GMutex*) bytes of GStaticMutex always resemble a GMutex
183   // pointer.  The gthread implementation relies on that, and we'll also do so.
184
185   GMutex*& runtime_mutex = reinterpret_cast<GMutex*&>(gobject_);
186
187   // Fortunately, it cannot hurt if we set this to the GMutex pointer returned
188   // by g_static_mutex_get_mutex().  Either we just overwrite it with the same
189   // value, or it was unused anyway.  Doing that allows casting the pointer
190   // location to a Glib::Mutex reference (its only data member is a GMutex*).
191
192   runtime_mutex = g_static_mutex_get_mutex(&gobject_);
193
194   return reinterpret_cast<Mutex&>(runtime_mutex);
195 }
196
197
198 /**** Glib::Mutex **********************************************************/
199
200 Mutex::Mutex()
201 :
202   gobject_ (g_mutex_new())
203 {}
204
205 Mutex::~Mutex()
206 {
207   g_mutex_free(gobject_);
208 }
209
210 void Mutex::lock()
211 {
212   g_mutex_lock(gobject_);
213 }
214
215 bool Mutex::trylock()
216 {
217   return g_mutex_trylock(gobject_);
218 }
219
220 void Mutex::unlock()
221 {
222   g_mutex_unlock(gobject_);
223 }
224
225
226 /**** Glib::StaticRecMutex *************************************************/
227
228 void StaticRecMutex::lock()
229 {
230   g_static_rec_mutex_lock(&gobject_);
231 }
232
233 bool StaticRecMutex::trylock()
234 {
235   return g_static_rec_mutex_trylock(&gobject_);
236 }
237
238 void StaticRecMutex::unlock()
239 {
240   g_static_rec_mutex_unlock(&gobject_);
241 }
242
243 void StaticRecMutex::lock_full(unsigned int depth)
244 {
245   g_static_rec_mutex_lock_full(&gobject_, depth);
246 }
247
248 unsigned int StaticRecMutex::unlock_full()
249 {
250   return g_static_rec_mutex_unlock_full(&gobject_);
251 }
252
253 StaticRecMutex::operator RecMutex&()
254 {
255   return static_cast<RecMutex&>(*this);
256 }
257
258
259 /**** Glib::RecMutex *******************************************************/
260
261 RecMutex::RecMutex()
262 {
263   g_static_rec_mutex_init(&gobject_);
264
265   // GLib doesn't have GRecMutex, only GStaticRecMutex.  Force initialization
266   // of the mutex now, to mimic the behaviour of a (hypothetical) GRecMutex.
267   g_static_mutex_get_mutex(&gobject_.mutex);
268 }
269
270 RecMutex::~RecMutex()
271 {
272   g_static_rec_mutex_free(&gobject_);
273 }
274
275
276 /**** Glib::StaticRWLock ***************************************************/
277
278 void StaticRWLock::reader_lock()
279 {
280   g_static_rw_lock_reader_lock(&gobject_);
281 }
282
283 bool StaticRWLock::reader_trylock()
284 {
285   return g_static_rw_lock_reader_trylock(&gobject_);
286 }
287
288 void StaticRWLock::reader_unlock()
289 {
290   g_static_rw_lock_reader_unlock(&gobject_);
291 }
292
293 void StaticRWLock::writer_lock()
294 {
295   g_static_rw_lock_writer_lock(&gobject_);
296 }
297
298 bool StaticRWLock::writer_trylock()
299 {
300   return g_static_rw_lock_writer_trylock(&gobject_);
301 }
302
303 void StaticRWLock::writer_unlock()
304 {
305   g_static_rw_lock_writer_unlock(&gobject_);
306 }
307
308 StaticRWLock::operator RWLock&()
309 {
310   return static_cast<RWLock&>(*this);
311 }
312
313
314 /**** Glib::RWLock *********************************************************/
315
316 RWLock::RWLock()
317 {
318   g_static_rw_lock_init(&gobject_);
319
320   // GLib doesn't have GRWLock, only GStaticRWLock.  Force initialization
321   // of the mutex and the condition variables now, to mimic the behaviour
322   // of a (hypothetical) GRWLock.
323
324   if(g_static_mutex_get_mutex(&gobject_.mutex))
325   {
326     gobject_.read_cond  = g_cond_new();
327     gobject_.write_cond = g_cond_new();
328   }
329 }
330
331 RWLock::~RWLock()
332 {
333   g_static_rw_lock_free(&gobject_);
334 }
335
336
337 /**** Glib::Cond ***********************************************************/
338
339 Cond::Cond()
340 :
341   gobject_ (g_cond_new())
342 {}
343
344 Cond::~Cond()
345 {
346   g_cond_free(gobject_);
347 }
348
349 void Cond::signal()
350 {
351   g_cond_signal(gobject_);
352 }
353
354 void Cond::broadcast()
355 {
356   g_cond_broadcast(gobject_);
357 }
358
359 void Cond::wait(Mutex& mutex)
360 {
361   g_cond_wait(gobject_, mutex.gobj());
362 }
363
364 bool Cond::timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time)
365 {
366   return g_cond_timed_wait(gobject_, mutex.gobj(), const_cast<Glib::TimeVal*>(&abs_time));
367 }
368
369
370 } // namespace Glib
371