00001 /*************************************************************************** 00002 * * 00003 * (c) Art Tevs, MPI Informatik Saarbruecken * 00004 * mailto: <tevs@mpi-sb.mpg.de> * 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 * * 00011 ***************************************************************************/ 00012 00013 00014 //---------------------------------------------------------------------------------- 00015 // Includes 00016 //---------------------------------------------------------------------------------- 00017 #include "IThread.h" 00018 #include "EventManager.h" 00019 #include "Log.h" 00020 #include <boost/bind.hpp> 00021 00022 namespace nrEngine{ 00023 00024 //-------------------------------------------------------------------- 00025 IThread::IThread()// : EventActor(std::string("Thread_") + boost::lexical_cast<std::string>(id)) 00026 { 00027 //mThread = NULL; 00028 mThreadState = THREAD_STOP; 00029 } 00030 00031 //-------------------------------------------------------------------- 00032 IThread::~IThread() 00033 { 00034 // delete the thread object if it is not empty 00035 //if (mThread) 00036 //{ 00037 // delete mThread; 00038 //} 00039 } 00040 00041 //-------------------------------------------------------------------- 00042 void IThread::threadStart() 00043 { 00044 // Check if we have already a thread created 00045 if (mThread) 00046 { 00047 NR_Log(Log::LOG_KERNEL, Log::LL_WARNING, "IThread: the appropriate thread is already running!"); 00048 return; 00049 } 00050 NR_Log(Log::LOG_KERNEL, "IThread: Create thread and start it"); 00051 00052 mThread.reset(new boost::thread(boost::bind(&IThread::run, this))); 00053 // initialise the attribute 00054 /*pthread_attr_init(&mThreadAttr); 00055 00056 // create the joinable attribute for thsi thread 00057 pthread_attr_setdetachstate(&mThreadAttr, PTHREAD_CREATE_JOINABLE); 00058 00059 // setup thread scheduling attribute 00060 pthread_attr_setschedpolicy(&mThreadAttr, SCHED_RR); 00061 00062 // now create a thread and let it run 00063 int res = pthread_create(&mThread, &mThreadAttr, IThread::run, (void *)this); 00064 if (res){ 00065 NR_Log(Log::LOG_KERNEL, Log::LL_ERROR, "IThread: creation of a thread failed with error code %d", res); 00066 return; 00067 }*/ 00068 mThreadState = THREAD_RUNNING; 00069 00070 mThreadState = THREAD_RUNNING; 00071 mThread.reset(new boost::thread(boost::bind(IThread::run, this))); 00072 00073 } 00074 00075 //-------------------------------------------------------------------- 00076 void IThread::threadStop() 00077 { 00078 // change state 00079 changeState(THREAD_STOP); 00080 00081 // join the thread to the main process 00082 /*pthread_attr_destroy(&mThreadAttr); 00083 int res = pthread_join(mThread, NULL); 00084 if (res){ 00085 NR_Log(Log::LOG_KERNEL, Log::LL_ERROR, "IThread: can not join running thread (error code %d)", res); 00086 return; 00087 }*/ 00088 mThread->join(); 00089 } 00090 00091 //-------------------------------------------------------------------- 00092 void IThread::threadSuspend() 00093 { 00094 changeState(THREAD_NEXT_SUSPEND); 00095 } 00096 00097 //-------------------------------------------------------------------- 00098 void IThread::threadResume() 00099 { 00100 changeState(THREAD_NEXT_RESUME); 00101 } 00102 00103 //-------------------------------------------------------------------- 00104 void IThread::changeState(ThreadState newState) 00105 { 00106 // first lock the mutex and then change the state 00107 /*try{ 00108 boost::mutex::scoped_lock lock(mMutex); 00109 mThreadState = newState; 00110 }catch (boost::lock_error err) {} 00111 */ 00112 00113 // lock the mutex change status and unlock it again 00114 //pthread_mutex_lock(&mMutex); 00115 mThreadState = newState; 00116 //pthread_mutex_unlock(&mMutex); 00117 00118 } 00119 00120 //-------------------------------------------------------------------- 00121 void IThread::yield(IThread* mythread) 00122 { 00123 // use pthread to yield the timeslice 00124 //pthread_yield(); 00125 boost::thread::yield(); 00126 } 00127 00128 //-------------------------------------------------------------------- 00129 void IThread::run(void* _mythread) 00130 { 00131 // try to cast the given parameter to IThread pointer 00132 IThread* mythread = static_cast<IThread*>(_mythread); 00133 if (mythread == NULL) 00134 { 00135 NR_Log(Log::LOG_KERNEL, Log::LL_ERROR, "IThread: not valid parameter was specified for IThread::run(void*) method"); 00136 return; 00137 } 00138 00139 // now loop the thread until some messages occurs 00140 bool run = true; 00141 while (run){ 00142 00143 // kernel requested to suspend the thread 00144 if (mythread->mThreadState == THREAD_NEXT_SUSPEND) 00145 { 00146 // notice about suspending and go into sleep mode 00147 mythread->changeState(THREAD_SLEEPING); 00148 mythread->_noticeSuspend(); 00149 00150 // kernel requested to resume the execution 00151 }else if (mythread->mThreadState == THREAD_NEXT_RESUME) 00152 { 00153 // notice about resuming the work and start it again 00154 mythread->changeState(THREAD_RUNNING); 00155 mythread->_noticeResume(); 00156 00157 // kernel does not requested anything, so run the task 00158 }else if (mythread->mThreadState == THREAD_RUNNING) 00159 { 00160 mythread->_noticeUpdate(); 00161 } 00162 00163 // check for the stop message, then stop the thread 00164 // this is a reading mutex, so do not have to lock it 00165 run = mythread->mThreadState != THREAD_STOP; 00166 00167 // we now yield the used timeslice for another threads 00168 yield(mythread); 00169 } 00170 00171 // notice to stop the underlying task 00172 mythread->_noticeStop(); 00173 00174 // exit the thread 00175 //return NULL; 00176 } 00177 00178 }; // end namespace 00179