2 #include "libtest_tests_internal.h"
5 struct test_per_thread_state
12 number_logical_processors,
16 struct lfds710_queue_bmm_state
20 /***** private prototypes *****/
21 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_enqueuer_and_dequeuer( void *libtest_threadset_per_thread_state );
27 /****************************************************************************/
28 void libtest_tests_queue_bmm_enqueuing_and_dequeuing( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
33 number_logical_processors,
35 power_of_two_number_elements = 1,
38 struct lfds710_list_asu_element
41 struct lfds710_queue_bmm_element
44 struct lfds710_queue_bmm_state
47 struct lfds710_misc_validation_info
50 struct libtest_logical_processor
53 struct libtest_threadset_per_thread_state
56 struct libtest_threadset_state
59 struct test_per_thread_state
62 LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
63 LFDS710_PAL_ASSERT( ms != NULL );
64 LFDS710_PAL_ASSERT( dvs != NULL );
66 /* TRD : create a queue with one element per thread
67 each thread constly dequeues and enqueues from that one queue
68 where when enqueuing sets in the element
69 its thread number and counter
70 and when dequeuing, checks the thread number and counter
71 against previously seen counter for that thread
72 where it should always see a higher number
75 *dvs = LFDS710_MISC_VALIDITY_VALID;
78 lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
79 tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
80 pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
81 per_thread_counters = libshared_memory_alloc_from_unknown_node( ms, sizeof(lfds710_pal_uint_t) * number_logical_processors * number_logical_processors, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
82 qbmme_array = libshared_memory_alloc_largest_possible_array_from_unknown_node( ms, sizeof(struct lfds710_queue_bmm_element), LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES, &number_elements );
84 // TRD : need to only use a power of 2 number of elements
85 number_elements >>= 1;
87 while( number_elements != 0 )
89 number_elements >>= 1;
90 power_of_two_number_elements <<= 1;
93 /* TRD : to make the test more demanding, smallest number of elements (greater than number of logical cores)
94 we really want one element per core
95 but with the power-of-2 requirements, we can't have it
98 while( power_of_two_number_elements > number_logical_processors )
99 power_of_two_number_elements >>= 1;
101 lfds710_queue_bmm_init_valid_on_current_logical_core( &qbmms, qbmme_array, power_of_two_number_elements, NULL );
103 // TRD : we assume the test will iterate at least once (or we'll have a false negative)
104 for( loop = 0 ; loop < number_logical_processors ; loop++ )
105 lfds710_queue_bmm_enqueue( &qbmms, (void *) loop, (void *) 0 );
107 libtest_threadset_init( &ts, NULL );
111 while( LFDS710_LIST_ASU_GET_START_AND_THEN_NEXT(*list_of_logical_processors,lasue) )
113 lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
114 (tpts+loop)->qbmms = &qbmms;
115 (tpts+loop)->thread_number = loop;
116 (tpts+loop)->counter = 0;
117 (tpts+loop)->error_flag = LOWERED;
118 (tpts+loop)->per_thread_counters = per_thread_counters + loop * number_logical_processors;
119 (tpts+loop)->number_logical_processors = number_logical_processors;
121 for( subloop = 0 ; subloop < number_logical_processors ; subloop++ )
122 *((tpts+loop)->per_thread_counters+subloop) = 0;
124 libtest_threadset_add_thread( &ts, &pts[loop], lp, thread_enqueuer_and_dequeuer, &tpts[loop] );
128 LFDS710_MISC_BARRIER_STORE;
130 lfds710_misc_force_store();
132 // TRD : run the test
133 libtest_threadset_run( &ts );
135 libtest_threadset_cleanup( &ts );
138 LFDS710_MISC_BARRIER_LOAD;
140 vi.min_elements = vi.max_elements = power_of_two_number_elements;
142 lfds710_queue_bmm_query( &qbmms, LFDS710_QUEUE_BMM_QUERY_SINGLETHREADED_VALIDATE, &vi, dvs );
144 for( loop = 0 ; loop < number_logical_processors ; loop++ )
145 if( (tpts+loop)->error_flag == RAISED )
146 *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
148 lfds710_queue_bmm_cleanup( &qbmms, NULL );
157 /****************************************************************************/
158 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_enqueuer_and_dequeuer( void *libtest_threadset_per_thread_state )
165 struct test_per_thread_state
168 struct libtest_threadset_per_thread_state
175 LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
177 LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
179 pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
180 tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
182 libtest_threadset_thread_ready_and_wait( pts );
184 current_time = start_time = time( NULL );
186 while( current_time < start_time + TEST_DURATION_IN_SECONDS )
188 /* TRD : this is a soft queue, so dequeue/enqueue operations although always occurring
189 may not be visible by the time the enqueue/dequeue function returns
190 i.e. all threads may have dequeued, and then enqueued, but not seen each others enqueues yet
191 so the queue looks empty
194 while( 0 == lfds710_queue_bmm_dequeue(tpts->qbmms, (void *) &thread_number, (void *) &counter) );
196 if( thread_number >= tpts->number_logical_processors )
197 tpts->error_flag = RAISED;
200 if( counter < tpts->per_thread_counters[thread_number] )
201 tpts->error_flag = RAISED;
203 if( counter >= tpts->per_thread_counters[thread_number] )
204 tpts->per_thread_counters[thread_number] = counter+1;
207 thread_number = tpts->thread_number;
208 counter = ++tpts->counter;
210 // TRD : the enqueue can only succeed once a dequeue of the *very next element* in the queue has become visible (i.e. our down earlier dequeue may not be the right dequeue)
211 while( 0 == lfds710_queue_bmm_enqueue(tpts->qbmms, (void *) thread_number, (void *) counter) );
213 if( time_loop++ == TIME_LOOP_COUNT )
216 time( ¤t_time );
220 LFDS710_MISC_BARRIER_STORE;
222 lfds710_misc_force_store();
224 return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);