// -*- c++ -*- /* $Id$ */ /* 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 #include #include #include GLIBMM_USING_STD(list) namespace Glib { // internal class ThreadPool::SlotList { public: SlotList(); ~SlotList(); sigc::slot* push(const sigc::slot& slot); sigc::slot pop(sigc::slot* slot_ptr); void lock_and_unlock(); private: Glib::Mutex mutex_; std::list< sigc::slot > list_; // noncopyable SlotList(const ThreadPool::SlotList&); ThreadPool::SlotList& operator=(const ThreadPool::SlotList&); }; ThreadPool::SlotList::SlotList() {} ThreadPool::SlotList::~SlotList() {} sigc::slot* ThreadPool::SlotList::push(const sigc::slot& slot) { Mutex::Lock lock (mutex_); list_.push_back(slot); return &list_.back(); } sigc::slot ThreadPool::SlotList::pop(sigc::slot* slot_ptr) { sigc::slot slot; { Mutex::Lock lock (mutex_); std::list< sigc::slot >::iterator pslot = list_.begin(); while(pslot != list_.end() && slot_ptr != &*pslot) ++pslot; if(pslot != list_.end()) { slot = *pslot; list_.erase(pslot); } } return slot; } void ThreadPool::SlotList::lock_and_unlock() { mutex_.lock(); mutex_.unlock(); } } // namespace Glib namespace { static void call_thread_entry_slot(void* data, void* user_data) { try { Glib::ThreadPool::SlotList *const slot_list = static_cast(user_data); sigc::slot slot (slot_list->pop(static_cast*>(data))); slot(); } 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(); } } } // anonymous namespace namespace Glib { ThreadPool::ThreadPool(int max_threads, bool exclusive) : gobject_ (0), slot_list_ (new SlotList()) { GError* error = 0; gobject_ = g_thread_pool_new( &call_thread_entry_slot, slot_list_, max_threads, exclusive, &error); if(error) { delete slot_list_; slot_list_ = 0; Glib::Error::throw_exception(error); } } ThreadPool::~ThreadPool() { if(gobject_) g_thread_pool_free(gobject_, 1, 1); if(slot_list_) { slot_list_->lock_and_unlock(); delete slot_list_; } } void ThreadPool::push(const sigc::slot& slot) { sigc::slot *const slot_ptr = slot_list_->push(slot); GError* error = 0; g_thread_pool_push(gobject_, slot_ptr, &error); if(error) { slot_list_->pop(slot_ptr); Glib::Error::throw_exception(error); } } void ThreadPool::set_max_threads(int max_threads) { GError* error = 0; g_thread_pool_set_max_threads(gobject_, max_threads, &error); if(error) Glib::Error::throw_exception(error); } int ThreadPool::get_max_threads() const { return g_thread_pool_get_max_threads(gobject_); } unsigned int ThreadPool::get_num_threads() const { return g_thread_pool_get_num_threads(gobject_); } unsigned int ThreadPool::unprocessed() const { return g_thread_pool_unprocessed(gobject_); } bool ThreadPool::get_exclusive() const { g_return_val_if_fail(gobject_ != 0, false); return gobject_->exclusive; } void ThreadPool::shutdown(bool immediately) { if(gobject_) { g_thread_pool_free(gobject_, immediately, 1); gobject_ = 0; } if(slot_list_) { slot_list_->lock_and_unlock(); delete slot_list_; slot_list_ = 0; } } // static void ThreadPool::set_max_unused_threads(int max_threads) { g_thread_pool_set_max_unused_threads(max_threads); } // static int ThreadPool::get_max_unused_threads() { return g_thread_pool_get_max_unused_threads(); } // static unsigned int ThreadPool::get_num_unused_threads() { return g_thread_pool_get_num_unused_threads(); } // static void ThreadPool::stop_unused_threads() { g_thread_pool_stop_unused_threads(); } } // namespace Glib