2 /* $Id: thread.ccg,v 1.9 2006/05/12 08:08:44 murrayc Exp $ */
4 /* Copyright (C) 2002 The gtkmm Development Team
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.
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.
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.
21 #include <glibmm/exceptionhandler.h>
31 static void* call_thread_entry_slot(void* data)
33 sigc::slot_base *const slot = reinterpret_cast<sigc::slot_base*>(data);
35 #ifdef GLIBMM_EXCEPTIONS_ENABLED
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
43 catch(Glib::Thread::Exit&)
45 // Just exit from the thread. The Thread::Exit exception
46 // is our sane C++ replacement of g_thread_exit().
50 Glib::exception_handlers_invoke();
52 #endif //GLIBMM_EXCEPTIONS_ENABLED
60 } // anonymous namespace
67 void thread_init_impl()
69 // Make sure the exception map is initialized before creating any thread.
70 Glib::Error::register_init();
74 /**** Glib::Thread *********************************************************/
77 Thread* Thread::create(const sigc::slot<void>& slot, bool joinable)
79 // Make a copy of slot on the heap
80 sigc::slot_base *const slot_copy = new sigc::slot<void>(slot);
84 GThread *const thread = g_thread_create(
85 &call_thread_entry_slot, slot_copy, joinable, &error);
90 Glib::Error::throw_exception(error);
93 return reinterpret_cast<Thread*>(thread);
97 Thread* Thread::create(const sigc::slot<void>& slot, unsigned long stack_size,
98 bool joinable, bool bound, ThreadPriority priority)
100 // Make a copy of slot on the heap
101 sigc::slot_base *const slot_copy = new sigc::slot<void>(slot);
105 GThread *const thread = g_thread_create_full(
106 &call_thread_entry_slot, slot_copy, stack_size, joinable,
107 bound, (GThreadPriority) priority, &error);
112 Glib::Error::throw_exception(error);
115 return reinterpret_cast<Thread*>(thread);
119 Thread* Thread::self()
121 return reinterpret_cast<Thread*>(g_thread_self());
124 bool Thread::joinable() const
126 return gobject_.joinable;
131 g_thread_join(&gobject_);
134 void Thread::set_priority(ThreadPriority priority)
136 g_thread_set_priority(&gobject_, (GThreadPriority) priority);
139 ThreadPriority Thread::get_priority() const
141 return (ThreadPriority) gobject_.priority;
150 Thread* wrap(GThread* gobject)
152 return reinterpret_cast<Thread*>(gobject);
156 /**** Glib::StaticMutex ****************************************************/
158 void StaticMutex::lock()
160 g_static_mutex_lock(&gobject_);
163 bool StaticMutex::trylock()
165 return g_static_mutex_trylock(&gobject_);
168 void StaticMutex::unlock()
170 g_static_mutex_unlock(&gobject_);
173 StaticMutex::operator Mutex&()
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.
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.
185 GMutex*& runtime_mutex = reinterpret_cast<GMutex*&>(gobject_);
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*).
192 runtime_mutex = g_static_mutex_get_mutex(&gobject_);
194 return reinterpret_cast<Mutex&>(runtime_mutex);
198 /**** Glib::Mutex **********************************************************/
202 gobject_ (g_mutex_new())
207 g_mutex_free(gobject_);
212 g_mutex_lock(gobject_);
215 bool Mutex::trylock()
217 return g_mutex_trylock(gobject_);
222 g_mutex_unlock(gobject_);
226 /**** Glib::StaticRecMutex *************************************************/
228 void StaticRecMutex::lock()
230 g_static_rec_mutex_lock(&gobject_);
233 bool StaticRecMutex::trylock()
235 return g_static_rec_mutex_trylock(&gobject_);
238 void StaticRecMutex::unlock()
240 g_static_rec_mutex_unlock(&gobject_);
243 void StaticRecMutex::lock_full(unsigned int depth)
245 g_static_rec_mutex_lock_full(&gobject_, depth);
248 unsigned int StaticRecMutex::unlock_full()
250 return g_static_rec_mutex_unlock_full(&gobject_);
253 StaticRecMutex::operator RecMutex&()
255 return static_cast<RecMutex&>(*this);
259 /**** Glib::RecMutex *******************************************************/
263 g_static_rec_mutex_init(&gobject_);
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);
270 RecMutex::~RecMutex()
272 g_static_rec_mutex_free(&gobject_);
276 /**** Glib::StaticRWLock ***************************************************/
278 void StaticRWLock::reader_lock()
280 g_static_rw_lock_reader_lock(&gobject_);
283 bool StaticRWLock::reader_trylock()
285 return g_static_rw_lock_reader_trylock(&gobject_);
288 void StaticRWLock::reader_unlock()
290 g_static_rw_lock_reader_unlock(&gobject_);
293 void StaticRWLock::writer_lock()
295 g_static_rw_lock_writer_lock(&gobject_);
298 bool StaticRWLock::writer_trylock()
300 return g_static_rw_lock_writer_trylock(&gobject_);
303 void StaticRWLock::writer_unlock()
305 g_static_rw_lock_writer_unlock(&gobject_);
308 StaticRWLock::operator RWLock&()
310 return static_cast<RWLock&>(*this);
314 /**** Glib::RWLock *********************************************************/
318 g_static_rw_lock_init(&gobject_);
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.
324 if(g_static_mutex_get_mutex(&gobject_.mutex))
326 gobject_.read_cond = g_cond_new();
327 gobject_.write_cond = g_cond_new();
333 g_static_rw_lock_free(&gobject_);
337 /**** Glib::Cond ***********************************************************/
341 gobject_ (g_cond_new())
346 g_cond_free(gobject_);
351 g_cond_signal(gobject_);
354 void Cond::broadcast()
356 g_cond_broadcast(gobject_);
359 void Cond::wait(Mutex& mutex)
361 g_cond_wait(gobject_, mutex.gobj());
364 bool Cond::timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time)
366 return g_cond_timed_wait(gobject_, mutex.gobj(), const_cast<Glib::TimeVal*>(&abs_time));