Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

phThread.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission : 
00003         Realtime Vision Processing System
00004     
00005     Copyright (C) 2004 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008     
00009     This file is part of Phission.
00010 
00011     Phission is free software; you can redistribute it and/or modify
00012     it under the terms of the GNU Lesser General Public License as published by
00013     the Free Software Foundation; either version 2 of the License, or
00014     (at your option) any later version.
00015 
00016     Phission is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019     GNU Lesser General Public License for more details.
00020 
00021     You should have received a copy of the GNU Lesser General Public License
00022     along with Phission; if not, write to the Free Software
00023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 
00025  ---------------------------------------------------------------------------*/
00026 /* -------------------------------------------------------------------------- *
00027  * phThread.cpp: C++ Wrapper class for threading                              *
00028  * -------------------------------------------------------------------------- */
00029 #ifdef HAVE_CONFIG_H
00030     #include <phissionconfig.h>
00031 #endif
00032 
00033 #if defined(HAVE_UNISTD_H)
00034     #include <unistd.h>
00035 #endif
00036 #if defined(HAVE_ERRNO_H)
00037     #include <errno.h>
00038 #endif
00039 
00040 #include <phStandard.h>
00041 
00042 #include <phObject.h>
00043 #include <phMutex.h>
00044 #include <phCondition.h>
00045 
00046 #include <phThread.h>
00047 
00048 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00049     #include <pthread.h>
00050     typedef pthread_t ph_thread_type;
00051 #endif
00052 #if defined(WIN32)
00053     #include <windows.h>
00054     typedef DWORD ph_thread_type;
00055 #endif
00056 #if defined(__ADSPBLACKFIN__)
00057     /* 
00058      * VDK::Thread
00059      * VDK::ThreadID
00060      * VDK::ThreadCreationBlock
00061      * VDK::CreateThreadEx
00062      * VDK::DestroyThread
00063      */
00064     #include <PhissionVDK.h>
00065     typedef VDK::ThreadID ph_thread_type;
00066 #endif
00067 #include <phError.h>
00068 #include <phMemory.h>
00069 #include <phPrint.h>
00070 
00071 #define USE_SCHEDULING() 0
00072 
00073 /* ---------------------------------------------------------------------------
00074  * Win32: 
00075  *      Stuff to do with threads
00076  *      
00077  * AttachThreadInput     
00078  *      Attaches the input processing mechanism of one thread 
00079  *      to that of another thread.
00080  * GetThreadIOPendingFlag     
00081  *      Determines whether a specified thread has any I/O requests pending.
00082  * GetThreadStartInformation     
00083  *      Retrieves the Win32 initialization information for 
00084  *      the specified thread.
00085  * GetThreadTimes     
00086  *      Retrieves timing information for the specified thread.
00087  * OpenThread     
00088  *      Opens an existing thread object.
00089  * ResumeThread     
00090  *      Decrements a thread's suspend count.
00091  * Sleep     
00092  *      Suspends the execution of the current thread for a specified interval.
00093  * SleepEx     
00094  *      Suspends the current thread until the specified condition is met.
00095  * WaitForInputIdle     
00096  *      Waits until the specified process is waiting for user input 
00097  *      with no input pending, or until the time-out interval has elapsed.
00098  * ------------------------------------------------------------------------ */
00099 
00100 /* ---------------------------------------------------------------------------
00101  * pthreads: other stuff to do with threading...maybe
00102  * ---------------------------------------------------------------------------
00103  * pthread_setspecific [pthread_key_create] - management of thread-specific data
00104  * pthread_getspecific [pthread_key_create] - management of thread-specific data
00105  * ---------------------------------------------------------------------------
00106  * pthread_atfork  - register handlers to be called at fork(2) time
00107  * pthread_sigmask - handling of signals in threads
00108  * ---------------------------------------------------------------------------
00109  * sigwait [pthread_sigmask] - handling of signals in threads
00110  * ------------------------------------------------------------------------ */
00111 
00112 /* -------------------------------------------------------------------------- */
00113 #if defined(WIN32)
00114 struct thread_attr_struct {
00115     SECURITY_ATTRIBUTES secAttr;
00116     DWORD creationFlags;
00117 };
00118 typedef struct thread_attr_struct thread_attr_t;
00119 #endif
00120 
00121 /* -------------------------------------------------------------------------- */
00122 /* Defined the phWrapperThread that we're using to launch threads in the
00123  * VDK. Using threads on the VDK requires the use of a class that inherits
00124  * from the VDK class. It seems a bit convoluted but it's seems to be the 
00125  * only way to hide the OS/VDK from the public interface (i.e. no VDK
00126  * header files in Phission header files */
00127 #if defined(__ADSPBLACKFIN__)
00128 class phWrapperThread : public VDK::Thread 
00129 {
00130 private:
00131     /* Pointer to the phThread being run on the VDK */
00132     phThread *m_thread;
00133     
00134 public:
00135     phWrapperThread(VDK::Thread::ThreadCreationBlock &tcb);
00136     virtual ~phWrapperThread( );
00137     
00138     virtual void            Run( );
00139     virtual int             ErrorHandler( );
00140     static  VDK::Thread    *Create( VDK::Thread::ThreadCreationBlock &tcb );
00141 };
00142  
00143 /* -------------------------------------------------------------------------- */
00144 phWrapperThread::phWrapperThread(VDK::Thread::ThreadCreationBlock &tcb)
00145     : VDK::Thread(tcb)
00146 {
00147     /* This routine does NOT run in new thread's context.  Any non-static thread
00148      *   initialization should be performed at the beginning of "Run()."
00149      */
00150     
00151     this->m_thread = (phThread *)tcb.user_data_ptr;
00152 }
00153 
00154 /* -------------------------------------------------------------------------- */
00155 phWrapperThread::~phWrapperThread()
00156 {
00157     /* This routine does NOT run in the thread's context.  Any VDK API calls
00158      *   should be performed at the end of "Run()."
00159      */
00160 
00161     // TODO - Put code to be executed just before this thread is destroyed HERE
00162 
00163 }
00164 
00165 /* -------------------------------------------------------------------------- */
00166 void phWrapperThread::Run()
00167 {
00168     phThread::entry((void *)this->m_thread);
00169 }
00170  
00171 /* -------------------------------------------------------------------------- */
00172 int phWrapperThread::ErrorHandler()
00173 {
00174     /* TODO - Put this thread's error handling code HERE */
00175 
00176     phError("phWrapperThread::ErrorHandler()");
00177     phPRINT("(%s)\n",this->m_thread->getName());
00178 
00179     switch (VDK::GetLastThreadError())
00180     {
00181         #if 0
00182         case VDK::kSemaphoreCreationFailure:
00183         case VDK::kSemaphoreDestructionFailure:
00184             return 0;
00185         #endif
00186         default:
00187             /* The default ErrorHandler (called below)  raises
00188              * a kernel panic and stops the system */
00189             return (VDK::Thread::ErrorHandler());
00190     }
00191 }
00192 
00193 /* -------------------------------------------------------------------------- */
00194 /* phWrapperThread Externally Accessible, Pre-Constructor Create Function */
00195 VDK::Thread* phWrapperThread::Create( VDK::Thread::ThreadCreationBlock &tcb )
00196 {
00197     /* This routine does NOT run in new thread's context.  Any non-static thread
00198      *   initialization should be performed at the beginning of "Run()."
00199      */
00200     return new phWrapperThread(tcb);
00201 }
00202 
00203 #endif /* if defined(__ADSPBLACKFIN__) */
00204 
00205 /* -------------------------------------------------------------------------- */
00206 struct ph_thread_info_t
00207 {
00208 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00209     /* pthread threading variables */
00210     
00211     /* m_attr: stores the thread attributes to be used when spawning 
00212      *  the thread */
00213     pthread_attr_t  m_attr;
00214     /* m_thread: Stores the thread handle returned by pthread_create */
00215     pthread_t       m_thread;
00216     #if 0
00217     /* m_cond: startup syncronization condition used in 'start' 
00218      * and 'signal_running/error' */
00219     pthread_cond_t  m_cond;
00220     #endif
00221 #endif
00222 #if defined(WIN32)
00223     /* Win32 threading variables */
00224     HANDLE          m_thread;
00225     DWORD           m_thread_id;
00226     thread_attr_t   m_thread_attr;
00227 #endif
00228 #if defined(__ADSPBLACKFIN__)
00229     VDK::ThreadID               m_thread;
00230     VDK::ThreadCreationBlock    m_thread_block;
00231     /* Used to signal when the thread has finished cleanup and is joining */
00232     VDK::SemaphoreID            m_thread_join;
00233     uint32_t                    m_thread_id;
00234 #endif
00235 };
00236 
00237 /* ------------------------------------------------------------------------- *
00238  * phThread:
00239  * ------------------------------------------------------------------------- */
00240 phThread::phThread() : phCondition()
00241 {
00242     phFUNCTION("phThread::phThread")
00243     int prc = 0;
00244     int locked = 0;
00245     
00246     phTHIS_LOOSE_LOCK(locked);
00247 
00248     this->m_info = (struct ph_thread_info_t *)phCalloc(1,
00249                             sizeof(struct ph_thread_info_t));
00250     phPRINT_PTR(this->m_info,"phCalloc","phCalloc failed.");
00251 
00252     /* initialize the member variables */
00253 #if defined(WIN32)
00254     this->m_info->m_thread_id = 0;
00255 #endif
00256 #if defined(__ADSPBLACKFIN__)
00257     this->m_info->m_thread_block.thread_id = (VDK::ThreadID)-1;
00258 #endif
00259     this->m_ready = 0;
00260     this->m_info->m_thread = (ph_thread_type)0x0;
00261     this->m_detached = 0;
00262     this->m_returned = phSUCCESS;
00263     this->m_running = 0;
00264     this->m_joining = 0;
00265     
00266 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00267     /* initialize the pthread attr structure */
00268     prc = pthread_attr_init(&(this->m_info->m_attr));
00269     if (prc != 0) rc = -1; else rc = 0;
00270     phCHECK_RC(rc,"pthread_attr_init","pthread_attr_init failed. This is bad.");
00271 #endif
00272 
00273 #if defined(WIN32)
00274     this->m_info->m_thread_attr.secAttr.nLength             = sizeof(SECURITY_ATTRIBUTES);
00275     this->m_info->m_thread_attr.secAttr.lpSecurityDescriptor= NULL;
00276     this->m_info->m_thread_attr.secAttr.bInheritHandle      = TRUE;
00277 
00278     this->m_info->m_thread_attr.creationFlags               = 0;
00279 #endif
00280 
00281 #if defined(__ADSPBLACKFIN__)
00282     this->m_info->m_thread_join = VDK::CreateSemaphore(0,1,0,0);
00283     if (this->m_info->m_thread_join == UINT_MAX)
00284     {
00285         phPRINT_RC(-1,NULL,"this->m_info->m_thread_join semaphore create failed");
00286     }
00287     /*
00288      * typedef struct VDK::ThreadCreationBlock
00289      * {
00290      *     VDK::ThreadType              template_id;                x
00291      *     VDK::ThreadID                thread_id;                  
00292      *     unsigned int                 thread_stack_size;          x
00293      *     VDK::Priority                thread_priority;            x
00294      *     void                        *user_data_ptr;              x
00295      *     struct VDK::ThreadTemplate  *pTemplate;
00296      *      struct ThreadTemplate
00297      *      {
00298      *          char*                           name;               x
00299      *          HeapID                          stack1Heap;         x
00300      *          HeapID                          threadStructHeap;   x
00301      *          VDK::Priority                   priority;           x
00302      *          unsigned int                    stackSize;          x
00303      *          VDK::Thread::CreateFunctionP    createFunction;     x
00304      *          bool                            messagesAllowed;    x
00305      *      };
00306      * } VDK::ThreadCreationBlock;
00307      */
00308     this->m_info->m_thread_block.template_id = kDynamicThreadType;
00309     
00310     this->m_info->m_thread_block.thread_stack_size  = 1536;
00311     this->m_info->m_thread_block.thread_priority    = VDK::kPriority10;
00312     this->m_info->m_thread_block.user_data_ptr      = (void *)this;
00313     
00314     this->m_info->m_thread_block.pTemplate = (struct VDK::ThreadTemplate *)
00315                             phCalloc(1,sizeof(struct VDK::ThreadTemplate));
00316     phPRINT_NULLPTR(this->m_info->m_thread_block.pTemplate,NULL,"phCalloc");
00317     
00318     this->m_info->m_thread_block.pTemplate->stack1Heap      = ksystem_heap;
00319     this->m_info->m_thread_block.pTemplate->threadStructHeap= ksystem_heap;
00320     this->m_info->m_thread_block.pTemplate->messagesAllowed = true;
00321     this->m_info->m_thread_block.pTemplate->priority        = VDK::kPriority10;
00322     this->m_info->m_thread_block.pTemplate->stackSize       = 1536;
00323     
00324     this->m_info->m_thread_block.pTemplate->createFunction = 
00325                         (VDK::Thread::CreateFunctionP)phWrapperThread::Create;
00326 #endif
00327  
00328     this->setName("phThread");
00329 error:
00330     phTHIS_LOOSE_UNLOCK(locked);
00331 }
00332     
00333 /* ------------------------------------------------------------------------- *
00334  * phThread:
00335  * ------------------------------------------------------------------------- */
00336 phThread::~phThread()
00337 {
00338     phFUNCTION("phThread::~phThread")
00339     int prc = 0;
00340 
00341     /* phTHIS_LOOSE_LOCK(locked); */
00342    
00343     /* rejoin with the thread if we're not the thread represented
00344      * in the object */
00345     rc = this->stop();
00346     phPRINT_RC(rc,NULL,"this->stop()");
00347     
00348 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00349     /* destroy the attr object */
00350     prc = pthread_attr_destroy(&(this->m_info->m_attr));
00351     if (prc != 0) rc = -1; else rc = 0;
00352     phPRINT_RC(rc,"pthread_attr_destroy","pthread_attr_destroy failed. This is bad.");
00353 #endif
00354 #if defined(__ADSPBLACKFIN__)
00355     VDK::DestroySemaphore(this->m_info->m_thread_join);
00356     this->m_info->m_thread_join = (VDK::SemaphoreID)0;
00357 #endif
00358 
00359     phFree(this->m_info);
00360 }
00361 
00362 /* ------------------------------------------------------------------------- *
00363  * entry:
00364  * ------------------------------------------------------------------------- */
00365 void *phThread::entry( void *param )
00366 {
00367     phFUNCTION("phThread::entry")
00368     int locked = 0;
00369     int runrc = 0;
00370 
00371     phThread *thread = (phThread *)param;
00372    
00373     /* Step 2 - spawned thread waits here until Step 1 in 'start' has been
00374      * performed and the lock is free */
00375     /* lock here! This will wait until the spawning thread has
00376      * released the lock in it's pthread_cond_wait call */
00377     rc = thread->lock();
00378     phCHECK_RC(rc,NULL,"thread->lock()");
00379     locked = 1;
00380     
00381     /* does anything need to be done here? */
00382    
00383     /* signal_running or signal_error should releace the mutex.
00384      * If the user doesn't properly implement the run routine,
00385      * then someone might possibly deadlock because this
00386      * method only unlocks if something goes wrong between the lock
00387      * and this call to run.... if anything is ever done 
00388      */
00389     locked = 0;
00390     
00391     rc = thread->setup();
00392     if (rc == phFAIL)
00393     {
00394         int tmp_rc = thread->signal_error();
00395         phPRINT_RC(tmp_rc,NULL,"thread->signal_error()");
00396     
00397     }
00398     phCHECK_RC(rc,NULL,"thread->setup() returned with error. Forced a signal_error.");
00399             
00400     /* hold the return value from run and use it in pthread_exit */
00401     runrc = thread->run();
00402 
00403 error:
00404     if (locked)
00405     {
00406         rc = thread->unlock();
00407         locked = 0;
00408         phPRINT_RC(rc,NULL,"this->unlock()");
00409     }
00410  
00411     thread->exit((uint32_t)runrc);
00412     return (void*)-1;
00413 }
00414 
00415 /* ------------------------------------------------------------------------- *
00416  * start:
00417  * ------------------------------------------------------------------------- */
00418 int phThread::start(int flag)
00419 {
00420     phFUNCTION("phThread::start")
00421     int prc = 0;
00422     int locked = 0;
00423 #if USE_SCHEDULING()
00424     int fifo_max = 0;
00425     int fifo_min = 0;
00426     struct sched_param fifo_param;
00427 #endif
00428 
00429     phTHIS_LOCK(locked);
00430   
00431     /* if the thread exited on it's own, then we should
00432      * rejoin with it; or at least try to */
00433     if ((this->m_info->m_thread != 0x0) && (this->m_running == 0))
00434     {
00435         rc = this->stop();
00436         phPRINT_RC(rc,NULL,"this->stop()");
00437     }
00438     if (this->m_joining)
00439     {
00440         phERR_PRINT("A thread is waiting to join on the thread still\n");
00441     }
00442     /* if the thread wasn't spawned yet */
00443     if (this->m_info->m_thread == (ph_thread_type)0x0)
00444     {
00445 #if USE_SCHEDULING()
00446         /* Set the scheduling to realtime if possible (this is non-fatal 
00447          * if it fails) */
00448         prc = pthread_attr_setschedpolicy(&thrattr, SCHED_FIFO);
00449         if (prc != 0) rc = -1; else rc = 0;
00450         phPRINT_RC(rc,"pthread_attr_setschedpolicy",
00451                  "Failed to set scheduling priority to SCHED_FIFO." 
00452                  " Need superuser permissions.");
00453         
00454 #ifdef _POSIX_PRIORITY_SCHEDULING
00455         fifo_max = sched_get_priority_max(SCHED_FIFO);
00456         fifo_min = sched_get_priority_min(SCHED_FIFO);
00457         fifo_param.sched_priority = fifo_max;
00458         
00459         prc = pthread_attr_setschedparam(&thrattr,&fifo_param);
00460         if (prc != 0) rc = -1; else rc = 0;
00461         phPRINT_RC(rc,"pthread_attr_setschedparam","pthread_attr_setschedparam failed.");
00462 #else
00463         #warning _POSIX_PRIORITY_SCHEDULING not supported
00464 #endif
00465 #endif /* USE_SCHEDULING() */
00466         
00467         /* Reinitialize all the variables, this is done
00468          * in several places, but seeing it here makes me
00469          * feel safe. */
00470         this->m_ready = 0;
00471         this->m_info->m_thread = (ph_thread_type)0x0;
00472 #if defined(WIN32)
00473         this->m_info->m_thread_id = 0;
00474 #endif
00475 #if defined(__ADSPBLACKFIN__)
00476         this->m_info->m_thread_block.thread_id = (VDK::ThreadID)-1;
00477 #endif
00478         this->m_detached = 0;
00479         this->m_returned = phSUCCESS;
00480         this->m_running = 0;
00481         this->m_joining = 0;
00482       
00483         /* if we're planning on detaching already,
00484          * apply the detach state to the attributes */
00485         if (flag & phDETACHED)
00486         {
00487 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00488             rc = pthread_attr_setdetachstate(&this->m_info->m_attr,
00489                     PTHREAD_CREATE_DETACHED);
00490             phPRINT_RC(rc,"pthread_attr_setdetachstate",
00491                     "Setting detached state failed.");
00492 #endif
00493             /* Set the object's detached state too */
00494             this->m_detached = 1;
00495         }
00496         
00497         /* Spawn thread */
00498 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00499         prc = pthread_create(&(this->m_info->m_thread),
00500                              &(this->m_info->m_attr),
00501                              phThread::entry,
00502                              this );
00503         if (prc != 0) rc = -1; else rc = 0;
00504         phCHECK_RC(rc,"pthread_create",
00505                  "pthread_create failed to call entry");
00506 #endif
00507 #if defined(WIN32)
00508         this->m_info->m_thread = CreateThread( &(this->m_info->m_thread_attr.secAttr),
00509                                                0,
00510                                                (LPTHREAD_START_ROUTINE)phThread::entry,
00511                                                this,
00512                                                this->m_info->m_thread_attr.creationFlags,
00513                                                &(this->m_info->m_thread_id) );
00514         phCHECK_NULLPTR(this->m_info->m_thread,
00515             "CreateThread","CreateThread failed to create a thread");
00516 #endif
00517 #if defined(__ADSPBLACKFIN__)
00518         this->m_info->m_thread_block.pTemplate->name = (char *)this->getName();
00519         this->m_info->m_thread = VDK::CreateThreadEx(&(this->m_info->m_thread_block));
00520 #endif
00521         
00522         //phPROGRESS("(this:%p) m_info->m_thread %d\n",this,(int32_t)this->m_info->m_thread);
00523         /* Wait for the thread to be started,
00524             this releases the lock on the object so that
00525             the entry point can get it. Thus, there is no possibility that
00526             the spawned thread will signal before we have a chance to
00527             wait. */
00528         do
00529         {
00530             /* Step 1 - spawner gives up mutex and waits for signal from
00531              * the spawned thread */
00532             locked = 0;
00533             this->signalWait();
00534             locked = 1;
00535         
00536             /* Step 5 - Check the variables to make sure it wasn't a spurious
00537              * signal */
00538         } while ((this->m_running == 0) && (this->m_error == 0));
00539         
00540         /* Step 6 - Check to make sure no error occured */
00541         /* if there is an error code, do something? */
00542         if (this->m_error == 1)
00543         {
00544             /* release signal_error so we can join in stop */
00545             this->m_ready = 1;
00546             
00547             this->signal();
00548 
00549             do
00550             {
00551                 this->signalWait();
00552             } while (this->m_ready != 2);
00553 
00554             /* Rejoin with the thread and reset parameters */
00555             rc = this->stop();
00556             phCHECK_RC(rc,NULL,"this->stop()");
00557 
00558             /* call the error routine of the thread object */
00559             rc = this->error();
00560             phCHECK_RC(rc,NULL,"this->error()");
00561             
00562             goto error;
00563         }
00564    
00565         /* Step 7 - Set the condition variable value */
00566         /* if it wasn't an error, then release 'signal_running' */
00567         this->m_ready = 1;
00568         
00569         /* Step 8 - signal the thread that called 'signal_running' */         
00570         this->signal();
00571     }
00572     
00573     
00574     /* Step 9 - release the lock so the spawned thread can wake up */
00575     phTHIS_UNLOCK(locked);
00576 
00577     return phSUCCESS;
00578 error:
00579     phTHIS_ERROR_UNLOCK(locked);
00580         
00581     return phFAIL;
00582 }
00583    
00584 /* ------------------------------------------------------------------------- *
00585  * stop:
00586  * ------------------------------------------------------------------------- */
00587 int phThread::stop()
00588 {
00589     phFUNCTION("phThread::stop")
00590     int prc = 0;
00591     int same = 0;
00592     int locked = 0;
00593 #if defined(WIN32)
00594     DWORD dwResult = 0;
00595     BOOL bResult;
00596     DWORD return_val = 0;
00597 #endif
00598 
00599     phTHIS_LOCK(locked);
00600 
00601     /* Make sure we don't call stop if we're the thread
00602      * represented in this object */
00603 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00604     same = pthread_equal(this->m_info->m_thread,pthread_self());
00605 #endif
00606 #if defined(WIN32)
00607     if (this->m_info->m_thread_id == GetCurrentThreadId())
00608         same = 1;
00609     else
00610         same = 0;
00611 #endif
00612 #if defined(__ADSPBLACKFIN__)
00613     if (this->m_info->m_thread_block.thread_id == VDK::GetThreadID())
00614         same = 1;
00615     else
00616         same = 0;
00617 #endif
00618     
00619     /* make sure that if we're trying to stop the thread,
00620      * someone else isn't already trying to join */
00621     if (this->m_joining == 1)
00622     {
00623         goto success;
00624     }
00625     /* If the thread was started and this isn't the
00626      * object doesn't contain the calling thread */
00627     if ((this->m_info->m_thread != 0x0) && (!same))
00628     {
00629         /* Set the running parameter to 0 */
00630         this->m_running = 0;        
00631     
00632         /* Try to wakeup the thread */
00633         rc = this->wakeup();
00634         phPRINT_RC(rc,NULL,"this->wakeup()");
00635 
00636         /* If this thread is detached, don't try to join */
00637         if (this->m_detached != 1)
00638         {
00639             this->m_joining = 1;
00640             
00641             phTHIS_UNLOCK(locked);
00642             
00643 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00644             /* Join with the thread */
00645             prc = pthread_join( this->m_info->m_thread, (void **)&this->m_returned );
00646             if (prc != 0)
00647             {
00648                 if (prc == ESRCH)
00649                 {
00650                     phERR_PRINT("pthread_join failed: ESRCH - No thread could be found corresponding to that specified by th.\n");
00651                 }
00652                 else if (prc == EINVAL)
00653                 {
00654                     phERR_PRINT("pthread_join failed: EINVAL - The th thread has been detached OR Another thread is already waiting on termination of th.\n");
00655                 }
00656                 else if (prc == EDEADLK)
00657                 {
00658                     phERR_PRINT("pthread_join failed: EDEADLK - The th argument refers to the calling thread.\n");
00659                 }
00660             }
00661 #endif
00662 #if defined(WIN32)
00663             dwResult      = WaitForSingleObject( this->m_info->m_thread, INFINITE );
00664             if (dwResult != WAIT_OBJECT_0)
00665                 rc = phFAIL;
00666             else
00667                 rc = phSUCCESS;
00668             phPRINT_RC(rc,"WaitForSingleObject","WaitForSingleObject failed.");
00669 
00670             bResult = GetExitCodeThread( this->m_info->m_thread, &return_val );
00671             if (!bResult) 
00672                 rc = phFAIL; 
00673             else 
00674                 rc = phSUCCESS;
00675             phPRINT_RC(rc,"GetExitCodeThread","GetExitCodeThread failed.");
00676 
00677             this->m_returned = (int32_t)return_val;
00678 
00679             CloseHandle(this->m_info->m_thread); 
00680 #endif
00681 #if defined(__ADSPBLACKFIN__)
00682             if (!VDK::PendSemaphore(this->m_info->m_thread_join,0L))
00683             {
00684                 phPRINT_RC(-1,NULL,"VDK::PendSemaphore failed.");
00685             }
00686 #endif
00687             phTHIS_LOCK(locked);
00688 
00689             this->m_joining = 0;
00690         }
00691         /* Reinit the member variables since we've closed */
00692 #if defined(WIN32)
00693         this->m_info->m_thread_id = 0;
00694 #endif
00695 #if defined(__ADSPBLACKFIN__)
00696         this->m_info->m_thread_block.thread_id = (VDK::ThreadID)-1;
00697 #endif
00698         this->m_info->m_thread  = (ph_thread_type)0x0;
00699         this->m_detached        = 0;
00700         this->m_error           = 0;
00701 
00702         /* call the object's cleanup method */
00703         rc = this->cleanup();
00704         phPRINT_RC(rc,NULL,"this->cleanup");
00705     }
00706 
00707 success: 
00708     phTHIS_UNLOCK(locked);
00709     
00710     return phSUCCESS;
00711 error:
00712     phTHIS_ERROR_UNLOCK(locked);
00713     
00714     return phFAIL;
00715 }
00716   
00717 /* ------------------------------------------------------------------------- *
00718  * signal_running:
00719  * ------------------------------------------------------------------------- */
00720 int phThread::signal_running()
00721 {
00722     phFUNCTION("phThread::signal_running")
00723     int locked = 0;
00724 
00725 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00726     if (!pthread_equal(this->m_info->m_thread,pthread_self()))
00727     {
00728         return phFAIL;
00729     }
00730 #endif
00731 #if defined(WIN32)
00732     if (this->m_info->m_thread_id != GetCurrentThreadId())
00733     {
00734         return phFAIL;
00735     }
00736 #endif 
00737 #if defined(__ADSPBLACKFIN__)
00738     if (this->m_info->m_thread_block.thread_id != VDK::GetThreadID())
00739     {
00740         return phFAIL;
00741     }
00742 #endif
00743 
00744     /* We should already have the lock once at this point..  */
00745     if (this->m_ready == 2) return phFAIL;
00746     
00747     this->m_running = 1;
00748     this->m_error = 0;
00749 
00750     /* Step 3 - spawned thread signals spawner thread condition that will
00751      * release it momentarily */
00752     /* Signal the calling thread that it's ok to procede */
00753     this->signal();
00754 
00755     /* Sync with start again */
00756     while (this->m_ready == 0)
00757     {
00758         /* Step 4 - release the spawner thread and wait for the signal */
00759         /* This releases the lock and waits */
00760         this->signalWait();
00761         /* Step 10 - Loop around after we get the signal and lock,
00762          * check the ready value, which should be 1, and then continue */
00763     }
00764 
00765     /* We have the lock here */
00766     locked = 1;
00767  
00768     /* Just for fun */
00769     this->m_ready = 2;
00770     
00771     /* Step 11 - finally release the lock and the running thread will obtain
00772      * exclusive access to resources by obtaining additional locks later */
00773 
00774     /* unlock the lock obtained from "entry" */
00775     phTHIS_UNLOCK(locked);
00776     
00777     return phSUCCESS;
00778 error:
00779 
00780     return phFAIL;
00781 }
00782 
00783 /* ------------------------------------------------------------------------- *
00784  * signal_error:
00785  * ------------------------------------------------------------------------- */
00786 int phThread::signal_error()
00787 {
00788     phFUNCTION("phThread::signal_error")
00789     int locked = 0;
00790     
00791 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00792     if (!pthread_equal(this->m_info->m_thread,pthread_self()))
00793     {
00794         return phFAIL;
00795     }
00796 #endif
00797 #if defined(WIN32)
00798     if (this->m_info->m_thread_id != GetCurrentThreadId())
00799     {
00800         return phFAIL;
00801     }
00802 #endif 
00803 #if defined(__ADSPBLACKFIN__)
00804     if (this->m_info->m_thread_block.thread_id != VDK::GetThreadID())
00805     {
00806         return phFAIL;
00807     }
00808 #endif
00809 
00810 
00811     /* We should already have the lock once at this point..  */
00812     if (this->m_ready == 2) return phFAIL;
00813     
00814     this->m_running = 0;
00815     this->m_error = 1;
00816 
00817     /* Signal the calling thread that it's ok to procede,
00818      * although we've set the error var so it's going to perform cleanup */
00819     this->signal();
00820 
00821     /* Sync with start again */
00822     while (this->m_ready == 0)
00823     {
00824         /* This releases the lock and waits */
00825         this->signalWait();
00826     }
00827     
00828     locked = 1;
00829  
00830     this->m_ready = 2;
00831     
00832     /* unlock the lock obtained from "entry" */
00833     this->signal();
00834 
00835     phTHIS_UNLOCK(locked);
00836     
00837     return phSUCCESS;
00838 error:
00839     return phFAIL;
00840 }
00841 
00842 /* ------------------------------------------------------------------------- *
00843  * isRunning:
00844  * ------------------------------------------------------------------------- */
00845 int phThread::isRunning()
00846 {
00847     /* Make this a cancellation point if pthread_cancel is supported. */
00848 #if 0
00849     if (pthread_equal(this->m_info->m_thread,pthread_self()))
00850     {
00851         pthread_testcancel();
00852     }
00853 #endif
00854     
00855 #if 0
00856     phFUNCTION("phThread::isRunning")
00857     phPROGRESS("this:%p id:%d\n",this,(int32_t)this->m_info->m_thread);
00858 #endif
00859     return this->m_running;
00860 }
00861 
00862 /* ------------------------------------------------------------------------- *
00863  * setRunning:
00864  * ------------------------------------------------------------------------- */
00865 void phThread::setRunning(int running)
00866 {
00867     this->m_running = running;
00868 }
00869 
00870 /* ------------------------------------------------------------------------- *
00871  * id:
00872  * ------------------------------------------------------------------------- */
00873 uint32_t phThread::id() 
00874 { 
00875     return (uint32_t)this->m_info->m_thread; 
00876 };
00877 
00878 /* ------------------------------------------------------------------------- *
00879  * threadStopped:
00880  * ------------------------------------------------------------------------- */
00881 int phThread::threadStopped()
00882 {
00883     return (this->m_info->m_thread != 0x0 ? 0 : 1);
00884 }
00885 
00886 /* ------------------------------------------------------------------------- * 
00887  * getReturnCode:
00888  * ------------------------------------------------------------------------- */
00889 int32_t phThread::getReturnCode()
00890 {
00891     phFUNCTION("phThread::getReturnCode")
00892     int     locked  = 0;
00893     int32_t retrc   = 0;
00894 
00895     phTHIS_LOCK(locked);
00896 
00897     retrc = this->m_returned;
00898     
00899     phTHIS_UNLOCK(locked);
00900     
00901     return retrc;
00902 error:
00903     phTHIS_ERROR_UNLOCK(locked);
00904     return 0;
00905 }
00906         
00907 /* ------------------------------------------------------------------------- *
00908  * detach:
00909  * ------------------------------------------------------------------------- */
00910 int phThread::detach()
00911 {
00912     phFUNCTION("phThread::detach")
00913     int locked = 0;
00914 
00915     phTHIS_LOCK(locked);
00916 
00917     /* make sure we don't try to detach again */
00918     if (this->m_detached != 1)
00919     {
00920         /* Set this object as detached */
00921         this->m_detached = 1;
00922     }
00923     
00924     phTHIS_UNLOCK(locked);
00925     
00926     return phSUCCESS;
00927 error:
00928 
00929     phTHIS_ERROR_UNLOCK(locked);
00930     
00931     return phFAIL;
00932 }
00933     
00934 /* ------------------------------------------------------------------------- * 
00935  * detached:
00936  * ------------------------------------------------------------------------- */
00937 int phThread::detached()
00938 {
00939     phFUNCTION("phThread::detached")
00940     int locked = 0;
00941     int retrc = 0;
00942 
00943     phTHIS_LOCK(locked);
00944 
00945     /* save the value for returning it later on */
00946     retrc = this->m_detached;
00947     
00948     phTHIS_UNLOCK(locked);
00949     
00950     return retrc;
00951 error:
00952     phTHIS_ERROR_UNLOCK(locked);
00953     return 0;
00954 }
00955 
00956 /* ------------------------------------------------------------------------- */
00957 int phThread::setPriority(int priority, int flag)
00958 {
00959     return -1;
00960 }
00961 
00962 /* ------------------------------------------------------------------------- */
00963 int phThread::getPriority()
00964 {
00965     return -1;
00966 }
00967 
00968 /* ------------------------------------------------------------------------- */
00969 /* pthread_getschedparam - control thread scheduling parameters */
00970 int phThread::getPriorityFlag()
00971 {
00972     return 0; 
00973 };
00974     
00975 /* ------------------------------------------------------------------------- *
00976  * exit:
00977  * ------------------------------------------------------------------------- */
00978 void phThread::exit(uint32_t value)
00979 {
00980     phFUNCTION("phThread::exit")
00981     
00982     /* only allow the thread to call this method, return
00983      * if the calling thread isn't the one represented by 
00984      * this method. */
00985 #if defined(HAVE_PTHREAD) && !defined(WIN32)
00986     if (!pthread_equal(this->m_info->m_thread,pthread_self()))
00987     {
00988         return;
00989     }
00990 #endif
00991 #if defined(WIN32)
00992     if (this->m_info->m_thread_id != GetCurrentThreadId())
00993     {
00994         return;
00995     }
00996 #endif 
00997 #if defined(__ADSPBLACKFIN__)
00998     if (this->m_info->m_thread_block.thread_id != VDK::GetThreadID())
00999     {
01000         return;
01001     }
01002 #endif
01003     /* Set the running variable to 0, who knows,
01004      * maybe someone else is listening for it.
01005      * If we've gotten this far, no matter who we are, we should set 
01006      * m_running to 0 so 'isRunning' returns false when the thread has
01007      * exit. */
01008     this->m_running = 0;        
01009        
01010     /* If the thread is detached, then we need to do cleanup */
01011     if (this->m_detached)
01012     {
01013         /* Call the object's wakeup, not sure why since we
01014          * are this thread. But perhaps the wakeup
01015          * call needs to sync with other threads. */
01016         rc = this->wakeup();
01017         phPRINT_RC(rc,NULL,"this->wakeup()");
01018         
01019         /* Call this thread's cleanup method */
01020         rc = this->cleanup();
01021         phPRINT_RC(rc,NULL,"this->cleanup");
01022        
01023         /* Set the values to their defaults, I'm very pedantic */
01024         this->m_info->m_thread = (ph_thread_type)0x0;
01025 #if defined(WIN32)
01026         this->m_info->m_thread_id = 0;
01027 #endif
01028 #if defined(__ADSPBLACKFIN__)
01029         this->m_info->m_thread_block.thread_id = (VDK::ThreadID)-1;
01030 #endif
01031         this->m_detached = 0;
01032         this->m_error = 0;
01033 
01034         /* Delete myself */
01035         delete this;
01036     }
01037 #if defined(__ADSPBLACKFIN__)
01038     else
01039     {
01040         /* Signal the thread waiting for the current one to exit;
01041          * This is functionally equivalent to the pthread_join
01042          * functionality */
01043         VDK::PostSemaphore(this->m_info->m_thread_join);
01044     }
01045 #endif
01046 
01047 /* error: */
01048     /* finally call pthread_exit */
01049 #if defined(HAVE_PTHREAD) && !defined(WIN32)
01050     /* There is a problem when calling this with some of the Redhat WS3
01051      * systems in the lab that cause this to segfault. Removing it
01052      * provides the same stack unwinding and thread ending mechanisms
01053      * but without the segfault. I suspect memory corruption somewhere
01054      * so I need to do more in depth testing before adding this back in */
01055     return;/* pthread_exit((void *)value); */
01056 #endif
01057 #if defined(WIN32)
01058     ExitThread((DWORD)value);
01059 #endif
01060 }
01061     
01062 /* ------------------------------------------------------------------------- *
01063  * equal:
01064  * ------------------------------------------------------------------------- */
01065 int phThread::equal( phThread &thread )
01066 {
01067     phFUNCTION("phThread::equal(t)")
01068     int retrc       = 0;
01069     int t_locked    = 0;
01070     int locked      = 0;
01071 
01072     phTHIS_LOCK(locked);
01073 
01074     rc = thread.lock();
01075     phCHECK_RC(rc,NULL,"thread.lock()");
01076     t_locked = 1;
01077    
01078     /* If the threads have valid values, then compare them...
01079      * otherwise they aren't valid and thus unequal */
01080     if ((this->m_info->m_thread != 0x0) && 
01081         (thread.m_info->m_thread != 0x0))
01082     {
01083 #if defined(HAVE_PTHREAD) && !defined(WIN32)
01084         retrc = pthread_equal(this->m_info->m_thread, thread.m_info->m_thread);
01085         if (retrc != 0) retrc = 1; else retrc = 0;
01086 #endif
01087 #if defined(WIN32)
01088         if (this->m_info->m_thread_id == thread.m_info->m_thread_id)
01089             retrc = 1;
01090         else
01091             retrc = 0;
01092 #endif
01093 #if defined(__ADSPBLACKFIN__)
01094         if (this->m_info->m_thread_block.thread_id == thread.m_info->m_thread_block.thread_id)
01095             retrc = 1;
01096         else
01097             retrc = 0;
01098 #endif
01099     }
01100     
01101     rc = thread.unlock();
01102     t_locked = 0;
01103     phCHECK_RC(rc,NULL,"thread.unlock()");
01104    
01105     phTHIS_UNLOCK(locked);
01106     
01107     return retrc;
01108 error:
01109     if (t_locked)
01110     {
01111         rc = thread.unlock();
01112         t_locked = 0;
01113         phPRINT_RC(rc,NULL,"thread.unlock()");
01114     }
01115 
01116     phTHIS_ERROR_UNLOCK(locked);
01117     
01118     return 0;
01119 }
01120 
01121 /* ------------------------------------------------------------------------- *
01122  * same:
01123  * ------------------------------------------------------------------------- */
01124 int phThread::same( phThread &thread_one, phThread &thread_two )
01125 {
01126     phFUNCTION("phThread::same(t,t)")
01127     int retrc = 0;
01128     int t1_locked = 0;
01129     int t2_locked = 0;
01130 
01131     rc = thread_one.lock();
01132     phCHECK_RC(rc,NULL,"thread_one.lock()");
01133     t1_locked = 1;
01134 
01135     rc = thread_two.lock();
01136     phCHECK_RC(rc,NULL,"thread_two.lock()");
01137     t2_locked = 1;
01138   
01139     /* If the threads have valid values, then compare them...
01140      * otherwise they aren't valid and thus unequal */
01141     if ((thread_one.m_info->m_thread != 0x0) && 
01142         (thread_two.m_info->m_thread != 0x0))
01143     {
01144 #if defined(HAVE_PTHREAD) && !defined(WIN32)
01145         retrc = pthread_equal(thread_one.m_info->m_thread, thread_two.m_info->m_thread);
01146         if (retrc != 0) retrc = 1; else retrc = 0;
01147 #endif
01148 #if defined(WIN32)
01149         if (thread_one.m_info->m_thread_id == thread_two.m_info->m_thread_id)
01150             retrc = 1;
01151         else
01152             retrc = 0;
01153 #endif
01154 #if defined(__ADSPBLACKFIN__)
01155         if (thread_one.m_info->m_thread_block.thread_id == 
01156             thread_two.m_info->m_thread_block.thread_id)
01157             retrc = 1;
01158         else
01159             retrc = 0;
01160 #endif
01161     }
01162 
01163     rc = thread_two.unlock();
01164     t2_locked = 0;
01165     phCHECK_RC(rc,NULL,"thread_two.unlock()");
01166    
01167     rc = thread_one.unlock();
01168     t1_locked = 0;
01169     phCHECK_RC(rc,NULL,"thread_one.unlock()");
01170     
01171     return retrc;
01172 error:
01173     if (t2_locked)
01174     {
01175         rc = thread_two.unlock();
01176         t2_locked = 0;
01177         phPRINT_RC(rc,NULL,"thread_two.unlock()");
01178     }
01179 
01180     if (t1_locked)
01181     {
01182         rc = thread_one.unlock();
01183         t1_locked = 0;
01184         phPRINT_RC(rc,NULL,"thread_one.unlock()");
01185     }
01186     
01187     return 0;
01188 }
01189 
01190 /* ------------------------------------------------------------------------- *
01191  * forcedExit:
01192  *  Force the close of the current thread.
01193  * ------------------------------------------------------------------------- */
01194 void phThread::forcedExit( )
01195 {
01196 #if defined(HAVE_PTHREAD) && !defined(WIN32)
01197     pthread_exit((void *)phFAIL);
01198 #endif
01199 #if defined(WIN32)
01200     ExitThread((DWORD)phFAIL);
01201 #endif
01202 #if defined(__ADSPBLACKFIN__)
01203     VDK::DestroyThread(VDK::GetThreadID(),true);
01204 #endif
01205 }
01206 
01207 
01208 /* ------------------------------------------------------------------------- * 
01209  * run:
01210  * ------------------------------------------------------------------------- *
01211  * IF this method isn't overloaded, it should be!!!!!!
01212  * ------------------------------------------------------------------------- */
01213 int phThread::run()
01214 {
01215     phFUNCTION("phThread::run")
01216 #if 0
01217     /* Do any thread-safe required setup here */
01218    
01219 goto error; /* this is just here to remind you to over load run */
01220     /* run has the lock until here */
01221     rc = this->signal_running();
01222     phCHECK_RC(rc, NULL, "this->signal_running()");
01223 
01224     /* Do any other setup here */
01225     
01226     while (this->isRunning())
01227     {
01228         phThread::yieldThread();
01229     }
01230 
01231     return phSUCCESS;
01232 error:
01233 #endif
01234     rc = this->signal_error();
01235     phPRINT_RC(rc, NULL, "this->signal_error()");
01236    
01237     return phFAIL;
01238 }
01239  
01240 /* ------------------------------------------------------------------------- *
01241  * setup:
01242  * ------------------------------------------------------------------------- */
01243 int phThread::setup()
01244 {
01245     phFUNCTION("phThread::setup")
01246     /* int locked = 0; */
01247 
01248     /* phTHIS_LOCK(locked); */
01249     
01250     /* phTHIS_UNLOCK(locked); */
01251     
01252     return phSUCCESS;
01253 /* error: */
01254     /* phTHIS_ERROR_UNLOCK(locked); */
01255     
01256 /*    return phFAIL;*/
01257 }   
01258 /* ------------------------------------------------------------------------- *
01259  * wakeup: 
01260  * ------------------------------------------------------------------------- */
01261 int phThread::wakeup()
01262 {
01263     phFUNCTION("phThread::wakeup")
01264     /* int locked = 0; */
01265 
01266     /* phTHIS_LOCK(locked); */
01267     
01268     /* phTHIS_UNLOCK(locked); */
01269     
01270     return phSUCCESS;
01271 /* error: */
01272     /* phTHIS_ERROR_UNLOCK(locked); */
01273     
01274 /*    return phFAIL; */
01275 }
01276      
01277 /* ------------------------------------------------------------------------- *
01278  * cleanup:
01279  * ------------------------------------------------------------------------- */
01280 int phThread::cleanup()
01281 {
01282     phFUNCTION("phThread::cleanup")
01283     /* int locked = 0; */
01284 
01285     /* phTHIS_LOCK(locked); */
01286     
01287     /* phTHIS_UNLOCK(locked); */
01288     
01289     return phSUCCESS;
01290 /* error: */
01291     /* phTHIS_ERROR_UNLOCK(locked); */
01292     
01293 /*     return phFAIL; */
01294 }
01295 
01296 /* ------------------------------------------------------------------------- * 
01297  * error:
01298  * ------------------------------------------------------------------------- */
01299 int phThread::error()
01300 {
01301     phFUNCTION("phThread::error")
01302     /* int locked = 0; */
01303 
01304     /* phTHIS_LOCK(locked); */
01305     
01306     /* phTHIS_UNLOCK(locked); */
01307     
01308     return phSUCCESS;
01309 /* error: */
01310     /* phTHIS_ERROR_UNLOCK(locked); */
01311     
01312 /*     return phFAIL; */
01313 }




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:03 2007 for phission by  doxygen 1.4.4