// -*- c++ -*- /* $Id: thread.ccg,v 1.9 2006/05/12 08:08:44 murrayc Exp $ */ /* Copyright (C) 2002 The gtkmm Development Team * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include namespace { extern "C" { static void* call_thread_entry_slot(void* data) { sigc::slot_base *const slot = reinterpret_cast(data); #ifdef GLIBMM_EXCEPTIONS_ENABLED try { #endif //GLIBMM_EXCEPTIONS_ENABLED // Recreate the specific slot, and drop the reference obtained by create(). (*static_cast*>(slot))(); #ifdef GLIBMM_EXCEPTIONS_ENABLED } catch(Glib::Thread::Exit&) { // Just exit from the thread. The Thread::Exit exception // is our sane C++ replacement of g_thread_exit(). } catch(...) { Glib::exception_handlers_invoke(); } #endif //GLIBMM_EXCEPTIONS_ENABLED delete slot; return 0; } } //extern "C" } // anonymous namespace namespace Glib { // internal void thread_init_impl() { // Make sure the exception map is initialized before creating any thread. Glib::Error::register_init(); } /**** Glib::Thread *********************************************************/ // static Thread* Thread::create(const sigc::slot& slot, bool joinable) { // Make a copy of slot on the heap sigc::slot_base *const slot_copy = new sigc::slot(slot); GError* error = 0; GThread *const thread = g_thread_create( &call_thread_entry_slot, slot_copy, joinable, &error); if(error) { delete slot_copy; Glib::Error::throw_exception(error); } return reinterpret_cast(thread); } // static Thread* Thread::create(const sigc::slot& slot, unsigned long stack_size, bool joinable, bool bound, ThreadPriority priority) { // Make a copy of slot on the heap sigc::slot_base *const slot_copy = new sigc::slot(slot); GError* error = 0; GThread *const thread = g_thread_create_full( &call_thread_entry_slot, slot_copy, stack_size, joinable, bound, (GThreadPriority) priority, &error); if(error) { delete slot_copy; Glib::Error::throw_exception(error); } return reinterpret_cast(thread); } // static Thread* Thread::self() { return reinterpret_cast(g_thread_self()); } bool Thread::joinable() const { return gobject_.joinable; } void Thread::join() { g_thread_join(&gobject_); } void Thread::set_priority(ThreadPriority priority) { g_thread_set_priority(&gobject_, (GThreadPriority) priority); } ThreadPriority Thread::get_priority() const { return (ThreadPriority) gobject_.priority; } // static void Thread::yield() { g_thread_yield(); } Thread* wrap(GThread* gobject) { return reinterpret_cast(gobject); } /**** Glib::StaticMutex ****************************************************/ void StaticMutex::lock() { g_static_mutex_lock(&gobject_); } bool StaticMutex::trylock() { return g_static_mutex_trylock(&gobject_); } void StaticMutex::unlock() { g_static_mutex_unlock(&gobject_); } StaticMutex::operator Mutex&() { // If GStaticMutex is implemented as struct (e.g. on Linux), its first struct // member (runtime_mutex) is a GMutex pointer. If the gthread implementation // is native (i.e. the vtable pointer passed to g_thread_init() was 0), then // the runtime_mutex pointer is unused, and the rest of the GStaticMutex // struct resembles the mutex data. // // On Win32, GStaticMutex is just a typedef to struct _GMutex*. Either way, // the first sizeof(GMutex*) bytes of GStaticMutex always resemble a GMutex // pointer. The gthread implementation relies on that, and we'll also do so. GMutex*& runtime_mutex = reinterpret_cast(gobject_); // Fortunately, it cannot hurt if we set this to the GMutex pointer returned // by g_static_mutex_get_mutex(). Either we just overwrite it with the same // value, or it was unused anyway. Doing that allows casting the pointer // location to a Glib::Mutex reference (its only data member is a GMutex*). runtime_mutex = g_static_mutex_get_mutex(&gobject_); return reinterpret_cast(runtime_mutex); } /**** Glib::Mutex **********************************************************/ Mutex::Mutex() : gobject_ (g_mutex_new()) {} Mutex::~Mutex() { g_mutex_free(gobject_); } void Mutex::lock() { g_mutex_lock(gobject_); } bool Mutex::trylock() { return g_mutex_trylock(gobject_); } void Mutex::unlock() { g_mutex_unlock(gobject_); } /**** Glib::StaticRecMutex *************************************************/ void StaticRecMutex::lock() { g_static_rec_mutex_lock(&gobject_); } bool StaticRecMutex::trylock() { return g_static_rec_mutex_trylock(&gobject_); } void StaticRecMutex::unlock() { g_static_rec_mutex_unlock(&gobject_); } void StaticRecMutex::lock_full(unsigned int depth) { g_static_rec_mutex_lock_full(&gobject_, depth); } unsigned int StaticRecMutex::unlock_full() { return g_static_rec_mutex_unlock_full(&gobject_); } StaticRecMutex::operator RecMutex&() { return static_cast(*this); } /**** Glib::RecMutex *******************************************************/ RecMutex::RecMutex() { g_static_rec_mutex_init(&gobject_); // GLib doesn't have GRecMutex, only GStaticRecMutex. Force initialization // of the mutex now, to mimic the behaviour of a (hypothetical) GRecMutex. g_static_mutex_get_mutex(&gobject_.mutex); } RecMutex::~RecMutex() { g_static_rec_mutex_free(&gobject_); } /**** Glib::StaticRWLock ***************************************************/ void StaticRWLock::reader_lock() { g_static_rw_lock_reader_lock(&gobject_); } bool StaticRWLock::reader_trylock() { return g_static_rw_lock_reader_trylock(&gobject_); } void StaticRWLock::reader_unlock() { g_static_rw_lock_reader_unlock(&gobject_); } void StaticRWLock::writer_lock() { g_static_rw_lock_writer_lock(&gobject_); } bool StaticRWLock::writer_trylock() { return g_static_rw_lock_writer_trylock(&gobject_); } void StaticRWLock::writer_unlock() { g_static_rw_lock_writer_unlock(&gobject_); } StaticRWLock::operator RWLock&() { return static_cast(*this); } /**** Glib::RWLock *********************************************************/ RWLock::RWLock() { g_static_rw_lock_init(&gobject_); // GLib doesn't have GRWLock, only GStaticRWLock. Force initialization // of the mutex and the condition variables now, to mimic the behaviour // of a (hypothetical) GRWLock. if(g_static_mutex_get_mutex(&gobject_.mutex)) { gobject_.read_cond = g_cond_new(); gobject_.write_cond = g_cond_new(); } } RWLock::~RWLock() { g_static_rw_lock_free(&gobject_); } /**** Glib::Cond ***********************************************************/ Cond::Cond() : gobject_ (g_cond_new()) {} Cond::~Cond() { g_cond_free(gobject_); } void Cond::signal() { g_cond_signal(gobject_); } void Cond::broadcast() { g_cond_broadcast(gobject_); } void Cond::wait(Mutex& mutex) { g_cond_wait(gobject_, mutex.gobj()); } bool Cond::timed_wait(Mutex& mutex, const Glib::TimeVal& abs_time) { return g_cond_timed_wait(gobject_, mutex.gobj(), const_cast(&abs_time)); } } // namespace Glib