diff options
| author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 00:00:00 +0000 |
|---|---|---|
| committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2025-07-05 19:27:33 +0500 |
| commit | 395149956d696e6e3099d8b76d797437f94a6942 (patch) | |
| tree | 6ed5013a637078ae2dfdc4acf1ad93bf29cea356 /C/Threads.c | |
| parent | e5431fa6f5505e385c6f9367260717e9c47dc2ee (diff) | |
| download | 7zip-25.00.tar.gz 7zip-25.00.tar.bz2 7zip-25.00.zip | |
25.0025.00
Diffstat (limited to 'C/Threads.c')
| -rw-r--r-- | C/Threads.c | 237 |
1 files changed, 234 insertions, 3 deletions
diff --git a/C/Threads.c b/C/Threads.c index 464efec..177d1d9 100644 --- a/C/Threads.c +++ b/C/Threads.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* Threads.c -- multithreading library | 1 | /* Threads.c -- multithreading library |
| 2 | 2024-03-28 : Igor Pavlov : Public domain */ | 2 | : Igor Pavlov : Public domain */ |
| 3 | 3 | ||
| 4 | #include "Precomp.h" | 4 | #include "Precomp.h" |
| 5 | 5 | ||
| @@ -59,6 +59,100 @@ WRes Thread_Wait_Close(CThread *p) | |||
| 59 | return (res != 0 ? res : res2); | 59 | return (res != 0 ? res : res2); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | typedef struct MY_PROCESSOR_NUMBER { | ||
| 63 | WORD Group; | ||
| 64 | BYTE Number; | ||
| 65 | BYTE Reserved; | ||
| 66 | } MY_PROCESSOR_NUMBER, *MY_PPROCESSOR_NUMBER; | ||
| 67 | |||
| 68 | typedef struct MY_GROUP_AFFINITY { | ||
| 69 | #if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION < 100000) | ||
| 70 | // KAFFINITY is not defined in old mingw | ||
| 71 | ULONG_PTR | ||
| 72 | #else | ||
| 73 | KAFFINITY | ||
| 74 | #endif | ||
| 75 | Mask; | ||
| 76 | WORD Group; | ||
| 77 | WORD Reserved[3]; | ||
| 78 | } MY_GROUP_AFFINITY, *MY_PGROUP_AFFINITY; | ||
| 79 | |||
| 80 | typedef BOOL (WINAPI *Func_SetThreadGroupAffinity)( | ||
| 81 | HANDLE hThread, | ||
| 82 | CONST MY_GROUP_AFFINITY *GroupAffinity, | ||
| 83 | MY_PGROUP_AFFINITY PreviousGroupAffinity); | ||
| 84 | |||
| 85 | typedef BOOL (WINAPI *Func_GetThreadGroupAffinity)( | ||
| 86 | HANDLE hThread, | ||
| 87 | MY_PGROUP_AFFINITY GroupAffinity); | ||
| 88 | |||
| 89 | typedef BOOL (WINAPI *Func_GetProcessGroupAffinity)( | ||
| 90 | HANDLE hProcess, | ||
| 91 | PUSHORT GroupCount, | ||
| 92 | PUSHORT GroupArray); | ||
| 93 | |||
| 94 | Z7_DIAGNOSTIC_IGNORE_CAST_FUNCTION | ||
| 95 | |||
| 96 | #if 0 | ||
| 97 | #include <stdio.h> | ||
| 98 | #define PRF(x) x | ||
| 99 | /* | ||
| 100 | -- | ||
| 101 | before call of SetThreadGroupAffinity() | ||
| 102 | GetProcessGroupAffinity return one group. | ||
| 103 | after call of SetThreadGroupAffinity(): | ||
| 104 | GetProcessGroupAffinity return more than group, | ||
| 105 | if SetThreadGroupAffinity() was to another group. | ||
| 106 | -- | ||
| 107 | GetProcessAffinityMask MS DOCs: | ||
| 108 | { | ||
| 109 | If the calling process contains threads in multiple groups, | ||
| 110 | the function returns zero for both affinity masks. | ||
| 111 | } | ||
| 112 | but tests in win10 with 2 groups (less than 64 cores total): | ||
| 113 | GetProcessAffinityMask() still returns non-zero affinity masks | ||
| 114 | even after SetThreadGroupAffinity() calls. | ||
| 115 | */ | ||
| 116 | static void PrintProcess_Info() | ||
| 117 | { | ||
| 118 | { | ||
| 119 | const | ||
| 120 | Func_GetProcessGroupAffinity fn_GetProcessGroupAffinity = | ||
| 121 | (Func_GetProcessGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 122 | "GetProcessGroupAffinity"); | ||
| 123 | if (fn_GetProcessGroupAffinity) | ||
| 124 | { | ||
| 125 | unsigned i; | ||
| 126 | USHORT GroupCounts[64]; | ||
| 127 | USHORT GroupCount = Z7_ARRAY_SIZE(GroupCounts); | ||
| 128 | BOOL boolRes = fn_GetProcessGroupAffinity(GetCurrentProcess(), | ||
| 129 | &GroupCount, GroupCounts); | ||
| 130 | printf("\n====== GetProcessGroupAffinity : " | ||
| 131 | "boolRes=%u GroupCounts = %u :", | ||
| 132 | boolRes, (unsigned)GroupCount); | ||
| 133 | for (i = 0; i < GroupCount; i++) | ||
| 134 | printf(" %u", GroupCounts[i]); | ||
| 135 | printf("\n"); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | { | ||
| 139 | DWORD_PTR processAffinityMask, systemAffinityMask; | ||
| 140 | if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask)) | ||
| 141 | { | ||
| 142 | PRF(printf("\n====== GetProcessAffinityMask : " | ||
| 143 | ": processAffinityMask=%x, systemAffinityMask=%x\n", | ||
| 144 | (UInt32)processAffinityMask, (UInt32)systemAffinityMask);) | ||
| 145 | } | ||
| 146 | else | ||
| 147 | printf("\n==GetProcessAffinityMask FAIL"); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | #else | ||
| 151 | #ifndef USE_THREADS_CreateThread | ||
| 152 | // #define PRF(x) | ||
| 153 | #endif | ||
| 154 | #endif | ||
| 155 | |||
| 62 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | 156 | WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) |
| 63 | { | 157 | { |
| 64 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | 158 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ |
| @@ -72,7 +166,43 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | |||
| 72 | 166 | ||
| 73 | unsigned threadId; | 167 | unsigned threadId; |
| 74 | *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); | 168 | *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId)); |
| 75 | 169 | ||
| 170 | #if 0 // 1 : for debug | ||
| 171 | { | ||
| 172 | DWORD_PTR prevMask; | ||
| 173 | DWORD_PTR affinity = 1 << 0; | ||
| 174 | prevMask = SetThreadAffinityMask(*p, (DWORD_PTR)affinity); | ||
| 175 | prevMask = prevMask; | ||
| 176 | } | ||
| 177 | #endif | ||
| 178 | #if 0 // 1 : for debug | ||
| 179 | { | ||
| 180 | /* win10: new thread will be created in same group that is assigned to parent thread | ||
| 181 | but affinity mask will contain all allowed threads of that group, | ||
| 182 | even if affinity mask of parent group is not full | ||
| 183 | win11: what group it will be created, if we have set | ||
| 184 | affinity of parent thread with ThreadGroupAffinity? | ||
| 185 | */ | ||
| 186 | const | ||
| 187 | Func_GetThreadGroupAffinity fn = | ||
| 188 | (Func_GetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 189 | "GetThreadGroupAffinity"); | ||
| 190 | if (fn) | ||
| 191 | { | ||
| 192 | // BOOL wres2; | ||
| 193 | MY_GROUP_AFFINITY groupAffinity; | ||
| 194 | memset(&groupAffinity, 0, sizeof(groupAffinity)); | ||
| 195 | /* wres2 = */ fn(*p, &groupAffinity); | ||
| 196 | PRF(printf("\n==Thread_Create cur = %6u GetThreadGroupAffinity(): " | ||
| 197 | "wres2_BOOL = %u, group=%u mask=%x\n", | ||
| 198 | GetCurrentThreadId(), | ||
| 199 | wres2, | ||
| 200 | groupAffinity.Group, | ||
| 201 | (UInt32)groupAffinity.Mask);) | ||
| 202 | } | ||
| 203 | } | ||
| 204 | #endif | ||
| 205 | |||
| 76 | #endif | 206 | #endif |
| 77 | 207 | ||
| 78 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | 208 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ |
| @@ -110,7 +240,84 @@ WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param | |||
| 110 | */ | 240 | */ |
| 111 | } | 241 | } |
| 112 | { | 242 | { |
| 113 | DWORD prevSuspendCount = ResumeThread(h); | 243 | const DWORD prevSuspendCount = ResumeThread(h); |
| 244 | /* ResumeThread() returns: | ||
| 245 | 0 : was_not_suspended | ||
| 246 | 1 : was_resumed | ||
| 247 | -1 : error | ||
| 248 | */ | ||
| 249 | if (prevSuspendCount == (DWORD)-1) | ||
| 250 | wres = GetError(); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | /* maybe we must use errno here, but probably GetLastError() is also OK. */ | ||
| 255 | return wres; | ||
| 256 | |||
| 257 | #endif | ||
| 258 | } | ||
| 259 | |||
| 260 | |||
| 261 | WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinityMask) | ||
| 262 | { | ||
| 263 | #ifdef USE_THREADS_CreateThread | ||
| 264 | |||
| 265 | UNUSED_VAR(group) | ||
| 266 | UNUSED_VAR(affinityMask) | ||
| 267 | return Thread_Create(p, func, param); | ||
| 268 | |||
| 269 | #else | ||
| 270 | |||
| 271 | /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ | ||
| 272 | HANDLE h; | ||
| 273 | WRes wres; | ||
| 274 | unsigned threadId; | ||
| 275 | h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId)); | ||
| 276 | *p = h; | ||
| 277 | wres = HandleToWRes(h); | ||
| 278 | if (h) | ||
| 279 | { | ||
| 280 | // PrintProcess_Info(); | ||
| 281 | { | ||
| 282 | const | ||
| 283 | Func_SetThreadGroupAffinity fn = | ||
| 284 | (Func_SetThreadGroupAffinity) Z7_CAST_FUNC_C GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), | ||
| 285 | "SetThreadGroupAffinity"); | ||
| 286 | if (fn) | ||
| 287 | { | ||
| 288 | // WRes wres2; | ||
| 289 | MY_GROUP_AFFINITY groupAffinity, prev_groupAffinity; | ||
| 290 | memset(&groupAffinity, 0, sizeof(groupAffinity)); | ||
| 291 | // groupAffinity.Mask must use only bits that supported by current group | ||
| 292 | // (groupAffinity.Mask = 0) means all allowed bits | ||
| 293 | groupAffinity.Mask = affinityMask; | ||
| 294 | groupAffinity.Group = (WORD)group; | ||
| 295 | // wres2 = | ||
| 296 | fn(h, &groupAffinity, &prev_groupAffinity); | ||
| 297 | /* | ||
| 298 | if (groupAffinity.Group == prev_groupAffinity.Group) | ||
| 299 | wres2 = wres2; | ||
| 300 | else | ||
| 301 | wres2 = wres2; | ||
| 302 | if (wres2 == 0) | ||
| 303 | { | ||
| 304 | wres2 = GetError(); | ||
| 305 | PRF(printf("\n==SetThreadGroupAffinity error: %u\n", wres2);) | ||
| 306 | } | ||
| 307 | else | ||
| 308 | { | ||
| 309 | PRF(printf("\n==Thread_Create_With_Group::SetThreadGroupAffinity()" | ||
| 310 | " threadId = %6u" | ||
| 311 | " group=%u mask=%x\n", | ||
| 312 | threadId, | ||
| 313 | prev_groupAffinity.Group, | ||
| 314 | (UInt32)prev_groupAffinity.Mask);) | ||
| 315 | } | ||
| 316 | */ | ||
| 317 | } | ||
| 318 | } | ||
| 319 | { | ||
| 320 | const DWORD prevSuspendCount = ResumeThread(h); | ||
| 114 | /* ResumeThread() returns: | 321 | /* ResumeThread() returns: |
| 115 | 0 : was_not_suspended | 322 | 0 : was_not_suspended |
| 116 | 1 : was_resumed | 323 | 1 : was_resumed |
| @@ -297,6 +504,13 @@ WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) | |||
| 297 | return Thread_Create_With_CpuSet(p, func, param, NULL); | 504 | return Thread_Create_With_CpuSet(p, func, param, NULL); |
| 298 | } | 505 | } |
| 299 | 506 | ||
| 507 | /* | ||
| 508 | WRes Thread_Create_With_Group(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, unsigned group, CAffinityMask affinity) | ||
| 509 | { | ||
| 510 | UNUSED_VAR(group) | ||
| 511 | return Thread_Create_With_Affinity(p, func, param, affinity); | ||
| 512 | } | ||
| 513 | */ | ||
| 300 | 514 | ||
| 301 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) | 515 | WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity) |
| 302 | { | 516 | { |
| @@ -577,5 +791,22 @@ WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p) | |||
| 577 | return AutoResetEvent_CreateNotSignaled(p); | 791 | return AutoResetEvent_CreateNotSignaled(p); |
| 578 | } | 792 | } |
| 579 | 793 | ||
| 794 | void ThreadNextGroup_Init(CThreadNextGroup *p, UInt32 numGroups, UInt32 startGroup) | ||
| 795 | { | ||
| 796 | // printf("\n====== ThreadNextGroup_Init numGroups = %x: startGroup=%x\n", numGroups, startGroup); | ||
| 797 | if (numGroups == 0) | ||
| 798 | numGroups = 1; | ||
| 799 | p->NumGroups = numGroups; | ||
| 800 | p->NextGroup = startGroup % numGroups; | ||
| 801 | } | ||
| 802 | |||
| 803 | |||
| 804 | UInt32 ThreadNextGroup_GetNext(CThreadNextGroup *p) | ||
| 805 | { | ||
| 806 | const UInt32 next = p->NextGroup; | ||
| 807 | p->NextGroup = (next + 1) % p->NumGroups; | ||
| 808 | return next; | ||
| 809 | } | ||
| 810 | |||
| 580 | #undef PRF | 811 | #undef PRF |
| 581 | #undef Print | 812 | #undef Print |
