thread.cpp

Go to the documentation of this file.
00001 /* $Id: thread.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 /*
00003    Copyright (C) 2003 - 2012 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 #include "global.hpp"
00017 
00018 #include <vector>
00019 
00020 #include "log.hpp"
00021 #include "thread.hpp"
00022 
00023 
00024 #define ERR_G LOG_STREAM(err, lg::general)
00025 
00026 
00027 static int run_async_operation(void* data)
00028 {
00029     threading::async_operation_ptr op(*reinterpret_cast<threading::async_operation_ptr*>(data));
00030     op->run();
00031 
00032     const threading::lock l(op->get_mutex());
00033     op->notify_finished(); //in case the operation didn't notify of finishing
00034 
00035     return 0;
00036 }
00037 
00038 namespace {
00039 
00040 std::vector<SDL_Thread*> detached_threads;
00041 
00042 }
00043 
00044 namespace threading {
00045 
00046 manager::~manager()
00047 {
00048     for(std::vector<SDL_Thread*>::iterator i = detached_threads.begin(); i != detached_threads.end(); ++i) {
00049         SDL_WaitThread(*i,NULL);
00050     }
00051 }
00052 
00053 thread::thread(int (*f)(void*), void* data) : thread_(SDL_CreateThread(f,data))
00054 {}
00055 
00056 thread::~thread()
00057 {
00058     join();
00059 }
00060 
00061 void thread::kill()
00062 {
00063     if(thread_ != NULL) {
00064         SDL_KillThread(thread_);
00065         thread_ = NULL;
00066     }
00067 }
00068 
00069 void thread::join()
00070 {
00071     if(thread_ != NULL) {
00072         SDL_WaitThread(thread_,NULL);
00073         thread_ = NULL;
00074     }
00075 }
00076 
00077 void thread::detach()
00078 {
00079     detached_threads.push_back(thread_);
00080     thread_ = NULL;
00081 }
00082 
00083 mutex::mutex() : m_(SDL_CreateMutex())
00084 {}
00085 
00086 mutex::~mutex()
00087 {
00088     SDL_DestroyMutex(m_);
00089 }
00090 
00091 lock::lock(mutex& m) : m_(m)
00092 {
00093     SDL_mutexP(m_.m_);
00094 }
00095 
00096 lock::~lock()
00097 {
00098     SDL_mutexV(m_.m_);
00099 }
00100 
00101 condition::condition() : cond_(SDL_CreateCond())
00102 {}
00103 
00104 condition::~condition()
00105 {
00106     SDL_DestroyCond(cond_);
00107 }
00108 
00109 bool condition::wait(const mutex& m)
00110 {
00111     return SDL_CondWait(cond_,m.m_) == 0;
00112 }
00113 
00114 condition::WAIT_TIMEOUT_RESULT condition::wait_timeout(const mutex& m, unsigned int timeout)
00115 {
00116     const int res = SDL_CondWaitTimeout(cond_,m.m_,timeout);
00117     switch(res) {
00118         case 0: return WAIT_OK;
00119         case SDL_MUTEX_TIMEDOUT: return WAIT_TIMED_OUT;
00120         default:
00121             ERR_G << "SDL_CondWaitTimeout: " << SDL_GetError() << "\n";
00122             return WAIT_ERROR;
00123     }
00124 }
00125 
00126 bool condition::notify_one()
00127 {
00128     if(SDL_CondSignal(cond_) < 0) {
00129         ERR_G << "SDL_CondSignal: " << SDL_GetError() << "\n";
00130         return false;
00131     }
00132 
00133     return true;
00134 }
00135 
00136 bool condition::notify_all()
00137 {
00138     if(SDL_CondBroadcast(cond_) < 0) {
00139         ERR_G << "SDL_CondBroadcast: " << SDL_GetError() << "\n";
00140         return false;
00141     }
00142     return true;
00143 }
00144 
00145 bool async_operation::notify_finished()
00146 {
00147     finishedVar_ = true;
00148     return finished_.notify_one();
00149 }
00150 active_operation_list async_operation::active_;
00151 
00152 async_operation::RESULT async_operation::execute(async_operation_ptr this_ptr, waiter& wait)
00153 {
00154     //the thread must be created after the lock, and also destroyed after it.
00155     //this is because during the thread's execution, we must always hold the mutex
00156     //unless we are waiting on notification that the thread is finished, or we have
00157     //already received that notification.
00158     //
00159     //we cannot hold the mutex while waiting for the thread to join though, because
00160     //the thread needs access to the mutex before it terminates
00161     {
00162         const lock l(get_mutex());
00163         active_.push_back(this_ptr);
00164         thread_.reset(new thread(run_async_operation,&this_ptr));
00165 
00166         bool completed = false;
00167         while(wait.process() == waiter::WAIT) {
00168             const condition::WAIT_TIMEOUT_RESULT res = finished_.wait_timeout(get_mutex(),20);
00169             if(res == condition::WAIT_OK || finishedVar_) {
00170                 completed = true;
00171                 break;
00172             }
00173 #ifndef __BEOS__
00174             else if(res == condition::WAIT_ERROR) {
00175                 break;
00176             }
00177 #endif
00178         }
00179 
00180         if(!completed) {
00181             aborted_ = true;
00182             return ABORTED;
00183         }
00184     }
00185 
00186     return COMPLETED;
00187 }
00188 
00189 
00190 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:12 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs