Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/express/threadNsprImpl.cxx

Go to the documentation of this file.
00001 // Filename: threadNsprImpl.cxx
00002 // Created by:  drose (08Aug02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "threadNsprImpl.h"
00020 #include "selectThreadImpl.h"
00021 
00022 #ifdef THREAD_NSPR_IMPL
00023 
00024 #include "pointerTo.h"
00025 #include "config_express.h"
00026 #include "mutexHolder.h"
00027 
00028 PRUintn ThreadNsprImpl::_pt_ptr_index = 0;
00029 bool ThreadNsprImpl::_got_pt_ptr_index = false;
00030 
00031 ////////////////////////////////////////////////////////////////////
00032 //     Function: ThreadNsprImpl::Destructor
00033 //       Access: Public
00034 //  Description: 
00035 ////////////////////////////////////////////////////////////////////
00036 ThreadNsprImpl::
00037 ~ThreadNsprImpl() {
00038   if (thread_cat.is_debug()) {
00039     thread_cat.debug() << "Deleting thread " << _parent_obj->get_name() << "\n";
00040   }
00041 
00042   // If the thread object is destructing, it means the last pointer
00043   // has gone away.  This can happen in one of three cases:
00044 
00045   // (1) start() was never called, and the last user reference has
00046   // gone away.  In this case, we should do nothing.
00047 
00048   // (2) There are no more user references, and the thread is still
00049   // running but is about to exit root_func().  In this case, no one
00050   // will ever call join().
00051 
00052   // (3) The thread terminated a while ago, and the last user
00053   // reference has just gone away.  In this case, we should call
00054   // join() if no one else has, to clean up whatever internal
00055   // structures NSPR might keep around for a non-detached thread.
00056 
00057 
00058   if (_thread == (PRThread *)NULL) {
00059     // Since the _thread pointer is still NULL, we must either be in
00060     // case (1), or case (3) but someone else has already called
00061     // join().  Do nothing.
00062     return;
00063   }
00064 
00065   PRThread *current_thread = PR_GetCurrentThread();
00066   if (current_thread == _thread) {
00067     // Since we are currently executing *this* thread, we must be in
00068     // case (2).  Unfortunately, we cannot now indicate we need to
00069     // clean up the thread, since NSPR doesn't have an interface to
00070     // make a thread unjoinable after it has been created, and a
00071     // thread can't join itself (can it?).
00072     if (_joinable) {
00073       thread_cat.warning()
00074         << "thread " << _parent_obj->get_name() << " was never joined.\n";
00075     }
00076     return;
00077   }
00078 
00079   // This is case (3).  The pointer went away and the thread has
00080   // already terminated; furthermore, no one has called join() yet.
00081   // We should do it.
00082   join();
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: ThreadNsprImpl::start
00087 //       Access: Public
00088 //  Description: 
00089 ////////////////////////////////////////////////////////////////////
00090 bool ThreadNsprImpl::
00091 start(ThreadPriority priority, bool global, bool joinable) {
00092   MutexHolder holder(_mutex);
00093   if (thread_cat.is_debug()) {
00094     thread_cat.debug() << "Starting thread " << _parent_obj->get_name() << "\n";
00095   }
00096   nassertr(_thread == (PRThread *)NULL, false);
00097   _joinable = joinable;
00098 
00099   if (!_got_pt_ptr_index) {
00100     // Allocate a new index to store the Thread parent pointer as a
00101     // piece of per-thread private data.
00102     PRStatus result = PR_NewThreadPrivateIndex(&_pt_ptr_index, NULL);
00103     if (result == PR_SUCCESS) {
00104       _got_pt_ptr_index = true;
00105     } else {
00106       thread_cat.error()
00107         << "Unable to associate Thread pointers with threads.\n";
00108       return false;
00109     }
00110   }
00111 
00112   PRThreadPriority nspr_pri;
00113 
00114   switch (priority) {
00115   case TP_low:
00116     nspr_pri = PR_PRIORITY_LOW;
00117     break;
00118 
00119   case TP_normal:
00120     nspr_pri = PR_PRIORITY_NORMAL;
00121     break;
00122 
00123   case TP_high:
00124     nspr_pri = PR_PRIORITY_HIGH;
00125     break;
00126 
00127   case TP_urgent:
00128     nspr_pri = PR_PRIORITY_URGENT;
00129     break;
00130 
00131   default:
00132     nassertr(false, false);
00133   }
00134 
00135   PRThreadScope nspr_scope = (global) ? PR_GLOBAL_THREAD : PR_LOCAL_THREAD;
00136 
00137   PRThreadState nspr_state = (_joinable) ? PR_JOINABLE_THREAD : PR_UNJOINABLE_THREAD;
00138 
00139   // Increment the parent object's reference count first.  The thread
00140   // will eventually decrement it when it terminates.
00141   _parent_obj->ref();
00142   _thread = 
00143     PR_CreateThread(PR_USER_THREAD, &root_func, (void *)_parent_obj,
00144                     nspr_pri, nspr_scope, nspr_state, 0);
00145 
00146   if (_thread == (PRThread *)NULL) {
00147     // Oops, we couldn't start the thread.  Be sure to decrement the
00148     // reference count we incremented above, and return false to
00149     // indicate failure.
00150     unref_delete(_parent_obj);
00151     return false;
00152   }
00153 
00154   // Thread was successfully started.
00155   return true;
00156 }
00157 
00158 ////////////////////////////////////////////////////////////////////
00159 //     Function: ThreadNsprImpl::join
00160 //       Access: Public
00161 //  Description: 
00162 ////////////////////////////////////////////////////////////////////
00163 void ThreadNsprImpl::
00164 join() {
00165   MutexHolder holder(_mutex);
00166   if (_joinable && _thread != (PRThread *)NULL) {
00167     PR_JoinThread(_thread);
00168     _thread = (PRThread *)NULL;
00169   }
00170 }
00171 
00172 ////////////////////////////////////////////////////////////////////
00173 //     Function: ThreadNsprImpl::root_func
00174 //       Access: Private, Static
00175 //  Description: The entry point of each thread.
00176 ////////////////////////////////////////////////////////////////////
00177 void ThreadNsprImpl::
00178 root_func(void *data) {
00179   Thread *parent_obj = (Thread *)data;
00180   PRStatus result = PR_SetThreadPrivate(_pt_ptr_index, parent_obj);
00181   nassertv(result == PR_SUCCESS);
00182   parent_obj->thread_main();
00183 
00184   if (thread_cat.is_debug()) {
00185     thread_cat.debug()
00186       << "Terminating thread " << parent_obj->get_name() 
00187       << ", count = " << parent_obj->get_ref_count() << "\n";
00188   }
00189 
00190   // Now drop the parent object reference that we grabbed in start().
00191   // This might delete the parent object, and in turn, delete the
00192   // ThreadNsprImpl object.
00193   unref_delete(parent_obj);
00194 }
00195 
00196 #endif  // THREAD_NSPR_IMPL

Generated on Fri May 2 00:38:41 2003 for Panda by doxygen1.3