2 #include "libtest_tests_internal.h"
5 struct test_per_thread_state
7 struct lfds710_freelist_state
10 struct lfds710_prng_st_state
16 struct lfds710_freelist_element
23 /***** private prototypes *****/
24 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping( void *libtest_threadset_per_thread_state );
30 /****************************************************************************/
31 void libtest_tests_freelist_ea_popping( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
36 number_elements_in_freelist,
37 number_logical_processors,
40 smallest_power_of_two_larger_than_or_equal_to_number_logical_processors = 2,
41 temp_number_logical_processors;
43 struct lfds710_freelist_element * volatile
44 (*ea)[LFDS710_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS];
46 struct lfds710_freelist_state
49 struct lfds710_list_asu_element
52 struct lfds710_misc_validation_info
55 struct lfds710_prng_st_state
58 struct libtest_logical_processor
61 struct libtest_threadset_per_thread_state
64 struct libtest_threadset_state
70 struct test_per_thread_state
73 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
74 LFDS710_PAL_ASSERT( ms != NULL );
75 LFDS710_PAL_ASSERT( dvs != NULL );
77 /* TRD : we create a freelist with as many elements as possible elements
79 the creation function runs in a single thread and creates
80 and pushes thofe elements onto the freelist
82 each element contains a void pointer to the container test element
84 we then run one thread per CPU
85 where each thread loops, popping as quickly as possible
86 each test element has a flag which indicates it has been popped
88 the threads run till the source freelist is empty
90 we then check the test elements
91 every element should have been popped
96 *dvs = LFDS710_MISC_VALIDITY_VALID;
98 lfds710_prng_st_init( &psts, LFDS710_PRNG_SEED );
100 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
102 temp_number_logical_processors = number_logical_processors >> 2;
103 while( temp_number_logical_processors != 0 )
105 temp_number_logical_processors >>= 1;
106 smallest_power_of_two_larger_than_or_equal_to_number_logical_processors <<= 1;
110 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
111 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
112 ea = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct lfds710_freelist_element *) * LFDS710_FREELIST_ELIMINATION_ARRAY_ELEMENT_SIZE_IN_FREELIST_ELEMENTS * smallest_power_of_two_larger_than_or_equal_to_number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
113 te_array = libshared_memory_alloc_largest_possible_array_from_unknown_node( ms, sizeof(struct test_element), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES, &number_elements );
115 lfds710_freelist_init_valid_on_current_logical_core( &fs, ea, smallest_power_of_two_larger_than_or_equal_to_number_logical_processors, NULL );
117 for( loop = 0 ; loop < number_elements ; loop++ )
119 (te_array+loop)->popped_flag = LOWERED;
120 LFDS710_FREELIST_SET_VALUE_IN_ELEMENT( (te_array+loop)->fe, te_array+loop );
121 lfds710_freelist_push( &fs, &(te_array+loop)->fe, &psts );
124 libtest_threadset_init( &ts, NULL );
128 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors, lasue) )
130 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
132 LFDS710_PRNG_ST_GENERATE( psts, random_value );
133 LFDS710_PRNG_ST_MIXING_FUNCTION( random_value );
134 lfds710_prng_st_init( &tpts[loop].psts, random_value );
136 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_popping, &tpts[loop] );
141 LFDS710_MISC_BARRIER_STORE;
143 lfds710_misc_force_store();
145 // TRD : run the test
146 libtest_threadset_run( &ts );
148 libtest_threadset_cleanup( &ts );
151 LFDS710_MISC_BARRIER_LOAD;
153 /* TRD : there is a chance, although tiny, that some elements remain in the elimination layer
154 each worker thread returns when a pop() fails, so they can return while elements remain in the EL
155 so now we're validating, we ask the freelist for a count
156 we then count the number of elements in the te_array which are RAISED and LOWERED
157 and the LOWERED count should equal the number of elements remaining in the freelist
158 we could go further and check they are the *same* elements, but this all needs rewriting...
161 lfds710_freelist_query( &fs, LFDS710_FREELIST_QUERY_SINGLETHREADED_GET_COUNT, NULL, &number_elements_in_freelist );
163 vi.min_elements = vi.max_elements = number_elements_in_freelist;
165 lfds710_freelist_query( &fs, LFDS710_FREELIST_QUERY_SINGLETHREADED_VALIDATE, &vi, dvs );
167 // TRD : now we check each element has popped_flag fet to RAISED
168 for( loop = 0 ; loop < number_elements ; loop++ )
169 if( (te_array+loop)->popped_flag == RAISED )
172 if( raised_count != number_elements - number_elements_in_freelist )
173 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
176 lfds710_freelist_cleanup( &fs, NULL );
185 /****************************************************************************/
186 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_popping( void *libtest_threadset_per_thread_state )
188 struct lfds710_freelist_element
191 struct test_per_thread_state
194 struct libtest_threadset_per_thread_state
200 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
202 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
204 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
206 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
208 libtest_threadset_thread_ready_and_wait( pts );
210 while( lfds710_freelist_pop(tpts->fs, &fe, &tpts->psts) )
212 te = LFDS710_FREELIST_GET_VALUE_FROM_ELEMENT( *fe );
213 te->popped_flag = RAISED;
216 LFDS710_MISC_BARRIER_STORE;
218 lfds710_misc_force_store();
220 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);