]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.0.0/test/src/test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.0.0 / test / src / test_lfds700_queue_bounded_singleconsumer_singleproducer_enqueuing_and_dequeuing.c
1 /***** includes *****/
2 #include "internal.h"
3
4 /***** structs *****/
5 struct test_state
6 {
7   enum flag
8     error_flag;
9
10   struct lfds700_queue_bss_state
11     *qs;
12 };
13
14 /***** private prototypes *****/
15 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer( void *util_thread_starter_thread_state );
16 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dequeuer( void *util_thread_starter_thread_state );
17
18
19
20
21
22 /****************************************************************************/
23 void test_lfds700_queue_bss_enqueuing_and_dequeuing( struct lfds700_list_asu_state *list_of_logical_processors )
24 {
25   enum lfds700_misc_validity
26     dvs = LFDS700_MISC_VALIDITY_VALID;
27
28   lfds700_pal_uint_t
29     loop,
30     number_logical_processors,
31     subloop;
32
33   struct lfds700_list_asu_element
34     *lasue;
35
36   struct lfds700_queue_bss_element
37     element_array[4];
38
39   struct lfds700_queue_bss_state
40     qs;
41
42   struct test_pal_logical_processor
43     *lp,
44     *lp_first;
45
46   struct util_thread_starter_state
47     *tts;
48
49   struct test_state
50     *ts;
51
52   test_pal_thread_state_t
53     *thread_handles;
54
55   assert( list_of_logical_processors != NULL );
56
57   /* TRD : so, this is the real test
58            problem is, because we use memory barriers only
59            and we only support one producer and one consumer
60            we need to ensure these threads are on different physical cores
61            if they're on the same core, the code would work even without memory barriers
62
63            problem is, in the test application, we only know the *number* of logical cores
64            obtaining topology information adds a great deal of complexity to the test app
65            and makes porting much harder
66
67            so, we know how many logical cores there are; my thought is to partially
68            permutate over them - we always run the producer on core 0, but we iterate
69            over the other logical cores, running the test once each time, with the
70            consumer being run on core 0, then core 1, then core 2, etc
71
72            (we run on core 0 for the single-cpu case; it's redundent, since a single
73             logical core running both producer and consumer will work, but otherwise
74             we have to skip the test, which is confusing for the user)
75
76            the test is one thread enqueuing and one thread dequeuing for two seconds
77   */
78
79   lfds700_list_asu_query( list_of_logical_processors, LFDS700_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
80
81   internal_display_test_name( "Enqueuing and dequeuing (%d seconds)", number_logical_processors * 2 );
82
83   ts = util_malloc_wrapper( sizeof(struct test_state) * 2 );
84
85   for( loop = 0 ; loop < 2 ; loop++ )
86   {
87     (ts+loop)->qs = &qs;
88     (ts+loop)->error_flag = LOWERED;
89   }
90
91   thread_handles = util_malloc_wrapper( sizeof(test_pal_thread_state_t) * 2 );
92
93   /* TRD : producer always on core 0
94            iterate over the other cores with consumer
95   */
96   
97   lasue = LFDS700_LIST_ASU_GET_START( *list_of_logical_processors );
98   lp_first = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
99
100   while( lasue != NULL )
101   {
102     lp = LFDS700_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
103
104     lfds700_queue_bss_init_valid_on_current_logical_core( &qs, element_array, 4, NULL );
105
106     util_thread_starter_new( &tts, 2 );
107
108     LFDS700_MISC_BARRIER_STORE;
109
110     lfds700_misc_force_store();
111
112     util_thread_starter_start( tts, &thread_handles[0], 0, lp_first, thread_enqueuer, ts );
113     util_thread_starter_start( tts, &thread_handles[1], 1, lp, thread_dequeuer, ts+1 );
114
115     util_thread_starter_run( tts );
116
117     for( subloop = 0 ; subloop < 2 ; subloop++ )
118       test_pal_thread_wait( thread_handles[subloop] );
119
120     util_thread_starter_delete( tts );
121
122     LFDS700_MISC_BARRIER_LOAD;
123
124     lfds700_queue_bss_cleanup( &qs, NULL );
125
126     lasue = LFDS700_LIST_ASU_GET_NEXT( *lasue );
127   }
128
129   if( (ts+1)->error_flag == RAISED )
130     dvs = LFDS700_MISC_VALIDITY_INVALID_TEST_DATA;
131
132   free( thread_handles );
133
134   free( ts );
135
136   internal_display_test_result( 1, "queue_bss", dvs );
137
138   return;
139 }
140
141
142
143
144
145 /****************************************************************************/
146 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_enqueuer( void *util_thread_starter_thread_state )
147 {
148   int
149     rv;
150
151   lfds700_pal_uint_t
152     datum = 0,
153     time_loop = 0;
154
155   struct test_state
156     *ts;
157
158   struct util_thread_starter_thread_state
159     *tsts;
160
161   time_t
162     current_time,
163     start_time;
164
165   LFDS700_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
166
167   assert( util_thread_starter_thread_state != NULL );
168
169   tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
170   ts = (struct test_state *) tsts->thread_user_state;
171
172   util_thread_starter_ready_and_wait( tsts );
173
174   current_time = start_time = time( NULL );
175
176   while( current_time < start_time + 2 )
177   {
178     rv = lfds700_queue_bss_enqueue( ts->qs, NULL, (void *) datum );
179
180     if( rv == 1 )
181       if( ++datum == 4 )
182         datum = 0;
183
184     if( time_loop++ == TIME_LOOP_COUNT )
185     {
186       time_loop = 0;
187       time( &current_time );
188     }
189   }
190
191   LFDS700_MISC_BARRIER_STORE;
192
193   lfds700_misc_force_store();
194
195   return( (test_pal_thread_return_t) EXIT_SUCCESS );
196 }
197
198
199
200
201
202 /****************************************************************************/
203 static test_pal_thread_return_t TEST_PAL_CALLING_CONVENTION thread_dequeuer( void *util_thread_starter_thread_state )
204 {
205   int
206     rv;
207
208   lfds700_pal_uint_t
209     datum,
210     expected_datum = 0,
211     time_loop = 0;
212
213   struct test_state
214     *ts;
215
216   struct util_thread_starter_thread_state
217     *tsts;
218
219   time_t
220     current_time,
221     start_time;
222
223   LFDS700_MISC_BARRIER_LOAD;
224
225   assert( util_thread_starter_thread_state != NULL );
226
227   tsts = (struct util_thread_starter_thread_state *) util_thread_starter_thread_state;
228   ts = (struct test_state *) tsts->thread_user_state;
229
230   util_thread_starter_ready_and_wait( tsts );
231
232   current_time = start_time = time( NULL );
233
234   while( current_time < start_time + 2 )
235   {
236     rv = lfds700_queue_bss_dequeue( ts->qs, NULL, (void *) &datum );
237
238     if( rv == 1 )
239     {
240       if( datum != expected_datum )
241         ts->error_flag = RAISED;
242
243       if( ++expected_datum == 4 )
244         expected_datum = 0;
245     }
246
247     if( time_loop++ == TIME_LOOP_COUNT )
248     {
249       time_loop = 0;
250       time( &current_time );
251     }
252   }
253
254   LFDS700_MISC_BARRIER_STORE;
255
256   lfds700_misc_force_store();
257
258   return( (test_pal_thread_return_t) EXIT_SUCCESS );
259 }
260