thread.cpp

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

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs