Panda3D
|
00001 // Filename: threadPosixImpl.cxx 00002 // Created by: drose (09Feb06) 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 "threadPosixImpl.h" 00016 #include "selectThreadImpl.h" 00017 00018 #ifdef THREAD_POSIX_IMPL 00019 00020 #include "thread.h" 00021 #include "pointerTo.h" 00022 #include "config_pipeline.h" 00023 #include <sched.h> 00024 00025 pthread_key_t ThreadPosixImpl::_pt_ptr_index = 0; 00026 bool ThreadPosixImpl::_got_pt_ptr_index = false; 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: ThreadPosixImpl::Destructor 00030 // Access: Public 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 ThreadPosixImpl:: 00034 ~ThreadPosixImpl() { 00035 if (thread_cat->is_debug()) { 00036 thread_cat.debug() 00037 << "Deleting thread " << _parent_obj->get_name() << "\n"; 00038 } 00039 00040 _mutex.acquire(); 00041 00042 if (!_detached) { 00043 pthread_detach(_thread); 00044 _detached = true; 00045 } 00046 00047 _mutex.release(); 00048 } 00049 00050 //////////////////////////////////////////////////////////////////// 00051 // Function: ThreadPosixImpl::setup_main_thread 00052 // Access: Public 00053 // Description: Called for the main thread only, which has been 00054 // already started, to fill in the values appropriate to 00055 // that thread. 00056 //////////////////////////////////////////////////////////////////// 00057 void ThreadPosixImpl:: 00058 setup_main_thread() { 00059 _status = S_running; 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: ThreadPosixImpl::start 00064 // Access: Public 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 bool ThreadPosixImpl:: 00068 start(ThreadPriority priority, bool joinable) { 00069 _mutex.acquire(); 00070 if (thread_cat->is_debug()) { 00071 thread_cat.debug() << "Starting " << *_parent_obj << "\n"; 00072 } 00073 00074 nassertd(_status == S_new) { 00075 _mutex.release(); 00076 return false; 00077 } 00078 00079 _joinable = joinable; 00080 _status = S_start_called; 00081 _detached = false; 00082 00083 if (!_got_pt_ptr_index) { 00084 init_pt_ptr_index(); 00085 } 00086 00087 pthread_attr_t attr; 00088 pthread_attr_init(&attr); 00089 00090 if (!_joinable) { 00091 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00092 _detached = true; 00093 } 00094 00095 int result = pthread_attr_setstacksize(&attr, thread_stack_size); 00096 if (result != 0) { 00097 thread_cat->warning() 00098 << "Unable to set stack size.\n"; 00099 } 00100 00101 // Ensure the thread has "system" scope, which should ensure it can 00102 // run in parallel with other threads. 00103 result = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 00104 if (result != 0) { 00105 thread_cat->warning() 00106 << "Unable to set system scope.\n"; 00107 } 00108 00109 struct sched_param param; 00110 int current_policy = SCHED_OTHER; 00111 result = pthread_attr_setschedpolicy(&attr, current_policy); 00112 if (result != 0) { 00113 thread_cat->warning() 00114 << "Unable to set scheduling policy.\n"; 00115 00116 } 00117 00118 result = 0; 00119 switch (priority) { 00120 case TP_low: 00121 param.sched_priority = sched_get_priority_min(current_policy); 00122 result = pthread_attr_setschedparam(&attr, ¶m); 00123 break; 00124 00125 case TP_high: 00126 case TP_urgent: 00127 param.sched_priority = sched_get_priority_max(current_policy); 00128 result = pthread_attr_setschedparam(&attr, ¶m); 00129 break; 00130 00131 case TP_normal: 00132 default: 00133 break; 00134 } 00135 00136 if (result != 0) { 00137 thread_cat->warning() 00138 << "Unable to specify thread priority.\n"; 00139 } 00140 00141 // Increment the parent object's reference count first. The thread 00142 // will eventually decrement it when it terminates. 00143 _parent_obj->ref(); 00144 result = pthread_create(&_thread, &attr, &root_func, (void *)this); 00145 00146 pthread_attr_destroy(&attr); 00147 00148 if (result != 0) { 00149 // Oops, we couldn't start the thread. Be sure to decrement the 00150 // reference count we incremented above, and return false to 00151 // indicate failure. 00152 unref_delete(_parent_obj); 00153 _mutex.release(); 00154 return false; 00155 } 00156 00157 // Thread was successfully started. 00158 _mutex.release(); 00159 return true; 00160 } 00161 00162 //////////////////////////////////////////////////////////////////// 00163 // Function: ThreadPosixImpl::join 00164 // Access: Public 00165 // Description: Blocks the calling process until the thread 00166 // terminates. If the thread has already terminated, 00167 // this returns immediately. 00168 //////////////////////////////////////////////////////////////////// 00169 void ThreadPosixImpl:: 00170 join() { 00171 _mutex.acquire(); 00172 if (!_detached) { 00173 _mutex.release(); 00174 void *return_val; 00175 pthread_join(_thread, &return_val); 00176 _detached = true; 00177 return; 00178 } 00179 _mutex.release(); 00180 } 00181 00182 //////////////////////////////////////////////////////////////////// 00183 // Function: ThreadPosixImpl::get_unique_id 00184 // Access: Public 00185 // Description: 00186 //////////////////////////////////////////////////////////////////// 00187 string ThreadPosixImpl:: 00188 get_unique_id() const { 00189 ostringstream strm; 00190 strm << getpid() << "." << _thread; 00191 00192 return strm.str(); 00193 } 00194 00195 //////////////////////////////////////////////////////////////////// 00196 // Function: ThreadPosixImpl::root_func 00197 // Access: Private, Static 00198 // Description: The entry point of each thread. 00199 //////////////////////////////////////////////////////////////////// 00200 void *ThreadPosixImpl:: 00201 root_func(void *data) { 00202 TAU_REGISTER_THREAD(); 00203 { 00204 //TAU_PROFILE("void ThreadPosixImpl::root_func()", " ", TAU_USER); 00205 00206 ThreadPosixImpl *self = (ThreadPosixImpl *)data; 00207 int result = pthread_setspecific(_pt_ptr_index, self->_parent_obj); 00208 nassertr(result == 0, NULL); 00209 00210 { 00211 self->_mutex.acquire(); 00212 nassertd(self->_status == S_start_called) { 00213 self->_mutex.release(); 00214 return NULL; 00215 } 00216 00217 self->_status = S_running; 00218 self->_mutex.release(); 00219 } 00220 00221 self->_parent_obj->thread_main(); 00222 00223 if (thread_cat->is_debug()) { 00224 thread_cat.debug() 00225 << "Terminating thread " << self->_parent_obj->get_name() 00226 << ", count = " << self->_parent_obj->get_ref_count() << "\n"; 00227 } 00228 00229 { 00230 self->_mutex.acquire(); 00231 nassertd(self->_status == S_running) { 00232 self->_mutex.release(); 00233 return NULL; 00234 } 00235 self->_status = S_finished; 00236 self->_mutex.release(); 00237 } 00238 00239 // Now drop the parent object reference that we grabbed in start(). 00240 // This might delete the parent object, and in turn, delete the 00241 // ThreadPosixImpl object. 00242 unref_delete(self->_parent_obj); 00243 } 00244 00245 return NULL; 00246 } 00247 00248 //////////////////////////////////////////////////////////////////// 00249 // Function: ThreadPosixImpl::init_pt_ptr_index 00250 // Access: Private, Static 00251 // Description: Allocate a new index to store the Thread parent 00252 // pointer as a piece of per-thread private data. 00253 //////////////////////////////////////////////////////////////////// 00254 void ThreadPosixImpl:: 00255 init_pt_ptr_index() { 00256 nassertv(!_got_pt_ptr_index); 00257 00258 int result = pthread_key_create(&_pt_ptr_index, NULL); 00259 if (result != 0) { 00260 thread_cat->error() 00261 << "Unable to associate Thread pointers with threads.\n"; 00262 return; 00263 } 00264 00265 _got_pt_ptr_index = true; 00266 00267 // Assume that we must be in the main thread, since this method must 00268 // be called before the first thread is spawned. 00269 Thread *main_thread_obj = Thread::get_main_thread(); 00270 result = pthread_setspecific(_pt_ptr_index, main_thread_obj); 00271 nassertv(result == 0); 00272 } 00273 00274 #endif // THREAD_POSIX_IMPL