Panda3D

threadSimpleImpl.cxx

00001 // Filename: threadSimpleImpl.cxx
00002 // Created by:  drose (18Jun07)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "selectThreadImpl.h"
00016 
00017 #ifdef THREAD_SIMPLE_IMPL
00018 
00019 #include "threadSimpleImpl.h"
00020 #include "threadSimpleManager.h"
00021 #include "thread.h"
00022 
00023 ThreadSimpleImpl *volatile ThreadSimpleImpl::_st_this;
00024 
00025 int ThreadSimpleImpl::_next_unique_id = 1;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: ThreadSimpleImpl::Constructor
00029 //       Access: Public
00030 //  Description: 
00031 ////////////////////////////////////////////////////////////////////
00032 ThreadSimpleImpl::
00033 ThreadSimpleImpl(Thread *parent_obj) :
00034   _parent_obj(parent_obj)
00035 {
00036   _unique_id = _next_unique_id;
00037   ++_next_unique_id;
00038 
00039   _status = TS_new;
00040   _joinable = false;
00041   _priority = TP_normal;
00042   _priority_weight = 1.0;
00043   _run_ticks = 0;
00044   _start_time = 0.0;
00045   _stop_time = 0.0;
00046   _wake_time = 0.0;
00047 
00048   _context = alloc_thread_context();
00049   _stack = NULL;
00050   _stack_size = 0;
00051 
00052   // Save this pointer for convenience.
00053   _manager = ThreadSimpleManager::get_global_ptr();
00054 
00055 #ifdef HAVE_POSIX_THREADS
00056   _posix_system_thread_id = (pthread_t)-1;
00057 #endif
00058 #ifdef WIN32
00059   _win32_system_thread_id = 0;
00060 #endif
00061 }
00062 
00063 ////////////////////////////////////////////////////////////////////
00064 //     Function: ThreadSimpleImpl::Destructor
00065 //       Access: Public
00066 //  Description: 
00067 ////////////////////////////////////////////////////////////////////
00068 ThreadSimpleImpl::
00069 ~ThreadSimpleImpl() {
00070   if (thread_cat->is_debug()) {
00071     thread_cat.debug() 
00072       << "Deleting thread " << _parent_obj->get_name() << "\n";
00073   }
00074   nassertv(_status != TS_running);
00075 
00076   free_thread_context(_context);
00077 
00078   if (_stack != (void *)NULL) {
00079     memory_hook->mmap_free(_stack, _stack_size);
00080   }
00081   _manager->remove_thread(this);
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: ThreadSimpleImpl::setup_main_thread
00086 //       Access: Public
00087 //  Description: Called for the main thread only, which has been
00088 //               already started, to fill in the values appropriate to
00089 //               that thread.
00090 ////////////////////////////////////////////////////////////////////
00091 void ThreadSimpleImpl::
00092 setup_main_thread() {
00093   _status = TS_running;
00094   _priority = TP_normal;
00095   _priority_weight = _manager->_simple_thread_normal_weight;
00096 
00097 #ifdef HAVE_POSIX_THREADS
00098   _posix_system_thread_id = pthread_self();
00099 #endif
00100 #ifdef WIN32
00101   _win32_system_thread_id = GetCurrentThreadId();
00102 #endif
00103 
00104   _manager->set_current_thread(this);
00105 }
00106 
00107 ////////////////////////////////////////////////////////////////////
00108 //     Function: ThreadSimpleImpl::start
00109 //       Access: Public
00110 //  Description: 
00111 ////////////////////////////////////////////////////////////////////
00112 bool ThreadSimpleImpl::
00113 start(ThreadPriority priority, bool joinable) {
00114   if (thread_cat->is_debug()) {
00115     thread_cat.debug() << "Starting " << *_parent_obj << "\n";
00116   }
00117 
00118   nassertr(_status == TS_new, false);
00119 
00120   nassertr(_stack == NULL, false);
00121   _stack_size = memory_hook->round_up_to_page_size((size_t)thread_stack_size);
00122   if (needs_stack_prealloc) {
00123     _stack = (unsigned char *)memory_hook->mmap_alloc(_stack_size, true);
00124   }
00125 
00126   _joinable = joinable;
00127   _status = TS_running;
00128   _priority = priority;
00129 
00130   switch (priority) {
00131   case TP_low:
00132     _priority_weight = _manager->_simple_thread_low_weight;
00133     break;
00134     
00135   case TP_normal:
00136     _priority_weight = _manager->_simple_thread_normal_weight;
00137     break;
00138     
00139   case TP_high:
00140     _priority_weight = _manager->_simple_thread_high_weight;
00141     break;
00142 
00143   case TP_urgent:
00144     _priority_weight = _manager->_simple_thread_urgent_weight;
00145     break;
00146   }
00147 
00148   // We'll keep the reference count upped while the thread is running.
00149   // When the thread finishes, we'll drop the reference count.
00150   _parent_obj->ref();
00151 
00152 #ifdef HAVE_PYTHON
00153   // Query the current Python thread state.
00154   _python_state = PyThreadState_Swap(NULL);
00155   PyThreadState_Swap(_python_state);
00156 #endif  // HAVE_PYTHON
00157 
00158   init_thread_context(_context, _stack, _stack_size, st_begin_thread, this);
00159 
00160   _manager->enqueue_ready(this, false);
00161   return true;
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: ThreadSimpleImpl::join
00166 //       Access: Public
00167 //  Description: Blocks the calling process until the thread
00168 //               terminates.  If the thread has already terminated,
00169 //               this returns immediately.
00170 ////////////////////////////////////////////////////////////////////
00171 void ThreadSimpleImpl::
00172 join() {
00173   nassertv(_joinable);
00174   if (_status == TS_running) {
00175     ThreadSimpleImpl *thread = _manager->get_current_thread();
00176     if (thread != this) {
00177       _joining_threads.push_back(thread);
00178       _manager->next_context();
00179     }
00180   }
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: ThreadSimpleImpl::preempt
00185 //       Access: Public
00186 //  Description: 
00187 ////////////////////////////////////////////////////////////////////
00188 void ThreadSimpleImpl::
00189 preempt() {
00190   _manager->preempt(this);
00191 }
00192 
00193 ////////////////////////////////////////////////////////////////////
00194 //     Function: ThreadSimpleImpl::get_unique_id
00195 //       Access: Public
00196 //  Description: 
00197 ////////////////////////////////////////////////////////////////////
00198 string ThreadSimpleImpl::
00199 get_unique_id() const {
00200   ostringstream strm;
00201 #ifdef WIN32
00202   strm << GetCurrentProcessId();
00203 #else
00204   strm << getpid();
00205 #endif
00206   strm << "." << _unique_id;
00207 
00208   return strm.str();
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: ThreadSimpleImpl::prepare_for_exit
00213 //       Access: Public, Static
00214 //  Description: Waits for all threads to terminate.  Normally this is
00215 //               called only from the main thread.
00216 ////////////////////////////////////////////////////////////////////
00217 void ThreadSimpleImpl::
00218 prepare_for_exit() {
00219   ThreadSimpleManager *manager = ThreadSimpleManager::get_global_ptr();
00220   manager->prepare_for_exit();
00221 }
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: ThreadSimpleImpl::sleep_this
00225 //       Access: Public
00226 //  Description: 
00227 ////////////////////////////////////////////////////////////////////
00228 void ThreadSimpleImpl::
00229 sleep_this(double seconds) {
00230   _manager->enqueue_sleep(this, seconds);
00231   _manager->next_context();
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: ThreadSimpleImpl::yield_this
00236 //       Access: Public
00237 //  Description: 
00238 ////////////////////////////////////////////////////////////////////
00239 void ThreadSimpleImpl::
00240 yield_this(bool volunteer) {
00241   if (thread_cat->is_debug() && volunteer) {
00242     thread_cat.debug() 
00243       << "Force-yielding " << _parent_obj->get_name() << "\n";
00244   }
00245   _manager->enqueue_ready(this, true);
00246   _manager->next_context();
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: ThreadSimpleImpl::st_begin_thread
00251 //       Access: Private, Static
00252 //  Description: This method is called as the first introduction to a
00253 //               new thread.
00254 ////////////////////////////////////////////////////////////////////
00255 void ThreadSimpleImpl::
00256 st_begin_thread(void *data) {
00257   ThreadSimpleImpl *self = (ThreadSimpleImpl *)data;
00258   self->begin_thread();
00259 }
00260 
00261 ////////////////////////////////////////////////////////////////////
00262 //     Function: ThreadSimpleImpl::begin_thread
00263 //       Access: Private
00264 //  Description: This method is called as the first introduction to a
00265 //               new thread.
00266 ////////////////////////////////////////////////////////////////////
00267 void ThreadSimpleImpl::
00268 begin_thread() {
00269 #ifdef HAVE_PYTHON
00270   PyThreadState_Swap(_python_state);
00271 #endif  // HAVE_PYTHON
00272 
00273 #ifdef HAVE_POSIX_THREADS
00274   _posix_system_thread_id = pthread_self();
00275 #endif
00276 #ifdef WIN32
00277   _win32_system_thread_id = GetCurrentThreadId();
00278 #endif
00279 
00280   // Here we are executing within the thread.  Run the thread_main
00281   // function defined for this thread.
00282   _parent_obj->thread_main();
00283 
00284   // Now we have completed the thread.
00285   _status = TS_finished;
00286 
00287   // Any threads that were waiting to join with this thread now become ready.
00288   JoiningThreads::iterator jti;
00289   for (jti = _joining_threads.begin(); jti != _joining_threads.end(); ++jti) {
00290     _manager->enqueue_ready(*jti, false);
00291   }
00292   _joining_threads.clear();
00293 
00294   _manager->enqueue_finished(this);
00295   _manager->next_context();
00296   
00297   // Shouldn't get here.
00298   nassertv(false);
00299   abort();
00300 }
00301 
00302 #endif  // THREAD_SIMPLE_IMPL
 All Classes Functions Variables Enumerations