8 /****************************************************************************/
9 #if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WIN7 )
11 /* TRD : _WIN32 indicates 32-bit or 64-bit Windows
12 !_KERNEL_MODE indicates Windows user-mode
13 NTDDI_VERSION indicates Windows version
14 - GetCurrentProcess requires XP
15 - InitializeProcThreadAttributeList requires Windows 7
16 - CreateRemoteThreadEx requires Windows 7
19 #ifdef TEST_PAL_THREAD_START
20 #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c
23 #define TEST_PAL_THREAD_START
25 int test_pal_thread_start( test_pal_thread_state_t *thread_state,
26 struct test_pal_logical_processor *lp,
27 test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
28 void *thread_user_state )
42 LPPROC_THREAD_ATTRIBUTE_LIST
46 attribute_list_length;
48 assert( thread_state != NULL );
50 assert( thread_function != NULL );
51 // TRD : thread_user_state can be NULL
53 /* TRD : here we're using CreateRemoteThreadEx() to start a thread in our own process
54 we do this because as a function, it allows us to specify processor and processor group affinity in the create call
57 brv = InitializeProcThreadAttributeList( NULL, 1, 0, &attribute_list_length );
58 attribute_list = malloc( attribute_list_length );
59 brv = InitializeProcThreadAttributeList( attribute_list, 1, 0, &attribute_list_length );
61 ga.Mask = ( (KAFFINITY) 1 << lp->logical_processor_number );
62 ga.Group = (WORD) lp->windows_logical_processor_group_number;
63 memset( ga.Reserved, 0, sizeof(WORD) * 3 );
65 brv = UpdateProcThreadAttribute( attribute_list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &ga, sizeof(GROUP_AFFINITY), NULL, NULL );
66 *thread_state = CreateRemoteThreadEx( GetCurrentProcess(), NULL, 0, thread_function, thread_user_state, NO_FLAGS, attribute_list, &thread_id );
68 DeleteProcThreadAttributeList( attribute_list );
69 free( attribute_list );
71 if( *thread_state != NULL )
83 /****************************************************************************/
84 #if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 )
86 /* TRD : _WIN32 indicates 64-bit or 32-bit Windows
87 NTDDI_VERSION indicates Windows version
88 - CreateThread requires XP
89 - SetThreadAffinityMask requires XP
90 - ResumeThread requires XP
93 #ifdef TEST_PAL_THREAD_START
94 #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c
97 #define TEST_PAL_THREAD_START
99 int test_pal_thread_start( test_pal_thread_state_t *thread_state,
100 struct test_pal_logical_processor *lp,
101 test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
102 void *thread_user_state )
114 assert( thread_state != NULL );
115 assert( lp != NULL );
116 assert( thread_function != NULL );
117 // TRD : thread_user_state can be NULL
119 /* TRD : Vista and earlier do not support processor groups
120 as such, there is a single implicit processor group
121 also, there's no support for actually starting a thread in its correct NUMA node / logical processor
122 so we make the best of it; we start suspended, set the affinity, and then resume
123 the thread itself internally is expected to be making allocs from the correct NUMA node
126 *thread_state = CreateThread( NULL, 0, thread_function, thread_user_state, CREATE_SUSPENDED, &thread_id );
128 affinity_mask = (DWORD_PTR) (1 << lp->logical_processor_number);
130 SetThreadAffinityMask( *thread_state, affinity_mask );
132 ResumeThread( *thread_state );
134 if( *thread_state != NULL )
146 /****************************************************************************/
147 #if( defined __linux__ && _POSIX_THREADS > 0 )
149 /* TRD : __linux__ indicates Linux
150 - gettid requires Linux
151 - sched_setaffinity requires Linux
152 _POSIX_THREADS indicates POSIX threads
153 - pthread_create requires POSIX
156 #ifdef TEST_PAL_THREAD_START
157 #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c
160 #define TEST_PAL_THREAD_START
162 /***** structs *****/
163 struct test_pal_internal_thread_state
165 struct test_pal_logical_processor
168 test_pal_thread_return_t
169 (TEST_PAL_CALLING_CONVENTION *thread_function)( void *thread_user_state );
175 /***** prototypes *****/
176 test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
178 /****************************************************************************/
179 int test_pal_thread_start( test_pal_thread_state_t *thread_state,
180 struct test_pal_logical_processor *lp,
181 test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
182 void *thread_user_state )
187 struct test_pal_internal_thread_state
190 /* TRD : this implementation works on Linux only as it uses sched_setaffinity(), which is Linux specific
191 although I cannot currently test, I believe this function also works on Android
193 this implementation exists because the pthreads function for setting thread affinity,
194 pthread_attr_setaffinity_np(), works on Linux, but not Android
197 assert( thread_state != NULL );
198 assert( lp != NULL );
199 assert( thread_function != NULL );
200 // TRD : thread_user_state can be NULL
202 its = malloc( sizeof(struct test_pal_internal_thread_state) );
205 its->thread_function = thread_function;
206 its->thread_user_state = thread_user_state;
208 rv = pthread_create( thread_state, NULL, test_pal_internal_thread_function, its );
216 /****************************************************************************/
217 test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
225 struct test_pal_internal_thread_state
228 test_pal_thread_return_t
231 assert( thread_user_state != NULL );
233 /* TRD : the APIs under Linux/POSIX for setting thread affinity are in a mess
234 pthreads offers pthread_attr_setaffinity_np(), which glibc supports,
235 but which is not supported by Android
236 Linux offers sched_setaffinity(), but this needs a *thread pid*,
237 and the only API to get a thread pid is gettid(), which works for
238 and only for *the calling thread*
240 so we come to this - a wrapper thread function, which is the function used
241 when starting a thread; this calls gettid() and then sched_setaffinity(),
242 and then calls into the actual thread function
244 generally shaking my head in disbelief at this point
247 assert( thread_user_state != NULL );
249 its = (struct test_pal_internal_thread_state *) thread_user_state;
252 CPU_SET( its->lp.logical_processor_number, &cpuset );
254 tid = syscall( SYS_gettid );
256 sched_setaffinity( tid, sizeof(cpu_set_t), &cpuset );
258 rv = its->thread_function( its->thread_user_state );
271 /****************************************************************************/
272 #if( !defined __linux__ && _POSIX_THREADS > 0 )
274 /* TRD : !__linux__ indicates not Linux
275 _POSIX_THREADS indicates POSIX threads
276 - pthread_attr_init requires POSIX
277 - pthread_attr_setaffinity_np requires POSIX
278 - pthread_create requires POSIX
279 - pthread_attr_destroy requires POSIX
282 #ifdef TEST_PAL_THREAD_START
283 #error More than one porting abstraction layer matches the current platform in test_porting_abstraction_layer_thread_start.c
286 #define TEST_PAL_THREAD_START
288 int test_pal_thread_start( test_pal_thread_state_t *thread_state,
289 struct test_pal_logical_processor *lp,
290 test_pal_thread_return_t (TEST_PAL_CALLING_CONVENTION *thread_function)(void *thread_user_state),
291 void *thread_user_state )
303 assert( thread_state != NULL );
304 assert( lp != NULL );
305 assert( thread_function != NULL );
306 // TRD : thread_user_state can be NULL
308 pthread_attr_init( &attr );
311 CPU_SET( lp->logical_processor_number, &cpuset );
312 pthread_attr_setaffinity_np( &attr, sizeof(cpuset), &cpuset );
314 rv_create = pthread_create( thread_state, &attr, thread_function, thread_user_state );
319 pthread_attr_destroy( &attr );
330 /****************************************************************************/
331 #if( !defined TEST_PAL_THREAD_START )
333 #error test_pal_thread_start() not implemented for this platform.