library of assembled shared sources

http://lass.cocamware.com

thread_win32.inl

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
00044 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_IMPL_THREAD_WIN32_INL
00045 
00046 #pragma LASS_NOTE("util::Threading: using win32 implementation")
00047 
00048 #include "../util_common.h"
00049 #include "../thread.h"
00050 #include "../singleton.h"
00051 #include "../environment.h"
00052 #include "../bit_manip.h"
00053 #include "lass_errno.h"
00054 
00055 #define NOMINMAX
00056 #define WIN32_LEAN_AND_MEAN
00057 #include <process.h>
00058 #include <windows.h>
00059 
00060 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00061 #   pragma warning(push)
00062 #   pragma warning(disable: 4239) //  nonstandard extension used : 'argument' : conversion from 'T' to 'T&'
00063 #   pragma warning(disable: 4267) // conversion from 'size_t' to 'unsigned int'
00064 #   pragma warning(disable: 4996) // This function or variable may be unsafe ...
00065 #endif
00066 
00067 namespace lass
00068 {
00069 namespace util
00070 {
00071 namespace impl
00072 {
00073 
00074 const unsigned numberOfProcessors()
00075 {
00076     DWORD_PTR processAffinityMask, systemAffinityMask;
00077     LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
00078 
00079     // we're doing an assumption here ... We think, we hope, that the mask
00080     // is a continuous series of bits starting from the LSB.  We'll test for this
00081     // until we are sure that our assumption is correct. [Bramz]
00082     //
00083     DWORD_PTR test = systemAffinityMask;
00084     while (test)
00085     {
00086         if (!(test & 0x1))
00087         {
00088             LASS_THROW("our assumption is wrong!");
00089         }
00090         test >>= 1;
00091     }
00092 
00093     return util::countBits(systemAffinityMask);
00094 }
00095 
00096 /** @internal
00097  *  @ingroup Threading
00098  */
00099 class MutexInternal: NonCopyable
00100 {
00101 public:
00102     MutexInternal():
00103         lockCount_(0)
00104     {
00105         mutex_ = LASS_ENFORCE_WINAPI(::CreateMutex(NULL, FALSE, NULL));
00106 
00107     }
00108     ~MutexInternal() 
00109     {
00110         LASS_ASSERT(lockCount_ == 0);
00111         const BOOL ret = CloseHandle(mutex_);
00112         LASS_ASSERT(ret != 0);
00113         if (ret == 0)
00114         {
00115             const unsigned lastError = impl::lass_GetLastError();
00116             std::cerr << "[LASS RUN MSG] WARNING:  CloseHandle failed in ~MutexInternal(): ("
00117                 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00118         }
00119     }
00120     void lock()
00121     {
00122         const DWORD ret = WaitForSingleObject(mutex_, INFINITE);
00123         switch ( ret )
00124         {
00125             case WAIT_ABANDONED:
00126                 // if you get here, you have a design flaw.  But we'll try to continue.
00127                 LASS_ASSERT(false);
00128                 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00129                     << "WaitForSingleObject returned with WAIT_ABANDONED. "
00130                     << "Going to take ownership and continue happily." << std::endl;
00131                 break;
00132             case WAIT_OBJECT_0:
00133                 // ok
00134                 break;
00135             case WAIT_FAILED:
00136                 {
00137                     const unsigned lastError = impl::lass_GetLastError();
00138                     LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00139                         << impl::lass_FormatMessage(lastError));
00140                 }
00141             case WAIT_TIMEOUT:
00142             default:
00143                 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00144         }
00145         ++lockCount_;
00146     }
00147     const LockResult tryLock()
00148     {
00149         const DWORD ret = WaitForSingleObject(mutex_, 0);
00150         switch ( ret )
00151         {
00152             case WAIT_ABANDONED:
00153                 // if you get here, you have a design flaw.  But we'll try to continue.
00154                 LASS_ASSERT(false);
00155                 std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00156                     << "WaitForSingleObject returned with WAIT_ABANDONED. "
00157                     << "Going to take ownership and continue happily." << std::endl;
00158                 break;
00159             case WAIT_OBJECT_0:
00160                 // ok
00161                 break;
00162             case WAIT_FAILED:
00163                 {
00164                     const unsigned lastError = impl::lass_GetLastError();
00165                     LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00166                         << impl::lass_FormatMessage(lastError));
00167                 }
00168             case WAIT_TIMEOUT:
00169                 return lockBusy;
00170             default:
00171                 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00172         }
00173         ++lockCount_;
00174         return lockSuccess;
00175     }
00176     void unlock()
00177     {
00178         LASS_ASSERT(lockCount_ > 0);
00179         if (lockCount_ == 0)
00180         {
00181             LASS_THROW("attempting to unlock an unlocked mutex");
00182         }
00183         --lockCount_;
00184         LASS_ENFORCE_WINAPI(ReleaseMutex(mutex_));
00185     }
00186     const unsigned lockCount() const 
00187     {
00188         return lockCount_;
00189     }
00190 private:
00191     HANDLE mutex_;
00192     unsigned lockCount_;
00193 };
00194 
00195 
00196 
00197 /** @internal
00198  *  @ingroup Threading
00199  */
00200 class CriticalSectionInternal: NonCopyable
00201 {
00202 public:
00203     CriticalSectionInternal()
00204     {
00205         InitializeCriticalSection(&criticalSection_);
00206     }
00207     ~CriticalSectionInternal()
00208     {
00209         LASS_ASSERT(criticalSection_.LockCount == -1);
00210         DeleteCriticalSection(&criticalSection_);
00211     }
00212     void lock()
00213     {
00214         EnterCriticalSection(&criticalSection_);
00215     }
00216     const LockResult tryLock()
00217     {
00218         return TryEnterCriticalSection(&criticalSection_) ? lockSuccess : lockBusy;
00219     }
00220     void unlock()
00221     {
00222         LASS_ASSERT(criticalSection_.RecursionCount > 0);
00223         LeaveCriticalSection(&criticalSection_);
00224     }
00225     const unsigned lockCount() const 
00226     { 
00227         return criticalSection_.RecursionCount; 
00228     }   
00229 private:
00230     CRITICAL_SECTION criticalSection_;
00231 };
00232 
00233 
00234 
00235 /** @internal
00236  *  @ingroup Threading
00237  */
00238 class ConditionInternal: NonCopyable
00239 {
00240 public:
00241     ConditionInternal():
00242         threadsWaiting_(0)
00243     {
00244         event_ = LASS_ENFORCE_WINAPI(::CreateEvent(
00245             NULL,   // default secutiry
00246             FALSE,  // not manual reset
00247             FALSE,  // nonsignaled initially
00248             NULL    // nameless event
00249         ));
00250     }
00251     ~ConditionInternal()
00252     {
00253         const BOOL ret = CloseHandle(event_);
00254         LASS_ASSERT(ret != 0);
00255         if (ret == 0)
00256         {
00257             const unsigned lastError = impl::lass_GetLastError();
00258             std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: "
00259                 << " CloseHandle failed in ~MutexInternal(): (" 
00260                 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00261         }
00262     }       
00263     void wait()
00264     {
00265         wait(INFINITE);
00266     }   
00267     const WaitResult wait(unsigned long iMilliSeconds)
00268     {
00269         // as m_nWaiters variable is accessed from multiple waiting threads
00270         // (and possibly from the broadcasting thread), we need to change its
00271         // value atomically
00272         ::InterlockedIncrement(&threadsWaiting_);
00273         // FIXME this should be MsgWaitForMultipleObjects() as we want to keep
00274         //       processing Windows messages while waiting (or don't we?)
00275         const DWORD ret = WaitForSingleObject(event_, iMilliSeconds);
00276         ::InterlockedDecrement(&threadsWaiting_);
00277         
00278         switch ( ret )
00279         {
00280             case WAIT_OBJECT_0:
00281                 return waitSuccess;
00282             case WAIT_TIMEOUT:
00283                 return waitTimeout;
00284             case WAIT_FAILED:
00285                 {
00286                     const unsigned lastError = impl::lass_GetLastError();
00287                     LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00288                         << impl::lass_FormatMessage(lastError));
00289                 }
00290             default:
00291                 LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00292         }
00293     }
00294     void signal()
00295     {
00296         // set the event to signaled: if a thread is already waiting on it, it
00297         // will be woken up, otherwise the event will remain in the signaled
00298         // state until someone waits on it. In any case, the system will return
00299         // it to a non signalled state afterwards. If multiple threads are
00300         // waiting, only one will be woken up.
00301         LASS_ENFORCE_WINAPI(::SetEvent(event_));
00302     }
00303     void broadcast()
00304     {
00305         // we need to save the original value as m_nWaiters is goign to be
00306         // decreased by the signalled thread resulting in the loop being
00307         // executed less times than needed
00308         LONG nWaiters = threadsWaiting_;
00309 
00310         // this works because all these threads are already waiting and so each
00311         // SetEvent() inside Signal() is really a PulseEvent() because the
00312         // event state is immediately returned to non-signaled
00313         for ( LONG n = 0; n < nWaiters; ++n )
00314             signal();
00315     }
00316 private:
00317     HANDLE event_;
00318     LONG threadsWaiting_;
00319 };
00320 
00321 
00322 
00323 /** @internal
00324  *  @ingroup Threading
00325  */
00326 class ThreadLocalStorageInternal: NonCopyable
00327 {
00328 public:
00329     typedef void (*TDestructor)(void*);
00330 
00331     ThreadLocalStorageInternal(void (*destructor)(void*))
00332     {
00333         index_ = TlsAlloc();
00334         if (index_ == TLS_OUT_OF_INDEXES)
00335         {
00336             const unsigned lastError = impl::lass_GetLastError();
00337             LASS_THROW("Failed to allocate thread local storage: TlsAlloc failed: ("
00338                 << lastError << ") " << impl::lass_FormatMessage(lastError));
00339         }
00340         if (TDestructors* destrs = destructors())
00341         {
00342             try
00343             {
00344                 (*destrs)[index_] = destructor;
00345             }
00346             catch (...)
00347             {
00348                 freeSlot(index_);
00349                 throw;
00350             }
00351         }
00352         else
00353         {
00354             freeSlot(index_);
00355             LASS_THROW("Failed to allocate thread local storage: dead destructor singleton");
00356         }
00357     }
00358     ~ThreadLocalStorageInternal()
00359     {
00360         if (TDestructors* destrs = destructors())
00361         {
00362             destrs->erase(index_);
00363         }
00364         freeSlot(index_);
00365     }
00366     void* const get() const
00367     {
00368         void* result = TlsGetValue(index_); // intel700 doesn't like void* const here [Bramz]
00369         if (result == 0)
00370         {
00371             // getting the value must be pretty fast at times, so only do this enforcer if 
00372             // result indicates that something _may_ be wrong [Bramz]
00373             //
00374             return LASS_ENFORCE_WINAPI(result)("Failed to get thread local storage value");
00375         }
00376         return result;
00377     }
00378     void set(void* value)
00379     {
00380         LASS_ENFORCE_WINAPI(TlsSetValue(index_, value))("Failed to set thread local storage value");
00381     }
00382 
00383     /** destruct the local copies of the variables in a thread.
00384      *  to be called at end of thread's life time ...
00385      */
00386     static void destructLocals()
00387     {
00388         if (TDestructors* destrs = destructors())
00389         {
00390             for (TDestructors::iterator i = destrs->begin(); i != destrs->end(); ++i)
00391             {
00392                 DWORD index = i->first;
00393                 TDestructor destructor = i->second;
00394                 if (destructor)
00395                 {
00396                     if (void* p = TlsGetValue(index))
00397                     {
00398                         destructor(p);
00399                         TlsSetValue(index, 0);
00400                     }
00401                 }
00402             }
00403         }
00404     }
00405 
00406 private:
00407 
00408     typedef std::map<DWORD, TDestructor> TDestructors;
00409 
00410     void freeSlot(DWORD index)
00411     {
00412         if (!TlsFree(index))
00413         {
00414             const unsigned lastError = impl::lass_GetLastError();
00415             std::cerr << "[LASS RUN MSG] UNDEFINED BEHAVIOUR WARNING: TlsFree failed: ("
00416                 << lastError << ") " << impl::lass_FormatMessage(lastError) << std::endl;
00417         }
00418     }
00419     
00420     static TDestructors* destructors()
00421     {
00422         return Singleton<TDestructors, destructionPriorityInternalTlsDestructors>::instance();
00423     }
00424     
00425     DWORD index_;
00426 };
00427 
00428 
00429 
00430 /** @internal
00431  *  @ingroup Threading
00432  *  Abuse singleton mechanism to destroy the local thread storage instances of the main thread
00433  *  before the destructor map (which is a singleton as well) goes out of business.  We do that
00434  *  by creating a helper singleton that has higher destruction priority
00435  */
00436 class MainLocalStorageDestroyer: NonCopyable
00437 {
00438 public:
00439     ~MainLocalStorageDestroyer()
00440     {
00441         ThreadLocalStorageInternal::destructLocals();
00442     }
00443 private:
00444     static MainLocalStorageDestroyer* forceIntoExistance;
00445 };
00446 
00447 MainLocalStorageDestroyer* MainLocalStorageDestroyer::forceIntoExistance =
00448     Singleton<MainLocalStorageDestroyer, destructionPriorityInternalTlsLocalsMain>::instance();
00449 
00450 
00451 
00452 /** @internal
00453  *  @ingroup Threading
00454  */
00455 void bindThread(HANDLE thread, unsigned processor)
00456 {
00457     DWORD_PTR affinityMask = 0;
00458     if (processor == Thread::anyProcessor)
00459     {
00460         DWORD_PTR processAffinityMask, systemAffinityMask;
00461         LASS_ENFORCE_WINAPI(GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask));
00462         affinityMask = systemAffinityMask;
00463     }
00464     else
00465     {
00466         if (processor >= util::numberOfProcessors)
00467         {
00468             LASS_THROW("'" << processor << "' is an invalid processor index. "
00469                 << "Valid range is [0, " << util::numberOfProcessors << ").");
00470         }
00471         affinityMask = DWORD_PTR(1) << processor;
00472     }
00473     LASS_ENFORCE_WINAPI(SetThreadAffinityMask(thread, affinityMask))
00474         ("Failed to bind thread to processor ")(processor);
00475 }
00476 
00477 void setThreadName(DWORD threadId, const char* threadName)
00478 {
00479     char buffer[10];
00480     strncpy(buffer, threadName, 10);
00481     buffer[9] = '\0';
00482 
00483     struct THREADNAME_INFO
00484     {
00485         DWORD dwType; // must be 0x1000
00486         LPCSTR szName; // pointer to name (in user addr space)
00487         DWORD dwThreadID; // thread ID (-1=caller thread)
00488         DWORD dwFlags; // reserved for future use, must be zero
00489     };
00490 
00491     THREADNAME_INFO info;
00492     info.dwType = 0x1000;
00493     info.szName = threadName;
00494     info.dwThreadID = threadId;
00495     info.dwFlags = 0;
00496 
00497     __try
00498     {
00499         RaiseException(0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR*)&info);
00500     }
00501     __except(EXCEPTION_CONTINUE_EXECUTION)
00502     {
00503     }
00504 }
00505 
00506 
00507 
00508 #define LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(exception_type)\
00509     catch (const exception_type& error)\
00510     {\
00511         pimpl->error_.reset(new experimental::RemoteExceptionWrapper<exception_type>(error));\
00512     }
00513 
00514 /** @internal
00515  *  @ingroup Threading
00516  */
00517 class ThreadInternal: NonCopyable
00518 {
00519 public:
00520 
00521     ThreadInternal(Thread& iThread, ThreadKind iKind, const char* name):
00522         thread_(iThread),
00523         name_(name),
00524         isJoinable_(iKind == threadJoinable),
00525         isCreated_(false)
00526     {
00527     }
00528     
00529     ~ThreadInternal()
00530     {
00531     }
00532     
00533     /** run thread.
00534         */
00535     void run()
00536     {
00537         if (isCreated_)
00538         {
00539             LASS_THROW("You can run a thread only once");
00540         }
00541         handle_ = (HANDLE) _beginthreadex(NULL, 0, &ThreadInternal::startThread, this, 0, &id_);
00542         if (handle_ == 0)
00543         {
00544             const int errnum = lass_errno();
00545             LASS_THROW("_beginthreadex failed: (" << errnum << ") " << lass_strerror(errnum));
00546         }
00547         if (name_)
00548         {
00549             setThreadName(id_, name_);
00550         }
00551         runCondition_.wait();
00552     }
00553     
00554     void join()
00555     {           
00556         if (!(isJoinable_ && isCreated_))
00557         {
00558             LASS_THROW("Can not wait for uncreated or detached threads");
00559         }
00560         else
00561         {
00562             const DWORD ret = WaitForSingleObject(handle_, INFINITE);
00563             switch ( ret )
00564             {
00565                 case WAIT_OBJECT_0:
00566                     // ok
00567                     break;
00568                 case WAIT_FAILED:
00569                     {
00570                         const unsigned lastError = impl::lass_GetLastError();
00571                         LASS_THROW("WaitForSingleObject failed: (" << lastError << ") "
00572                             << impl::lass_FormatMessage(lastError));
00573                     }
00574                 default:
00575                     LASS_THROW("impossible return value of WaitForSingleObject: " << ret);
00576             }
00577             isJoinable_ = false;
00578             if (error_.get())
00579             {
00580                 error_->throwSelf();
00581             }
00582         }
00583     }
00584 
00585     void bind(unsigned processor)
00586     {
00587         bindThread(handle_, processor);
00588     }
00589     
00590     static void sleep(unsigned long iMilliSeconds)
00591     {
00592         Sleep(iMilliSeconds);
00593     }
00594     
00595     static void yield()
00596     {
00597         Sleep(0);
00598     }
00599 
00600     static void bindCurrent(unsigned processor)
00601     {
00602         bindThread(GetCurrentThread(), processor);
00603     }
00604 
00605     // thread function
00606     static unsigned __stdcall startThread(void* iPimpl)
00607     {
00608         LASS_ASSERT(iPimpl);
00609         ThreadInternal* pimpl = static_cast<ThreadInternal*>(iPimpl);
00610         pimpl->isCreated_ = true;
00611         if (pimpl->isJoinable_)
00612         {
00613             try
00614             {
00615                 pimpl->runCondition_.signal();
00616                 pimpl->thread_.doRun();
00617             }
00618             catch (const experimental::RemoteExceptionBase& error)
00619             {
00620                 pimpl->error_ = error.clone();
00621             }
00622             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::domain_error)
00623             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::invalid_argument)
00624             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::length_error)
00625             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::out_of_range)
00626             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::range_error)
00627             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::overflow_error)
00628             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::underflow_error)
00629             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::runtime_error)
00630             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::logic_error)
00631             LASS_UTIL_THREAD_WIN32_CATCH_AND_WRAP(::std::exception)
00632         }
00633         else
00634         {
00635             pimpl->runCondition_.signal();
00636             pimpl->thread_.doRun();
00637             delete &pimpl->thread_;
00638         }
00639         return 0;
00640     }
00641 
00642     static void onThreadDetach()
00643     {
00644         ThreadLocalStorageInternal::destructLocals();
00645     }
00646 
00647 private:
00648 
00649     Thread& thread_;
00650     HANDLE handle_;  // handle of the thread
00651     std::auto_ptr<experimental::RemoteExceptionBase> error_;
00652     Condition runCondition_;
00653     const char* name_;
00654     unsigned id_;
00655     bool isJoinable_;
00656     bool isCreated_;
00657 };
00658 
00659 
00660 }
00661 }
00662 }
00663 
00664 #if LASS_COMPILER_TYPE == LASS_COMPILER_TYPE_MSVC
00665 #   pragma warning(pop)
00666 #endif
00667 
00668 #ifdef LASS_BUILD_DLL
00669 
00670 #include "../dll/dll_main.h"
00671 
00672 namespace lass
00673 {
00674 namespace util
00675 {
00676 namespace impl
00677 {
00678 
00679 BOOL threadDllMain(HINSTANCE, DWORD dwReason, LPVOID)
00680 {
00681     switch (dwReason)
00682     {
00683     case DLL_PROCESS_DETACH:
00684     case DLL_THREAD_DETACH:
00685         lass::util::impl::ThreadInternal::onThreadDetach();
00686         break;
00687     }
00688     return TRUE;
00689 }
00690 }
00691 }
00692 }
00693 
00694 LASS_EXECUTE_BEFORE_MAIN_EX(
00695     lassUtilImplThreadWin32RegisterDllMain,
00696     ::lass::dll::registerDllMain(::lass::util::impl::threadDllMain);
00697 )
00698 
00699 #else
00700 
00701 namespace
00702 {
00703 
00704 void NTAPI lassOnThreadCallback(PVOID, DWORD dwReason, PVOID)
00705 {
00706     if(dwReason == DLL_THREAD_DETACH)
00707     {
00708         lass::util::impl::ThreadInternal::onThreadDetach();
00709     }
00710 }
00711 
00712 #if _MSC_VER >= 1400 // VC8.0
00713 #   pragma section(".CRT$XLB", read)
00714 #else
00715 #   pragma section(".CRT$XLB", read, write)
00716 #endif
00717 
00718 extern "C" __declspec(allocate(".CRT$XLB")) PIMAGE_TLS_CALLBACK lassThreadCallback = lassOnThreadCallback;
00719 
00720 }
00721 
00722 #ifdef _WIN64
00723 #   pragma comment(linker, "/INCLUDE:_tls_used")
00724 #else
00725 #   pragma comment(linker, "/INCLUDE:__tls_used")
00726 #endif
00727 
00728 #endif
00729 
00730 
00731 
00732 #endif
00733  
00734 // EOF
00735  

Generated on Mon Nov 10 14:21:40 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo