Panda3D
|
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