/src/unrar/threadmisc.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | static inline bool CriticalSectionCreate(CRITSECT_HANDLE *CritSection) |
2 | 13.0k | { |
3 | | #ifdef _WIN_ALL |
4 | | InitializeCriticalSection(CritSection); |
5 | | return true; |
6 | | #elif defined(_UNIX) |
7 | | return pthread_mutex_init(CritSection,NULL)==0; |
8 | 13.0k | #endif |
9 | 13.0k | } |
10 | | |
11 | | |
12 | | static inline void CriticalSectionDelete(CRITSECT_HANDLE *CritSection) |
13 | 13.0k | { |
14 | | #ifdef _WIN_ALL |
15 | | DeleteCriticalSection(CritSection); |
16 | | #elif defined(_UNIX) |
17 | | pthread_mutex_destroy(CritSection); |
18 | 13.0k | #endif |
19 | 13.0k | } |
20 | | |
21 | | |
22 | | static inline void CriticalSectionStart(CRITSECT_HANDLE *CritSection) |
23 | 841k | { |
24 | | #ifdef _WIN_ALL |
25 | | EnterCriticalSection(CritSection); |
26 | | #elif defined(_UNIX) |
27 | | pthread_mutex_lock(CritSection); |
28 | 841k | #endif |
29 | 841k | } |
30 | | |
31 | | |
32 | | static inline void CriticalSectionEnd(CRITSECT_HANDLE *CritSection) |
33 | 846k | { |
34 | | #ifdef _WIN_ALL |
35 | | LeaveCriticalSection(CritSection); |
36 | | #elif defined(_UNIX) |
37 | | pthread_mutex_unlock(CritSection); |
38 | 846k | #endif |
39 | 846k | } |
40 | | |
41 | | |
42 | | static THREAD_HANDLE ThreadCreate(NATIVE_THREAD_PTR Proc,void *Data) |
43 | 7.74k | { |
44 | 7.74k | #ifdef _UNIX |
45 | | /* |
46 | | pthread_attr_t attr; |
47 | | pthread_attr_init(&attr); |
48 | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); |
49 | | */ |
50 | 7.74k | pthread_t pt; |
51 | 7.74k | int Code=pthread_create(&pt,NULL/*&attr*/,Proc,Data); |
52 | 7.74k | if (Code!=0) |
53 | 0 | { |
54 | 0 | wchar Msg[100]; |
55 | 0 | swprintf(Msg,ASIZE(Msg),L"\npthread_create failed, code %d\n",Code); |
56 | 0 | ErrHandler.GeneralErrMsg(Msg); |
57 | 0 | ErrHandler.SysErrMsg(); |
58 | 0 | ErrHandler.Exit(RARX_FATAL); |
59 | 0 | } |
60 | 7.74k | return pt; |
61 | | #else |
62 | | DWORD ThreadId; |
63 | | HANDLE hThread=CreateThread(NULL,0x10000,Proc,Data,0,&ThreadId); |
64 | | if (hThread==NULL) |
65 | | { |
66 | | ErrHandler.GeneralErrMsg(L"CreateThread failed"); |
67 | | ErrHandler.SysErrMsg(); |
68 | | ErrHandler.Exit(RARX_FATAL); |
69 | | } |
70 | | return hThread; |
71 | | #endif |
72 | 7.74k | } |
73 | | |
74 | | |
75 | | static void ThreadClose(THREAD_HANDLE hThread) |
76 | 7.74k | { |
77 | 7.74k | #ifdef _UNIX |
78 | 7.74k | pthread_join(hThread,NULL); |
79 | | #else |
80 | | CloseHandle(hThread); |
81 | | #endif |
82 | 7.74k | } |
83 | | |
84 | | |
85 | | #ifdef _WIN_ALL |
86 | | static void CWaitForSingleObject(HANDLE hHandle) |
87 | | { |
88 | | DWORD rc=WaitForSingleObject(hHandle,INFINITE); |
89 | | if (rc==WAIT_FAILED) |
90 | | { |
91 | | ErrHandler.GeneralErrMsg(L"\nWaitForMultipleObjects error %d, GetLastError %d",rc,GetLastError()); |
92 | | ErrHandler.Exit(RARX_FATAL); |
93 | | } |
94 | | } |
95 | | #endif |
96 | | |
97 | | |
98 | | #ifdef _UNIX |
99 | | static void cpthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) |
100 | 567k | { |
101 | 567k | int rc=pthread_cond_wait(cond,mutex); |
102 | 567k | if (rc!=0) |
103 | 0 | { |
104 | 0 | ErrHandler.GeneralErrMsg(L"\npthread_cond_wait error %d",rc); |
105 | 0 | ErrHandler.Exit(RARX_FATAL); |
106 | 0 | } |
107 | 567k | } |
108 | | #endif |
109 | | |
110 | | |
111 | | uint GetNumberOfCPU() |
112 | 23.9k | { |
113 | | #ifndef RAR_SMP |
114 | | return 1; |
115 | | #else |
116 | 23.9k | #ifdef _UNIX |
117 | 23.9k | #ifdef _SC_NPROCESSORS_ONLN |
118 | 23.9k | uint Count=(uint)sysconf(_SC_NPROCESSORS_ONLN); |
119 | 23.9k | return Count<1 ? 1:Count; |
120 | | #elif defined(_APPLE) |
121 | | uint Count; |
122 | | size_t Size=sizeof(Count); |
123 | | return sysctlbyname("hw.ncpu",&Count,&Size,NULL,0)==0 ? Count:1; |
124 | | #endif |
125 | | #else // !_UNIX |
126 | | |
127 | | #ifdef WIN32_CPU_GROUPS |
128 | | // https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask |
129 | | // "Starting with Windows 11 and Windows Server 2022, on a system with |
130 | | // more than 64 processors, process and thread affinities span all |
131 | | // processors in the system, across all processor groups, by default." |
132 | | // Supposing there are 80 CPUs in 2 processor groups 40 CPUs each. |
133 | | // Looks like, beginning from Windows 11 an app can use them all by default, |
134 | | // not resorting to processor groups API. But if we use GetProcessAffinityMask |
135 | | // to count CPUs, we would be limited to 40 CPUs only. So we call |
136 | | // GetActiveProcessorCount() if it is available anf if there are multiple |
137 | | // processor groups. For a single group we prefer the affinity aware |
138 | | // GetProcessAffinityMask(). Out thread pool code handles the case |
139 | | // with restricted processor group affinity. So we avoid the complicated |
140 | | // code to calculate all processor groups affinity here, such as using |
141 | | // GetLogicalProcessorInformationEx, and resort to GetActiveProcessorCount(). |
142 | | HMODULE hKernel=GetModuleHandle(L"kernel32.dll"); |
143 | | if (hKernel!=nullptr) |
144 | | { |
145 | | typedef DWORD (WINAPI *GETACTIVEPROCESSORCOUNT)(WORD GroupNumber); |
146 | | GETACTIVEPROCESSORCOUNT pGetActiveProcessorCount=(GETACTIVEPROCESSORCOUNT)GetProcAddress(hKernel,"GetActiveProcessorCount"); |
147 | | typedef WORD (WINAPI *GETACTIVEPROCESSORGROUPCOUNT)(); |
148 | | GETACTIVEPROCESSORGROUPCOUNT pGetActiveProcessorGroupCount=(GETACTIVEPROCESSORGROUPCOUNT)GetProcAddress(hKernel,"GetActiveProcessorGroupCount"); |
149 | | if (pGetActiveProcessorCount!=nullptr && pGetActiveProcessorGroupCount!=nullptr && |
150 | | pGetActiveProcessorGroupCount()>1) |
151 | | { |
152 | | // Once the thread pool called SetThreadGroupAffinity(), |
153 | | // GetProcessAffinityMask() below will return 0. So we shall always |
154 | | // use GetActiveProcessorCount() here if there are multiple processor |
155 | | // groups, which makes SetThreadGroupAffinity() call possible. |
156 | | DWORD Count=pGetActiveProcessorCount(ALL_PROCESSOR_GROUPS); |
157 | | return Count; |
158 | | } |
159 | | } |
160 | | #endif |
161 | | |
162 | | DWORD_PTR ProcessMask; |
163 | | DWORD_PTR SystemMask; |
164 | | |
165 | | if (!GetProcessAffinityMask(GetCurrentProcess(),&ProcessMask,&SystemMask)) |
166 | | return 1; |
167 | | uint Count=0; |
168 | | for (DWORD_PTR Mask=1;Mask!=0;Mask<<=1) |
169 | | if ((ProcessMask & Mask)!=0) |
170 | | Count++; |
171 | | return Count<1 ? 1:Count; |
172 | | #endif |
173 | | |
174 | 23.9k | #endif // RAR_SMP |
175 | 23.9k | } |
176 | | |
177 | | |
178 | | uint GetNumberOfThreads() |
179 | 23.9k | { |
180 | 23.9k | uint NumCPU=GetNumberOfCPU(); |
181 | 23.9k | if (NumCPU<1) |
182 | 0 | return 1; |
183 | 23.9k | if (NumCPU>MaxPoolThreads) |
184 | 0 | return MaxPoolThreads; |
185 | 23.9k | return NumCPU; |
186 | 23.9k | } |
187 | | |
188 | | |
189 | | |