]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/libshared/src/libshared_porting_abstraction_layer/libshared_porting_abstraction_layer_thread_start.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / libshared / src / libshared_porting_abstraction_layer / libshared_porting_abstraction_layer_thread_start.c
1 /***** includes *****/
2 #include "libshared_porting_abstraction_layer_internal.h"
3
4
5
6
7
8 /****************************************************************************/
9 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WIN7 && !defined KERNEL_MODE )
10
11   #ifdef LIBSHARED_PAL_THREAD_START
12     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
13   #endif
14
15   #define LIBSHARED_PAL_THREAD_START
16
17   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
18                                   struct libshared_pal_thread_info *pti )
19   {
20     BOOL
21       brv;
22
23     DWORD
24       thread_id;
25
26     GROUP_AFFINITY
27       ga;
28
29     int
30       rv = 0;
31
32     LPPROC_THREAD_ATTRIBUTE_LIST
33       attribute_list;
34
35     SIZE_T
36       attribute_list_length;
37
38     LFDS710_PAL_ASSERT( thread_handle != NULL );
39     LFDS710_PAL_ASSERT( pti != NULL );
40
41     /* TRD : here we're using CreateRemoteThreadEx() to start a thread in our own process
42              we do this because as a function, it allows us to specify processor and processor group affinity in the create call
43     */
44
45     brv = InitializeProcThreadAttributeList( NULL, 1, 0, &attribute_list_length );
46     attribute_list = VirtualAlloc( NULL, attribute_list_length, MEM_COMMIT, PAGE_READWRITE );
47     brv = InitializeProcThreadAttributeList( attribute_list, 1, 0, &attribute_list_length );
48
49     ga.Mask = ( (KAFFINITY) 1 << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti) );
50     ga.Group = (WORD) LIBSHARED_PAL_PTI_GET_WINDOWS_PROCESSOR_GROUP_NUMBER(*pti);
51     ga.Reserved[0] = ga.Reserved[1] = ga.Reserved[2] = 0;
52
53     brv = UpdateProcThreadAttribute( attribute_list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &ga, sizeof(GROUP_AFFINITY), NULL, NULL );
54     *thread_handle = CreateRemoteThreadEx( GetCurrentProcess(), NULL, 0, LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti), NO_FLAGS, attribute_list, &thread_id );
55
56     DeleteProcThreadAttributeList( attribute_list );
57     VirtualFree( attribute_list, 0, MEM_RELEASE );
58
59     if( *thread_handle != NULL )
60       rv = 1;
61
62     return rv;
63   }
64
65 #endif
66
67
68
69
70
71 /****************************************************************************/
72 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 && !defined KERNEL_MODE )
73
74   #ifdef LIBSHARED_PAL_THREAD_START
75     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
76   #endif
77
78   #define LIBSHARED_PAL_THREAD_START
79
80   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
81                                   struct libshared_pal_thread_info *pti )
82   {
83     int
84       rv = 0;
85
86     DWORD
87       thread_id;
88
89     DWORD_PTR
90       affinity_mask,
91       result;
92
93     LFDS710_PAL_ASSERT( thread_handle != NULL );
94     LFDS710_PAL_ASSERT( pti != NULL );
95
96     /* TRD : Vista and earlier do not support processor groups
97              as such, there is a single implicit processor group
98              also, there's no support for actually starting a thread in its correct NUMA node / logical processor
99              so we make the best of it; we start suspended, set the affinity, and then resume
100              the thread itself internally is expected to be making allocs from the correct NUMA node
101     */
102
103     *thread_handle = CreateThread( NULL, 0, LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti), CREATE_SUSPENDED, &thread_id );
104
105     if( *thread_handle != NULL )
106     {
107       affinity_mask = (DWORD_PTR) (1 << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti));
108       SetThreadAffinityMask( *thread_handle, affinity_mask );
109       ResumeThread( *thread_handle );
110       rv = 1;
111     }
112
113     return rv;
114   }
115
116 #endif
117
118
119
120
121
122
123 /****************************************************************************/
124 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 && defined KERNEL_MODE )
125
126   #ifdef LIBSHARED_PAL_THREAD_START
127     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
128   #endif
129
130   #define LIBSHARED_PAL_THREAD_START
131
132   /***** prototypes *****/
133   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
134
135   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
136                                   struct libshared_pal_thread_info *pti )
137   {
138     int
139       rv = 0;
140
141     NTSTATUS
142       nts_create;
143
144     OBJECT_ATTRIBUTES
145       oa;
146
147     assert( thread_state != NULL );
148     // TRD : cpu can be any value in its range
149     assert( thread_function != NULL );
150     // TRD : thread_user_state can be NULL
151
152     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
153
154     nts_create = PsCreateSystemThread( thread_handle, THREAD_ALL_ACCESS, &oa, NtCurrentProcess(), NULL, test_pal_internal_thread_function, pti );
155
156     if( nts_create == STATUS_SUCCESS )
157       rv = 1;
158
159     return rv;
160   }
161
162   /****************************************************************************/
163   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
164   {
165     KAFFINITY
166       affinity;
167
168     struct libshared_pal_thread_info
169       *pti;
170
171     LFDS710_PAL_ASSERT( thread_user_state != NULL );
172
173     pti = (struct libshared_pal_thread_info *) thread_user_state;
174
175     affinity = 1 << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti);
176
177     KeSetSystemAffinityThread( affinity );
178
179     LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
180
181     return;
182   }
183
184 #endif
185
186
187
188
189
190 /****************************************************************************/
191 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WIN7 && defined KERNEL_MODE )
192
193   #ifdef LIBSHARED_PAL_THREAD_START
194     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
195   #endif
196
197   #define LIBSHARED_PAL_THREAD_START
198
199   /***** prototypes *****/
200   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
201
202   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
203                                   struct libshared_pal_thread_info *pti )
204   {
205     int
206       rv = 0;
207
208     NTSTATUS
209       nts_create;
210
211     OBJECT_ATTRIBUTES
212       oa;
213
214     assert( thread_state != NULL );
215     // TRD : cpu can be any value in its range
216     assert( thread_function != NULL );
217     // TRD : thread_user_state can be NULL
218
219     InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
220
221     nts_create = PsCreateSystemThread( thread_handle, THREAD_ALL_ACCESS, &oa, NtCurrentProcess(), NULL, test_pal_internal_thread_function, pti );
222
223     if( nts_create == STATUS_SUCCESS )
224       rv = 1;
225
226     return rv;
227   }
228
229   /****************************************************************************/
230   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
231   {
232     GROUP_AFFINITY
233       group_affinity,
234       previous_group_affinity;
235
236     struct libshared_pal_thread_info
237       *pti;
238
239     LFDS710_PAL_ASSERT( thread_user_state != NULL );
240
241     pti = (struct libshared_pal_thread_info *) thread_user_state;
242
243     KeSetSystemGroupAffinityThread( &group_affinity, &previous_group_affinity );
244
245     group_affinity.Mask = ( (KAFFINITY) 1 ) << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti);
246     // TRD : Group is a WORD in the user-mode MS docs, but a USHORT in WDK7.1 headers
247     group_affinity.Group = (USHORT) LIBSHARED_PAL_PTI_GET_WINDOWS_PROCESSOR_GROUP_NUMBER(*pti);
248     group_affinity.Reserved[0] = group_affinity.Reserved[1] = group_affinity.Reserved[2] = 0;
249
250     LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
251
252     return;
253   }
254
255 #endif
256
257
258
259
260
261 /****************************************************************************/
262 #if( defined __linux__ && defined _POSIX_THREADS && _POSIX_THREADS > 0 && !defined KERNEL_MODE )
263
264   #ifdef LIBSHARED_PAL_THREAD_START
265     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
266   #endif
267
268   #define LIBSHARED_PAL_THREAD_START
269
270   /***** prototypes *****/
271   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
272
273   /****************************************************************************/
274   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
275                                   struct libshared_pal_thread_info *pti )
276   {
277     int
278       rv;
279
280     /* TRD : this implementation exists because the pthreads function for setting thread affinity,
281              pthread_attr_setaffinity_np(), works on Linux, but not Android
282     */
283
284     LFDS710_PAL_ASSERT( thread_handle != NULL );
285     LFDS710_PAL_ASSERT( pti != NULL );
286
287     rv = pthread_create( thread_handle, NULL, test_pal_internal_thread_function, pti );
288
289     if( rv == 0 )
290       rv = 1;
291
292     return rv;
293   }
294
295   /****************************************************************************/
296   static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
297   {
298     cpu_set_t
299       cpuset;
300
301     pid_t
302       tid;
303
304     struct libshared_pal_thread_info
305       *pti;
306
307     LIBSHARED_PAL_THREAD_RETURN_TYPE
308       rv;
309
310     LFDS710_PAL_ASSERT( thread_user_state != NULL );
311
312     /* TRD : the APIs under Linux/POSIX for setting thread affinity are in a mess
313
314              pthreads offers pthread_attr_setaffinity_np(), which glibc supports, but which is not supported by Android
315
316              Linux offers sched_setaffinity(), but this needs a *thread pid*,
317              and the only API to get a thread pid is gettid(), which works for
318              and only for *the calling thread*
319
320              so we come to this - a wrapper thread function, which is the function used
321              when starting a thread; this calls gettid() and then sched_setaffinity(),
322              and then calls into the actual thread function
323
324              generally shaking my head in disbelief at this point
325     */
326
327     pti = (struct libshared_pal_thread_info *) thread_user_state;
328
329     CPU_ZERO( &cpuset );
330     CPU_SET( LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti), &cpuset );
331
332     tid = syscall( SYS_gettid );
333
334     sched_setaffinity( tid, sizeof(cpu_set_t), &cpuset );
335
336     rv = LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
337
338     return LIBSHARED_PAL_THREAD_RETURN_CAST(rv);
339   }
340
341 #endif
342
343
344
345
346
347 /****************************************************************************/
348 #if( !defined __linux__ && defined _POSIX_THREADS && _POSIX_THREADS > 0 && !defined KERNEL_MODE )
349
350   #ifdef LIBSHARED_PAL_THREAD_START
351     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
352   #endif
353
354   #define LIBSHARED_PAL_THREAD_START
355
356   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
357                                   struct libshared_pal_thread_info *pti )
358   {
359     int
360       rv = 0,
361       rv_create;
362
363     cpu_set_t
364       cpuset;
365
366     pthread_attr_t
367       attr;
368
369     LFDS710_PAL_ASSERT( thread_handle != NULL );
370     LFDS710_PAL_ASSERT( pti != NULL );
371
372     pthread_attr_init( &attr );
373
374     CPU_ZERO( &cpuset );
375     CPU_SET( LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti), &cpuset );
376     pthread_attr_setaffinity_np( &attr, sizeof(cpuset), &cpuset );
377
378     rv_create = pthread_create( thread_handle, &attr, LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
379
380     if( rv_create == 0 )
381       rv = 1;
382
383     pthread_attr_destroy( &attr );
384
385     return rv;
386   }
387
388 #endif
389
390
391
392
393
394 /****************************************************************************/
395 #if( defined __linux__ && defined KERNEL_MODE )
396
397   #ifdef LIBSHARED_PAL_THREAD_START
398     #error More than one porting abstraction layer matches the current platform in "libshared_porting_abstraction_layer_thread_start.c".
399   #endif
400
401   #define LIBSHARED_PAL_THREAD_START
402
403   int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
404                                   struct libshared_pal_thread_info *pti )
405   {
406     LFDS710_PAL_ASSERT( thread_handle != NULL );
407     LFDS710_PAL_ASSERT( pti != NULL );
408
409     *thread_handle = kthread_create_on_node( LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti), (int) LIBSHARED_PAL_PTI_GET_NUMA_NODE_ID(*pti), "lfds" );
410
411     kthread_bind( *thread_handle, LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti) );
412
413     wake_up_process( *thread_handle );
414
415     return 1;
416   }
417
418 #endif
419
420
421
422
423
424 /****************************************************************************/
425 #if( !defined LIBSHARED_PAL_THREAD_START )
426
427   #error No matching porting abstraction layer in "libshared_porting_abstraction_layer_thread_start.c".
428
429 #endif
430