Panda3D
 All Classes Functions Variables Enumerations
threadPosixImpl.cxx
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, &param);
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, &param);
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
 All Classes Functions Variables Enumerations