reSIProcate/rutil  9694
ThreadIf.cxx
Go to the documentation of this file.
00001 #include "rutil/ThreadIf.hxx"
00002 
00003 #if defined(WIN32)
00004 #include <stdio.h>
00005 #include <tchar.h>
00006 #include <time.h>
00007 #ifdef _WIN32_WCE
00008 typedef LPTHREAD_START_ROUTINE RESIP_THREAD_START_ROUTINE;
00009 #else
00010 #include <process.h> // for _beginthreadex()
00011 typedef unsigned(__stdcall *RESIP_THREAD_START_ROUTINE)(void*);
00012 #endif
00013 
00014 //from Random.cxx
00015 #include "rutil/Socket.hxx"
00016 #endif
00017 
00018 #include <cassert>
00019 #include <iostream>
00020 #include "rutil/ThreadIf.hxx"
00021 #include "rutil/Mutex.hxx"
00022 #include "rutil/Lock.hxx"
00023 #include "rutil/Socket.hxx"
00024 #include "rutil/Logger.hxx"
00025 
00026 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
00027 
00028 using namespace resip;
00029 
00030 #ifdef WIN32
00031 ThreadIf::TlsDestructorMap *ThreadIf::mTlsDestructors;
00032 Mutex *ThreadIf::mTlsDestructorsMutex;
00033 #endif
00034 
00035 extern "C"
00036 {
00037 static void*
00038 #ifdef WIN32
00039 #ifdef _WIN32_WCE
00040 WINAPI
00041 #else
00042 __stdcall
00043 #endif
00044 #endif
00045 threadIfThreadWrapper( void* threadParm )
00046 {
00047    assert( threadParm );
00048    ThreadIf* t = static_cast < ThreadIf* > ( threadParm );
00049 
00050    assert( t );
00051    t->thread();
00052 #ifdef WIN32
00053    // Free data in TLS slots.
00054    ThreadIf::tlsDestroyAll();
00055 #ifdef _WIN32_WCE
00056    ExitThread( 0 );
00057 #else
00058    _endthreadex(0);
00059 #endif
00060 #endif
00061    return 0;
00062 }
00063 }
00064 
00065 #ifdef WIN32
00066 unsigned int TlsDestructorInitializer::mInstanceCounter=0;
00067 TlsDestructorInitializer::TlsDestructorInitializer()
00068 {
00069    if (mInstanceCounter++ == 0)
00070    {
00071       ThreadIf::mTlsDestructorsMutex = new Mutex();
00072       ThreadIf::mTlsDestructors = new ThreadIf::TlsDestructorMap;
00073    }
00074 }
00075 TlsDestructorInitializer::~TlsDestructorInitializer()
00076 {
00077    if (--mInstanceCounter == 0)
00078    {
00079       delete ThreadIf::mTlsDestructorsMutex;
00080       ThreadIf::mTlsDestructors->clear();
00081       delete ThreadIf::mTlsDestructors;
00082    }
00083 }
00084 #endif
00085 
00086 
00087 ThreadIf::ThreadIf() : 
00088 #ifdef WIN32
00089    mThread(0),
00090 #endif
00091    mId(0), mShutdown(false), mShutdownMutex()
00092 {
00093 }
00094 
00095 
00096 ThreadIf::~ThreadIf()
00097 {
00098    shutdown();
00099    join();
00100 }
00101 
00102 void
00103 ThreadIf::run()
00104 {
00105    assert(mId == 0);
00106 
00107 #if defined(WIN32)
00108    // !kh!
00109    // Why _beginthreadex() instead of CreateThread():
00110    //   http://support.microsoft.com/support/kb/articles/Q104/6/41.ASP
00111    // Example of using _beginthreadex() mixed with WaitForSingleObject() and CloseHandle():
00112    //   http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_crt__beginthread.2c_._beginthreadex.asp
00113    
00114    mThread =
00115 #ifdef _WIN32_WCE
00116        // there is no _beginthreadex() for WINCE
00117        CreateThread
00118 #else
00119        (HANDLE)_beginthreadex 
00120 #endif // _WIN32_WCE
00121          (
00122          NULL, // LPSECURITY_ATTRIBUTES lpThreadAttributes,  // pointer to security attributes
00123          0, // DWORD dwStackSize,                         // initial thread stack size
00124          RESIP_THREAD_START_ROUTINE
00125          (threadIfThreadWrapper), // LPTHREAD_START_ROUTINE lpStartAddress,     // pointer to thread function
00126          this, //LPVOID lpParameter,                        // argument for new thread
00127          0, //DWORD dwCreationFlags,                     // creation flags
00128          (unsigned*)&mId// LPDWORD lpThreadId                         // pointer to receive thread ID
00129          );
00130    assert( mThread != 0 );
00131 #else
00132    // spawn the thread
00133    if ( int retval = pthread_create( &mId, 0, threadIfThreadWrapper, this) )
00134    {
00135       std::cerr << "Failed to spawn thread: " << retval << std::endl;
00136       assert(0);
00137       // TODO - ADD LOGING HERE
00138    }
00139 #endif
00140 }
00141 
00142 void
00143 ThreadIf::join()
00144 {
00145    // !kh!
00146    // perhaps assert instead of returning when join()ed already?
00147    // programming error?
00148    //assert(mId == 0);
00149 
00150    if (mId == 0)
00151    {
00152       return;
00153    }
00154 
00155 #if defined(WIN32)
00156    DWORD exitCode;
00157    while (true)
00158    {
00159       if (GetExitCodeThread(mThread,&exitCode) != 0)
00160       {
00161          if (exitCode != STILL_ACTIVE)
00162          {
00163             break;
00164          }
00165          else
00166          {
00167             WaitForSingleObject(mThread,INFINITE);
00168          }
00169       }
00170       else
00171       {
00172          // log something here
00173          break;
00174       }
00175    }
00176 
00177    //  !kh!
00178    CloseHandle(mThread);
00179    mThread=0;
00180 #else
00181    void* stat;
00182    if (mId != pthread_self())
00183    {
00184       int r = pthread_join( mId , &stat );
00185       if ( r != 0 )
00186       {
00187          WarningLog( << "Internal error: pthread_join() returned " << r );
00188          assert(0);
00189          // TODO
00190       }
00191    }
00192    
00193 #endif
00194 
00195    mId = 0;
00196 }
00197 
00198 void
00199 ThreadIf::detach()
00200 {
00201 #if !defined(WIN32)
00202    pthread_detach(mId);
00203 #else
00204    if(mThread)
00205    {
00206       CloseHandle(mThread);
00207       mThread = 0;
00208    }
00209 #endif
00210    mId = 0;
00211 }
00212 
00213 ThreadIf::Id
00214 ThreadIf::selfId()
00215 {
00216 #if defined(WIN32)
00217    return GetCurrentThreadId();
00218 #else
00219    return pthread_self();
00220 #endif
00221 }
00222 
00223 int
00224 ThreadIf::tlsKeyCreate(TlsKey &key, TlsDestructor *destructor)
00225 {
00226 #if defined(WIN32)
00227    key = TlsAlloc();
00228    if (key!=TLS_OUT_OF_INDEXES)
00229    {
00230       Lock lock(*mTlsDestructorsMutex);
00231       (*mTlsDestructors)[key] = destructor;
00232       return 0;
00233    }
00234    else
00235    {
00236       return GetLastError();
00237    }
00238 #else
00239    return pthread_key_create(&key, destructor);
00240 #endif
00241 }
00242 
00243 int
00244 ThreadIf::tlsKeyDelete(TlsKey key)
00245 {
00246 #if defined(WIN32)
00247    if (TlsFree(key)>0)
00248    {
00249       Lock lock(*mTlsDestructorsMutex);
00250       mTlsDestructors->erase(key);
00251       return 0;
00252    }
00253    else
00254    {
00255       return GetLastError();
00256    }
00257 #else
00258    return pthread_key_delete(key);
00259 #endif
00260 }
00261 
00262 int
00263 ThreadIf::tlsSetValue(TlsKey key, const void *val)
00264 {
00265 #if defined(WIN32)
00266    return TlsSetValue(key, (LPVOID)val)>0?0:GetLastError();
00267 #else
00268    return pthread_setspecific(key, val);
00269 #endif
00270 }
00271 
00272 void *
00273 ThreadIf::tlsGetValue(TlsKey key)
00274 {
00275 #if defined(WIN32)
00276    return TlsGetValue(key);
00277 #else
00278    return pthread_getspecific(key);
00279 #endif
00280 }
00281 
00282 
00283 void
00284 ThreadIf::shutdown()
00285 {
00286    Lock lock(mShutdownMutex);
00287    if (!mShutdown)
00288    {
00289       mShutdown = true;
00290       mShutdownCondition.signal();
00291    }
00292 }
00293 
00294 bool
00295 ThreadIf::waitForShutdown(int ms) const
00296 {
00297    Lock lock(mShutdownMutex);
00298    if(!mShutdown)
00299    {
00300       mShutdownCondition.wait(mShutdownMutex, ms);
00301    }
00302    return mShutdown;
00303 }
00304 
00305 bool
00306 ThreadIf::isShutdown() const
00307 {
00308    Lock lock(mShutdownMutex);
00309    (void)lock;
00310    return ( mShutdown );
00311 }
00312 
00313 #ifdef WIN32
00314 void
00315 ThreadIf::tlsDestroyAll()
00316 {
00317    Lock lock(*mTlsDestructorsMutex);
00318    ThreadIf::TlsDestructorMap::const_iterator i = mTlsDestructors->begin();
00319    while(i != mTlsDestructors->end())
00320    {
00321       void *val = TlsGetValue(i->first);
00322       if (val != NULL)
00323       {
00324          (*(i->second))(val);
00325       }
00326       i++;
00327    }
00328 }
00329 #endif
00330 
00331 // End of File
00332 
00333 /* ====================================================================
00334  * The Vovida Software License, Version 1.0
00335  *
00336  * Copyright (c) 2000-2008 Vovida Networks, Inc.  All rights reserved.
00337  *
00338  * Redistribution and use in source and binary forms, with or without
00339  * modification, are permitted provided that the following conditions
00340  * are met:
00341  *
00342  * 1. Redistributions of source code must retain the above copyright
00343  *    notice, this list of conditions and the following disclaimer.
00344  *
00345  * 2. Redistributions in binary form must reproduce the above copyright
00346  *    notice, this list of conditions and the following disclaimer in
00347  *    the documentation and/or other materials provided with the
00348  *    distribution.
00349  *
00350  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00351  *    and "Vovida Open Communication Application Library (VOCAL)" must
00352  *    not be used to endorse or promote products derived from this
00353  *    software without prior written permission. For written
00354  *    permission, please contact vocal@vovida.org.
00355  *
00356  * 4. Products derived from this software may not be called "VOCAL", nor
00357  *    may "VOCAL" appear in their name, without prior written
00358  *    permission of Vovida Networks, Inc.
00359  *
00360  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00361  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00362  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00363  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00364  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00365  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00366  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00367  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00368  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00369  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00370  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00371  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00372  * DAMAGE.
00373  *
00374  * ====================================================================
00375  *
00376  * This software consists of voluntary contributions made by Vovida
00377  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00378  * Inc.  For more information on Vovida Networks, Inc., please see
00379  * <http://www.vovida.org/>.
00380  *
00381  */