2 #include "libshared_porting_abstraction_layer_internal.h"
8 /****************************************************************************/
9 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WIN7 && !defined KERNEL_MODE )
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".
15 #define LIBSHARED_PAL_THREAD_START
17 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
18 struct libshared_pal_thread_info *pti )
32 LPPROC_THREAD_ATTRIBUTE_LIST
36 attribute_list_length;
38 LFDS710_PAL_ASSERT( thread_handle != NULL );
39 LFDS710_PAL_ASSERT( pti != NULL );
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
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 );
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;
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 );
56 DeleteProcThreadAttributeList( attribute_list );
57 VirtualFree( attribute_list, 0, MEM_RELEASE );
59 if( *thread_handle != NULL )
71 /****************************************************************************/
72 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 && !defined KERNEL_MODE )
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".
78 #define LIBSHARED_PAL_THREAD_START
80 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
81 struct libshared_pal_thread_info *pti )
93 LFDS710_PAL_ASSERT( thread_handle != NULL );
94 LFDS710_PAL_ASSERT( pti != NULL );
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
103 *thread_handle = CreateThread( NULL, 0, LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti), CREATE_SUSPENDED, &thread_id );
105 if( *thread_handle != NULL )
107 affinity_mask = (DWORD_PTR) (1 << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti));
108 SetThreadAffinityMask( *thread_handle, affinity_mask );
109 ResumeThread( *thread_handle );
123 /****************************************************************************/
124 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 && defined KERNEL_MODE )
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".
130 #define LIBSHARED_PAL_THREAD_START
132 /***** prototypes *****/
133 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
135 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
136 struct libshared_pal_thread_info *pti )
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
152 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
154 nts_create = PsCreateSystemThread( thread_handle, THREAD_ALL_ACCESS, &oa, NtCurrentProcess(), NULL, test_pal_internal_thread_function, pti );
156 if( nts_create == STATUS_SUCCESS )
162 /****************************************************************************/
163 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
168 struct libshared_pal_thread_info
171 LFDS710_PAL_ASSERT( thread_user_state != NULL );
173 pti = (struct libshared_pal_thread_info *) thread_user_state;
175 affinity = 1 << LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti);
177 KeSetSystemAffinityThread( affinity );
179 LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
190 /****************************************************************************/
191 #if( defined _WIN32 && NTDDI_VERSION >= NTDDI_WIN7 && defined KERNEL_MODE )
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".
197 #define LIBSHARED_PAL_THREAD_START
199 /***** prototypes *****/
200 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
202 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
203 struct libshared_pal_thread_info *pti )
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
219 InitializeObjectAttributes( &oa, NULL, OBJ_KERNEL_HANDLE, NULL, NULL );
221 nts_create = PsCreateSystemThread( thread_handle, THREAD_ALL_ACCESS, &oa, NtCurrentProcess(), NULL, test_pal_internal_thread_function, pti );
223 if( nts_create == STATUS_SUCCESS )
229 /****************************************************************************/
230 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
234 previous_group_affinity;
236 struct libshared_pal_thread_info
239 LFDS710_PAL_ASSERT( thread_user_state != NULL );
241 pti = (struct libshared_pal_thread_info *) thread_user_state;
243 KeSetSystemGroupAffinityThread( &group_affinity, &previous_group_affinity );
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;
250 LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
261 /****************************************************************************/
262 #if( defined __linux__ && defined _POSIX_THREADS && _POSIX_THREADS > 0 && !defined KERNEL_MODE )
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".
268 #define LIBSHARED_PAL_THREAD_START
270 /***** prototypes *****/
271 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
273 /****************************************************************************/
274 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
275 struct libshared_pal_thread_info *pti )
280 /* TRD : this implementation exists because the pthreads function for setting thread affinity,
281 pthread_attr_setaffinity_np(), works on Linux, but not Android
284 LFDS710_PAL_ASSERT( thread_handle != NULL );
285 LFDS710_PAL_ASSERT( pti != NULL );
287 rv = pthread_create( thread_handle, NULL, test_pal_internal_thread_function, pti );
295 /****************************************************************************/
296 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
304 struct libshared_pal_thread_info
307 LIBSHARED_PAL_THREAD_RETURN_TYPE
310 LFDS710_PAL_ASSERT( thread_user_state != NULL );
312 /* TRD : the APIs under Linux/POSIX for setting thread affinity are in a mess
314 pthreads offers pthread_attr_setaffinity_np(), which glibc supports, but which is not supported by Android
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*
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
324 generally shaking my head in disbelief at this point
327 pti = (struct libshared_pal_thread_info *) thread_user_state;
330 CPU_SET( LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti), &cpuset );
332 tid = syscall( SYS_gettid );
334 sched_setaffinity( tid, sizeof(cpu_set_t), &cpuset );
336 rv = LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti)( LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
338 return LIBSHARED_PAL_THREAD_RETURN_CAST(rv);
347 /****************************************************************************/
348 #if( !defined __linux__ && defined _POSIX_THREADS && _POSIX_THREADS > 0 && !defined KERNEL_MODE )
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".
354 #define LIBSHARED_PAL_THREAD_START
356 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
357 struct libshared_pal_thread_info *pti )
369 LFDS710_PAL_ASSERT( thread_handle != NULL );
370 LFDS710_PAL_ASSERT( pti != NULL );
372 pthread_attr_init( &attr );
375 CPU_SET( LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti), &cpuset );
376 pthread_attr_setaffinity_np( &attr, sizeof(cpuset), &cpuset );
378 rv_create = pthread_create( thread_handle, &attr, LIBSHARED_PAL_PTI_GET_THREAD_FUNCTION(*pti), LIBSHARED_PAL_PTI_GET_THREAD_ARGUMENT(*pti) );
383 pthread_attr_destroy( &attr );
394 /****************************************************************************/
395 #if( defined __linux__ && defined KERNEL_MODE )
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".
401 #define LIBSHARED_PAL_THREAD_START
403 int libshared_pal_thread_start( libshared_pal_thread_handle_t *thread_handle,
404 struct libshared_pal_thread_info *pti )
406 LFDS710_PAL_ASSERT( thread_handle != NULL );
407 LFDS710_PAL_ASSERT( pti != NULL );
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" );
411 kthread_bind( *thread_handle, LIBSHARED_PAL_PTI_GET_LOGICAL_PROCESSOR_NUMBER(*pti) );
413 wake_up_process( *thread_handle );
424 /****************************************************************************/
425 #if( !defined LIBSHARED_PAL_THREAD_START )
427 #error No matching porting abstraction layer in "libshared_porting_abstraction_layer_thread_start.c".