ThreadNSPR.cpp

Go to the documentation of this file.
00001 /****************** <VPR heading BEGIN do not edit this line> *****************
00002  *
00003  * VR Juggler Portable Runtime
00004  *
00005  * Original Authors:
00006  *   Allen Bierbaum, Patrick Hartling, Kevin Meinert, Carolina Cruz-Neira
00007  *
00008  * -----------------------------------------------------------------
00009  * File:          $RCSfile$
00010  * Date modified: $Date: 2006-12-13 12:04:57 -0600 (Wed, 13 Dec 2006) $
00011  * Version:       $Revision: 19655 $
00012  * -----------------------------------------------------------------
00013  *
00014  ****************** <VPR heading END do not edit this line> ******************/
00015 
00016 /*************** <auto-copyright.pl BEGIN do not edit this line> **************
00017  *
00018  * VR Juggler is (C) Copyright 1998-2005 by Iowa State University
00019  *
00020  * Original Authors:
00021  *   Allen Bierbaum, Christopher Just,
00022  *   Patrick Hartling, Kevin Meinert,
00023  *   Carolina Cruz-Neira, Albert Baker
00024  *
00025  * This library is free software; you can redistribute it and/or
00026  * modify it under the terms of the GNU Library General Public
00027  * License as published by the Free Software Foundation; either
00028  * version 2 of the License, or (at your option) any later version.
00029  *
00030  * This library is distributed in the hope that it will be useful,
00031  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00032  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00033  * Library General Public License for more details.
00034  *
00035  * You should have received a copy of the GNU Library General Public
00036  * License along with this library; if not, write to the
00037  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00038  * Boston, MA 02111-1307, USA.
00039  *
00040  *************** <auto-copyright.pl END do not edit this line> ***************/
00041 
00042 #include <vpr/vprConfig.h>
00043 
00044 #include <iomanip>
00045 #include <boost/concept_check.hpp>
00046 
00047 #include <vpr/Util/Assert.h>
00048 //#include <vpr/Thread/Thread.h>
00049 #include <vpr/md/NSPR/NSPRHelpers.h>
00050 #include <vpr/md/NSPR/Thread/ThreadNSPR.h>
00051 
00052 
00053 namespace vpr
00054 {
00055 
00056 ThreadNSPR::staticWrapper ThreadNSPR::statics;    // Initialize the static data
00057 PRUint32 ThreadNSPR::mTicksPerSec = PR_TicksPerSecond();
00058 
00059 // Non-spawning constructor.  This will not start a thread.
00060 ThreadNSPR::ThreadNSPR(VPRThreadPriority priority, VPRThreadScope scope,
00061                        VPRThreadState state, PRUint32 stackSize)
00062    : mThread(NULL)
00063    , mUserThreadFunctor(NULL)
00064    , mDeleteFunctor(false)
00065    , mStartFunctor(NULL)
00066    , mPriority(priority)
00067    , mScope(scope)
00068    , mState(state)
00069    , mStackSize(stackSize)
00070 {
00071 }
00072 
00073 // Spawning constructor with arguments.  This will start a new thread that
00074 // will execute the specified function.
00075 ThreadNSPR::ThreadNSPR(thread_func_t func, void* arg,
00076                        VPRThreadPriority priority, VPRThreadScope scope,
00077                        VPRThreadState state, PRUint32 stackSize)
00078    : mThread(NULL)
00079    , mUserThreadFunctor(NULL)
00080    , mDeleteFunctor(false)
00081    , mStartFunctor(NULL)
00082    , mPriority(priority)
00083    , mScope(scope)
00084    , mState(state)
00085    , mStackSize(stackSize)
00086 {
00087    mDeleteFunctor = true;
00088    setFunctor(new ThreadNonMemberFunctor(func, arg));
00089    start();
00090 }
00091 
00092 // Spawning constructor (functor version).  This will start a new thread that
00093 // will execute the specified function.
00094 ThreadNSPR::ThreadNSPR(BaseThreadFunctor* functorPtr,
00095                        VPRThreadPriority priority, VPRThreadScope scope,
00096                        VPRThreadState state, PRUint32 stackSize)
00097    : mThread(NULL)
00098    , mUserThreadFunctor(NULL)
00099    , mDeleteFunctor(false)
00100    , mStartFunctor(NULL)
00101    , mPriority(priority)
00102    , mScope(scope)
00103    , mState(state)
00104    , mStackSize(stackSize)
00105 {
00106    setFunctor(functorPtr);
00107    start();
00108 }
00109 
00110 // Destructor.
00111 ThreadNSPR::~ThreadNSPR()
00112 {
00113    ThreadManager::instance()->lock();
00114    {
00115       unregisterThread();
00116    }
00117    ThreadManager::instance()->unlock();
00118 
00119    if ( NULL != mStartFunctor )
00120    {
00121       delete mStartFunctor;
00122       mStartFunctor = NULL;
00123    }
00124 
00125    if ( mDeleteFunctor )
00126    {
00127       delete mUserThreadFunctor;
00128       mUserThreadFunctor = NULL;
00129    }
00130 }
00131 
00132 void ThreadNSPR::setFunctor(BaseThreadFunctor* functorPtr)
00133 {
00134    vprASSERT(mThread == NULL && "Thread already running");
00135    vprASSERT(functorPtr->isValid());
00136 
00137    mUserThreadFunctor = functorPtr;
00138 }
00139 
00140 // Creates a new thread that will execute mUserFunctorPtr.
00141 vpr::ReturnStatus ThreadNSPR::start()
00142 {
00143    vpr::ReturnStatus status;
00144 
00145    if ( NULL != mThread )
00146    {
00147       vprASSERT(false && "Thread already running");
00148       status.setCode(vpr::ReturnStatus::Fail);
00149    }
00150    else if ( NULL == mUserThreadFunctor )
00151    {
00152       vprASSERT(false && "No functor set");
00153       status.setCode(vpr::ReturnStatus::Fail);
00154    }
00155    else
00156    {
00157       PRThreadPriority nspr_prio;
00158       PRThreadScope nspr_scope;
00159       PRThreadState nspr_state;
00160 
00161       nspr_prio  = vprThreadPriorityToNSPR(mPriority);
00162       nspr_scope = vprThreadScopeToNSPR(mScope);
00163       nspr_state = vprThreadStateToNSPR(mState);
00164 
00165       vprASSERT(mUserThreadFunctor->isValid());
00166 
00167       // Store the member functor and create the functor for spawning to our
00168       // start routine.
00169       mStartFunctor = 
00170          new ThreadMemberFunctor<ThreadNSPR>(this, &ThreadNSPR::startThread,
00171                                              NULL);
00172 
00173       // Finally create the thread.
00174       // - On success --> The start method registers the actual thread info
00175       mThreadStartCompleted = false;      // Initialize registration flag (uses cond var for this)
00176       PRThread* ret_thread =
00177          PR_CreateThread(PR_USER_THREAD, vprThreadFunctorFunction,
00178                          (void*) mStartFunctor, nspr_prio, nspr_scope,
00179                          nspr_state, (PRUint32) mStackSize);
00180 
00181       // Inform the caller if the thread was not created successfully.
00182       if ( NULL == ret_thread )
00183       {
00184          ThreadManager::instance()->lock();
00185          {
00186             registerThread(false);
00187          }
00188          ThreadManager::instance()->unlock();
00189 
00190          NSPR_PrintError("vpr::ThreadNSPR::spawn() - Cannot create thread");
00191          status.setCode(vpr::ReturnStatus::Fail);
00192       }
00193       else
00194       {
00195          // start thread will register the thread, so let's wait for it
00196          // -- Wait for registration to complete
00197          mThreadStartCondVar.acquire();
00198          {
00199             // While not desired state (ie. register completed)
00200             while ( !mThreadStartCompleted )
00201             {
00202                mThreadStartCondVar.wait();
00203             }
00204          }
00205          mThreadStartCondVar.release();
00206          // ASSERT: Thread has completed registration
00207          vprASSERT(NULL != mThread && "Thread registration failed");
00208          vprASSERT(-1 != getTID() && "Thread id is invalid for successful thread");
00209 
00210          // Set the return code to success
00211          status.setCode(vpr::ReturnStatus::Succeed);
00212       }
00213    }
00214 
00215    return status;
00216 }
00217 
00218 int ThreadNSPR::join(void** status)
00219 {
00220    boost::ignore_unused_variable_warning(status);
00221    return PR_JoinThread(mThread);
00222 }
00223 
00224 Thread* ThreadNSPR::self()
00225 {
00226    vprASSERT((statics.mStaticsInitialized==1221) && "Trying to call vpr::ThreadNSPR::self before statics are initialized. Don't do that");
00227 
00228    Thread* my_thread;
00229    threadIdKey().getspecific((void**)&my_thread);
00230 
00231    return my_thread;
00232 }
00233 
00234 std::ostream& Thread::outStream(std::ostream& out)
00235 {
00236    out.setf(std::ios::right);
00237    out << std::setw(7) << std::setfill('0')
00238 #ifdef VPR_OS_Windows
00239        << _getpid()
00240 #else
00241        << getpid()
00242 #endif
00243        << "/";
00244    out.unsetf(std::ios::right);
00245    BaseThread::outStream(out);
00246    out << std::setfill(' ');
00247    return out;
00248 }
00249 
00259 void ThreadNSPR::startThread(void* nullParam)
00260 {
00261    boost::ignore_unused_variable_warning(nullParam);
00262 
00263    // WE are a new thread... yeah!!!!
00264    // TELL EVERYONE THAT WE LIVE!!!!
00265    mThread = PR_GetCurrentThread();                   // Set the identity of the thread
00266    vprASSERT(NULL != mThread && "Invalid thread");    // We should not be able to have a NULL thread
00267    ThreadManager::instance()->lock();                 // Lock manager
00268    {
00269       threadIdKey().setspecific((void*)this);         // Store self in thread local data
00270       registerThread(true);                           // Finish thread initialization
00271    }
00272    ThreadManager::instance()->unlock();
00273 
00274    // Signal that registration is completed
00275    mThreadStartCondVar.acquire();
00276    {
00277       mThreadStartCompleted = true;
00278       mThreadStartCondVar.signal();
00279    }
00280    mThreadStartCondVar.release();
00281 
00282    // --- CALL USER FUNCTOR --- //
00283    (*mUserThreadFunctor)();
00284 }
00285 
00286 
00287 // Set this thread's priority.
00288 int ThreadNSPR::setPrio(VPRThreadPriority prio)
00289 {
00290    int retval(0);
00291 
00292    if ( prio > 3 )
00293    {
00294       retval = -1;
00295    }
00296    else
00297    {
00298       PR_SetThreadPriority(mThread, vprThreadPriorityToNSPR(prio));
00299    }
00300 
00301    return retval;
00302 }
00303 
00304 // ===========================================================================
00305 // Private methods follow.
00306 // ===========================================================================
00307 
00308 
00309 PRThreadPriority ThreadNSPR::vprThreadPriorityToNSPR(const VPRThreadPriority priority)
00310 {
00311    PRThreadPriority nspr_prio;
00312 
00313    switch ( priority )
00314    {
00315       case VPR_PRIORITY_LOW:
00316          nspr_prio = PR_PRIORITY_LOW;
00317          break;
00318       case VPR_PRIORITY_NORMAL:
00319          nspr_prio = PR_PRIORITY_NORMAL;
00320          break;
00321       case VPR_PRIORITY_HIGH:
00322          nspr_prio = PR_PRIORITY_HIGH;
00323          break;
00324       case VPR_PRIORITY_URGENT:
00325          nspr_prio = PR_PRIORITY_URGENT;
00326          break;
00327    };
00328 
00329    return nspr_prio;
00330 }
00331 
00332 PRThreadScope ThreadNSPR::vprThreadScopeToNSPR(const VPRThreadScope scope)
00333 {
00334    PRThreadScope nspr_scope;
00335 
00336    switch ( scope )
00337    {
00338       case VPR_LOCAL_THREAD:
00339          nspr_scope = PR_LOCAL_THREAD;
00340          break;
00341       case VPR_GLOBAL_THREAD:
00342          nspr_scope = PR_GLOBAL_THREAD;
00343          break;
00344    };
00345 
00346    return nspr_scope;
00347 }
00348 
00349 PRThreadState ThreadNSPR::vprThreadStateToNSPR(const VPRThreadState state)
00350 {
00351    PRThreadState nspr_state;
00352 
00353    switch ( state )
00354    {
00355       case VPR_JOINABLE_THREAD:
00356          nspr_state = PR_JOINABLE_THREAD;
00357          break;
00358       case VPR_UNJOINABLE_THREAD:
00359          nspr_state = PR_UNJOINABLE_THREAD;
00360          break;
00361    };
00362 
00363    return nspr_state;
00364 }
00365 
00366 BaseThread::VPRThreadPriority ThreadNSPR::nsprThreadPriorityToVPR(const PRThreadPriority priority)
00367 {
00368    VPRThreadPriority vpr_prio;
00369 
00370    switch ( priority )
00371    {
00372       case PR_PRIORITY_LOW:
00373          vpr_prio = VPR_PRIORITY_LOW;
00374          break;
00375       case PR_PRIORITY_NORMAL:
00376          vpr_prio = VPR_PRIORITY_NORMAL;
00377          break;
00378       case PR_PRIORITY_HIGH:
00379          vpr_prio = VPR_PRIORITY_HIGH;
00380          break;
00381       case PR_PRIORITY_URGENT:
00382          vpr_prio = VPR_PRIORITY_URGENT;
00383          break;
00384    };
00385 
00386    return vpr_prio;
00387 }
00388 
00389 BaseThread::VPRThreadScope ThreadNSPR::nsprThreadScopeToVPR(const PRThreadScope scope)
00390 {
00391    VPRThreadScope vpr_scope;
00392 
00393    switch ( scope )
00394    {
00395       case PR_LOCAL_THREAD:
00396          vpr_scope = VPR_LOCAL_THREAD;
00397          break;
00398       case PR_GLOBAL_THREAD:
00399       case PR_GLOBAL_BOUND_THREAD:
00400          vpr_scope = VPR_GLOBAL_THREAD;
00401          break;
00402    };
00403 
00404    return vpr_scope;
00405 }
00406 
00407 BaseThread::VPRThreadState ThreadNSPR::nsprThreadStateToVPR(const PRThreadState state)
00408 {
00409    VPRThreadState vpr_state;
00410 
00411    switch ( state )
00412    {
00413       case PR_JOINABLE_THREAD:
00414          vpr_state = VPR_JOINABLE_THREAD;
00415          break;
00416       case PR_UNJOINABLE_THREAD:
00417          vpr_state = VPR_UNJOINABLE_THREAD;
00418          break;
00419    };
00420 
00421    return vpr_state;
00422 }
00423 
00424 } // End of vpr namespace

Generated on Thu Jan 4 10:52:11 2007 for VR Juggler Portable Runtime by  doxygen 1.5.1