libclamunrar/threadmisc.cpp
01eebc13
 // Typically we use the same global thread pool for all RAR modules.
 static ThreadPool *GlobalPool=NULL;
 static uint GlobalPoolUseCount=0;
 
 static inline bool CriticalSectionCreate(CRITSECT_HANDLE *CritSection)
 {
 #ifdef _WIN_ALL
   InitializeCriticalSection(CritSection);
   return true;
 #elif defined(_UNIX)
   return pthread_mutex_init(CritSection,NULL)==0;
 #endif
 }
 
 
 static inline void CriticalSectionDelete(CRITSECT_HANDLE *CritSection)
 {
 #ifdef _WIN_ALL
   DeleteCriticalSection(CritSection);
 #elif defined(_UNIX)
   pthread_mutex_destroy(CritSection);
 #endif
 }
 
 
 static inline void CriticalSectionStart(CRITSECT_HANDLE *CritSection)
 {
 #ifdef _WIN_ALL
   EnterCriticalSection(CritSection);
 #elif defined(_UNIX)
   pthread_mutex_lock(CritSection);
 #endif
 }
 
 
 static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection)
 {
 #ifdef _WIN_ALL
   LeaveCriticalSection(CritSection);
 #elif defined(_UNIX)
   pthread_mutex_unlock(CritSection);
 #endif
 }
 
 
 static struct GlobalPoolCreateSync
 {
   CRITSECT_HANDLE CritSection;
   GlobalPoolCreateSync()  { CriticalSectionCreate(&CritSection); }
   ~GlobalPoolCreateSync() { CriticalSectionDelete(&CritSection); }
 } PoolCreateSync;
 
 
 ThreadPool* CreateThreadPool()
 {
ab504f13
 #ifdef RARDLL
   // We use a simple thread pool, which does not allow to add tasks from
   // different functions and threads in the same time. It is ok for RAR,
   // but UnRAR.dll can be used in multithreaded environment. So we return
   // a new pool for UnRAR.dll every time.
   return new ThreadPool(MaxPoolThreads);
 #else
   // Reuse the existing pool for RAR.
01eebc13
   CriticalSectionStart(&PoolCreateSync.CritSection); 
ab504f13
   
01eebc13
   if (GlobalPoolUseCount++ == 0)
     GlobalPool=new ThreadPool(MaxPoolThreads);
 
   CriticalSectionEnd(&PoolCreateSync.CritSection); 
   return GlobalPool;
ab504f13
 #endif
01eebc13
 }
 
 
 void DestroyThreadPool(ThreadPool *Pool)
 {
   if (Pool!=NULL)
   {
ab504f13
 #ifdef RARDLL
     delete Pool;
 #else
01eebc13
     CriticalSectionStart(&PoolCreateSync.CritSection); 
 
     if (Pool==GlobalPool && GlobalPoolUseCount > 0 && --GlobalPoolUseCount == 0)
       delete GlobalPool;
 
     CriticalSectionEnd(&PoolCreateSync.CritSection); 
ab504f13
 #endif
01eebc13
   }
 }
 
 
 static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data)
 {
 #ifdef _UNIX
 /*
   pthread_attr_t attr;
   pthread_attr_init(&attr);
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 */
   pthread_t pt;
   int Code=pthread_create(&pt,NULL/*&attr*/,Proc,Data);
   if (Code!=0)
   {
     wchar Msg[100];
     swprintf(Msg,ASIZE(Msg),L"\npthread_create failed, code %d\n",Code);
     ErrHandler.GeneralErrMsg(Msg);
     ErrHandler.SysErrMsg();
     ErrHandler.Exit(RARX_FATAL);
   }
   return pt;
 #else
   DWORD ThreadId;
   HANDLE hThread=CreateThread(NULL,0x10000,Proc,Data,0,&ThreadId);
   if (hThread==NULL)
   {
     ErrHandler.GeneralErrMsg(L"CreateThread failed");
     ErrHandler.SysErrMsg();
     ErrHandler.Exit(RARX_FATAL);
   }
   return hThread;
 #endif
 }
 
 
 static void ThreadClose(THREAD_HANDLE hThread)
 {
 #ifdef _UNIX
   pthread_join(hThread,NULL);
 #else
   CloseHandle(hThread);
 #endif
 }
 
 
 #ifdef _WIN_ALL
 static void CWaitForSingleObject(HANDLE hHandle)
 {
   DWORD rc=WaitForSingleObject(hHandle,INFINITE);
   if (rc==WAIT_FAILED)
   {
     ErrHandler.GeneralErrMsg(L"\nWaitForMultipleObjects error %d, GetLastError %d",rc,GetLastError());
     ErrHandler.Exit(RARX_FATAL);
   }
 }
 #endif
 
 
 #ifdef _UNIX
 static void cpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
 {
   int rc=pthread_cond_wait(cond,mutex);
   if (rc!=0)
   {
     ErrHandler.GeneralErrMsg(L"\npthread_cond_wait error %d",rc);
     ErrHandler.Exit(RARX_FATAL);
   }
 }
 #endif
 
 
 uint GetNumberOfCPU()
 {
 #ifndef RAR_SMP
   return 1;
 #else
 #ifdef _UNIX
 #ifdef _SC_NPROCESSORS_ONLN
   uint Count=(uint)sysconf(_SC_NPROCESSORS_ONLN);
   return Count<1 ? 1:Count;
 #elif defined(_APPLE)
   uint Count;
   size_t Size=sizeof(Count);
   return sysctlbyname("hw.ncpu",&Count,&Size,NULL,0)==0 ? Count:1;
 #endif
 #else // !_UNIX
   DWORD_PTR ProcessMask;
   DWORD_PTR SystemMask;
 
   if (!GetProcessAffinityMask(GetCurrentProcess(),&ProcessMask,&SystemMask))
     return 1;
   uint Count=0;
   for (DWORD_PTR Mask=1;Mask!=0;Mask<<=1)
     if ((ProcessMask & Mask)!=0)
       Count++;
   return Count<1 ? 1:Count;
 #endif
 
 #endif // RAR_SMP
 }
 
 
 uint GetNumberOfThreads()
 {
   uint NumCPU=GetNumberOfCPU();
   if (NumCPU<1)
     return 1;
   if (NumCPU>MaxPoolThreads)
     return MaxPoolThreads;
   return NumCPU;
 }