]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.0.0/test/src/test_porting_abstraction_layer_thread_start.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.0.0 / test / src / test_porting_abstraction_layer_thread_start.c
1 /***** includes *****/
2 #include "internal.h"
3
4
5
6
7
8 /****************************************************************************/
9 #if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WIN7 )
10
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
17   */
18
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
21   #endif
22
23   #define TEST_PAL_THREAD_START
24
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 )
29   {
30     BOOL
31       brv;
32
33     DWORD
34       thread_id;
35
36     GROUP_AFFINITY
37       ga;
38
39     int
40       rv = 0;
41
42     LPPROC_THREAD_ATTRIBUTE_LIST
43       attribute_list;
44
45     SIZE_T
46       attribute_list_length;
47
48     assert( thread_state != NULL );
49     assert( lp != NULL );
50     assert( thread_function != NULL );
51     // TRD : thread_user_state can be NULL
52
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
55     */
56
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 );
60
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 );
64
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 );
67
68     DeleteProcThreadAttributeList( attribute_list );
69     free( attribute_list );
70
71     if( *thread_state != NULL )
72       rv = 1;
73
74     return( rv );
75   }
76
77 #endif
78
79
80
81
82
83 /****************************************************************************/
84 #if( defined _WIN32 && !defined _KERNEL_MODE && NTDDI_VERSION >= NTDDI_WINXP && NTDDI_VERSION < NTDDI_WIN7 )
85
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
91   */
92
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
95   #endif
96
97   #define TEST_PAL_THREAD_START
98
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 )
103   {
104     int
105       rv = 0;
106
107     DWORD
108       thread_id;
109
110     DWORD_PTR
111       affinity_mask,
112       result;
113
114     assert( thread_state != NULL );
115     assert( lp != NULL );
116     assert( thread_function != NULL );
117     // TRD : thread_user_state can be NULL
118
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
124     */
125
126     *thread_state = CreateThread( NULL, 0, thread_function, thread_user_state, CREATE_SUSPENDED, &thread_id );
127
128     affinity_mask = (DWORD_PTR) (1 << lp->logical_processor_number);
129
130     SetThreadAffinityMask( *thread_state, affinity_mask );
131
132     ResumeThread( *thread_state );
133
134     if( *thread_state != NULL )
135       rv = 1;
136
137     return( rv );
138   }
139
140 #endif
141
142
143
144
145
146 /****************************************************************************/
147 #if( defined __linux__ && _POSIX_THREADS > 0 )
148
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
154   */
155
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
158   #endif
159
160   #define TEST_PAL_THREAD_START
161
162   /***** structs *****/
163   struct test_pal_internal_thread_state
164   {
165     struct test_pal_logical_processor
166       lp;
167
168     test_pal_thread_return_t
169       (TEST_PAL_CALLING_CONVENTION *thread_function)( void *thread_user_state );
170
171     void
172       *thread_user_state;
173   };
174
175   /***** prototypes *****/
176   test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state );
177
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 )
183   {
184     int
185       rv;
186
187     struct test_pal_internal_thread_state
188       *its;
189
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
192
193              this implementation exists because the pthreads function for setting thread affinity,
194              pthread_attr_setaffinity_np(), works on Linux, but not Android
195     */
196
197     assert( thread_state != NULL );
198     assert( lp != NULL );
199     assert( thread_function != NULL );
200     // TRD : thread_user_state can be NULL
201
202     its = malloc( sizeof(struct test_pal_internal_thread_state) );
203
204     its->lp = *lp;
205     its->thread_function = thread_function;
206     its->thread_user_state = thread_user_state;
207
208     rv = pthread_create( thread_state, NULL, test_pal_internal_thread_function, its );
209
210     if( rv == 0 )
211       rv = 1;
212
213     return( rv );
214   }
215
216   /****************************************************************************/
217   test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION test_pal_internal_thread_function( void *thread_user_state )
218   {
219     cpu_set_t
220       cpuset;
221
222     pid_t
223       tid;
224
225     struct test_pal_internal_thread_state
226       *its;
227
228     test_pal_thread_return_t
229       rv;
230
231     assert( thread_user_state != NULL );
232
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*
239
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
243
244              generally shaking my head in disbelief at this point
245     */
246
247     assert( thread_user_state != NULL );
248
249     its = (struct test_pal_internal_thread_state *) thread_user_state;
250
251     CPU_ZERO( &cpuset );
252     CPU_SET( its->lp.logical_processor_number, &cpuset );
253
254     tid = syscall( SYS_gettid );
255
256     sched_setaffinity( tid, sizeof(cpu_set_t), &cpuset );
257
258     rv = its->thread_function( its->thread_user_state );
259
260     free( its );
261
262     return( rv );
263   }
264
265 #endif
266
267
268
269
270
271 /****************************************************************************/
272 #if( !defined __linux__ && _POSIX_THREADS > 0 )
273
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
280   */
281
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
284   #endif
285
286   #define TEST_PAL_THREAD_START
287
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 )
292   {
293     int
294       rv = 0,
295       rv_create;
296
297     cpu_set_t
298       cpuset;
299
300     pthread_attr_t
301       attr;
302
303     assert( thread_state != NULL );
304     assert( lp != NULL );
305     assert( thread_function != NULL );
306     // TRD : thread_user_state can be NULL
307
308     pthread_attr_init( &attr );
309
310     CPU_ZERO( &cpuset );
311     CPU_SET( lp->logical_processor_number, &cpuset );
312     pthread_attr_setaffinity_np( &attr, sizeof(cpuset), &cpuset );
313
314     rv_create = pthread_create( thread_state, &attr, thread_function, thread_user_state );
315
316     if( rv_create == 0 )
317       rv = 1;
318
319     pthread_attr_destroy( &attr );
320
321     return( rv );
322   }
323
324 #endif
325
326
327
328
329
330 /****************************************************************************/
331 #if( !defined TEST_PAL_THREAD_START )
332
333   #error test_pal_thread_start() not implemented for this platform.
334
335 #endif
336