Panda3D

threadWin32Impl.cxx

00001 // Filename: threadWin32Impl.cxx
00002 // Created by:  drose (07Feb06)
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 "threadWin32Impl.h"
00016 #include "selectThreadImpl.h"
00017 
00018 #ifdef THREAD_WIN32_IMPL
00019 
00020 #include "thread.h"
00021 #include "pointerTo.h"
00022 #include "config_pipeline.h"
00023 
00024 DWORD ThreadWin32Impl::_pt_ptr_index = 0;
00025 bool ThreadWin32Impl::_got_pt_ptr_index = false;
00026 
00027 ////////////////////////////////////////////////////////////////////
00028 //     Function: ThreadWin32Impl::Destructor
00029 //       Access: Public
00030 //  Description: 
00031 ////////////////////////////////////////////////////////////////////
00032 ThreadWin32Impl::
00033 ~ThreadWin32Impl() {
00034   if (thread_cat->is_debug()) {
00035     thread_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n";
00036   }
00037 
00038   CloseHandle(_thread);
00039 }
00040 
00041 ////////////////////////////////////////////////////////////////////
00042 //     Function: ThreadWin32Impl::setup_main_thread
00043 //       Access: Public
00044 //  Description: Called for the main thread only, which has been
00045 //               already started, to fill in the values appropriate to
00046 //               that thread.
00047 ////////////////////////////////////////////////////////////////////
00048 void ThreadWin32Impl::
00049 setup_main_thread() {
00050   _status = S_running;
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: ThreadWin32Impl::start
00055 //       Access: Public
00056 //  Description: 
00057 ////////////////////////////////////////////////////////////////////
00058 bool ThreadWin32Impl::
00059 start(ThreadPriority priority, bool joinable) {
00060   _mutex.acquire();
00061   if (thread_cat->is_debug()) {
00062     thread_cat.debug() << "Starting " << *_parent_obj << "\n";
00063   }
00064 
00065   nassertd(_status == S_new && _thread == 0) {
00066     _mutex.release();
00067     return false;
00068   }
00069 
00070   _joinable = joinable;
00071   _status = S_start_called;
00072 
00073   if (!_got_pt_ptr_index) {
00074     init_pt_ptr_index();
00075   }
00076 
00077   // Increment the parent object's reference count first.  The thread
00078   // will eventually decrement it when it terminates.
00079   _parent_obj->ref();
00080   _thread = 
00081     CreateThread(NULL, 0, &root_func, (void *)this, 0, &_thread_id);
00082 
00083   if (_thread_id == 0) {
00084     // Oops, we couldn't start the thread.  Be sure to decrement the
00085     // reference count we incremented above, and return false to
00086     // indicate failure.
00087     unref_delete(_parent_obj);
00088     _mutex.release();
00089     return false;
00090   }
00091 
00092   // Thread was successfully started.  Set the priority as specified.
00093   switch (priority) {
00094   case TP_low:
00095     SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL);
00096     break;
00097 
00098   case TP_high:
00099     SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL);
00100     break;
00101 
00102   case TP_urgent:
00103     SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST);
00104     break;
00105 
00106   case TP_normal:
00107   default:
00108     SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL);
00109     break;
00110   }
00111 
00112   _mutex.release();
00113   return true;
00114 }
00115 
00116 ////////////////////////////////////////////////////////////////////
00117 //     Function: ThreadWin32Impl::join
00118 //       Access: Public
00119 //  Description: Blocks the calling process until the thread
00120 //               terminates.  If the thread has already terminated,
00121 //               this returns immediately.
00122 ////////////////////////////////////////////////////////////////////
00123 void ThreadWin32Impl::
00124 join() {
00125   _mutex.acquire();
00126   nassertd(_joinable && _status != S_new) {
00127     _mutex.release();
00128     return;
00129   }
00130 
00131   while (_status != S_finished) {
00132     _cv.wait();
00133   }
00134   _mutex.release();
00135 }
00136 
00137 ////////////////////////////////////////////////////////////////////
00138 //     Function: ThreadWin32Impl::get_unique_id
00139 //       Access: Public
00140 //  Description: 
00141 ////////////////////////////////////////////////////////////////////
00142 string ThreadWin32Impl::
00143 get_unique_id() const {
00144   ostringstream strm;
00145   strm << GetCurrentProcessId() << "." << _thread_id;
00146 
00147   return strm.str();
00148 }
00149 
00150 ////////////////////////////////////////////////////////////////////
00151 //     Function: ThreadWin32Impl::root_func
00152 //       Access: Private, Static
00153 //  Description: The entry point of each thread.
00154 ////////////////////////////////////////////////////////////////////
00155 DWORD ThreadWin32Impl::
00156 root_func(LPVOID data) {
00157   TAU_REGISTER_THREAD();
00158   {
00159     //TAU_PROFILE("void ThreadWin32Impl::root_func()", " ", TAU_USER);
00160 
00161     ThreadWin32Impl *self = (ThreadWin32Impl *)data;
00162     BOOL result = TlsSetValue(_pt_ptr_index, self->_parent_obj);
00163     nassertr(result, 1);
00164     
00165     {
00166       self->_mutex.acquire();
00167       nassertd(self->_status == S_start_called) {
00168         self->_mutex.release();
00169         return 1;
00170       }
00171       self->_status = S_running;
00172       self->_cv.notify();
00173       self->_mutex.release();
00174     }
00175     
00176     self->_parent_obj->thread_main();
00177     
00178     if (thread_cat->is_debug()) {
00179       thread_cat.debug()
00180         << "Terminating thread " << self->_parent_obj->get_name() 
00181         << ", count = " << self->_parent_obj->get_ref_count() << "\n";
00182     }
00183     
00184     {
00185       self->_mutex.acquire();
00186       nassertd(self->_status == S_running) {
00187         self->_mutex.release();
00188         return 1;
00189       }
00190       self->_status = S_finished;
00191       self->_cv.notify();
00192       self->_mutex.release();
00193     }
00194     
00195     // Now drop the parent object reference that we grabbed in start().
00196     // This might delete the parent object, and in turn, delete the
00197     // ThreadWin32Impl object.
00198     unref_delete(self->_parent_obj);
00199   }
00200 
00201   return 0;
00202 }
00203 
00204 ////////////////////////////////////////////////////////////////////
00205 //     Function: ThreadWin32Impl::init_pt_ptr_index
00206 //       Access: Private, Static
00207 //  Description: Allocate a new index to store the Thread parent
00208 //               pointer as a piece of per-thread private data.
00209 ////////////////////////////////////////////////////////////////////
00210 void ThreadWin32Impl::
00211 init_pt_ptr_index() {
00212   nassertv(!_got_pt_ptr_index);
00213 
00214   _pt_ptr_index = TlsAlloc();
00215   if (_pt_ptr_index == TLS_OUT_OF_INDEXES) {
00216     thread_cat->error()
00217       << "Unable to associate Thread pointers with threads.\n";
00218     return;
00219   }
00220 
00221   _got_pt_ptr_index = true;
00222 
00223   // Assume that we must be in the main thread, since this method must
00224   // be called before the first thread is spawned.
00225   Thread *main_thread_obj = Thread::get_main_thread();
00226   BOOL result = TlsSetValue(_pt_ptr_index, main_thread_obj);
00227   nassertv(result);
00228 }
00229 
00230 #endif  // THREAD_WIN32_IMPL
 All Classes Functions Variables Enumerations