diff options
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 |