|
reSIProcate/rutil
9694
|
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 */
1.7.5.1