]> pd.if.org Git - liblfds/blob - liblfds/liblfds7.1.0/test_and_benchmark/libtest/src/libtest_tests/libtest_tests_queue_bounded_singleproducer_singleconsumer_enqueuing_and_dequeuing.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds7.1.0 / test_and_benchmark / libtest / src / libtest_tests / libtest_tests_queue_bounded_singleproducer_singleconsumer_enqueuing_and_dequeuing.c
1 /***** includes *****/
2 #include "libtest_tests_internal.h"
3
4 /***** structs *****/
5 struct test_per_thread_state
6 {
7   enum flag
8     error_flag;
9
10   struct lfds710_queue_bss_state
11     *qs;
12 };
13
14 /***** private prototypes *****/
15 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_enqueuer( void *libtest_threadset_per_thread_state );
16 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_dequeuer( void *libtest_threadset_per_thread_state );
17
18
19
20
21
22 /****************************************************************************/
23 void libtest_tests_queue_bss_enqueuing_and_dequeuing( struct lfds710_list_asu_state *list_of_logical_processors, struct libshared_memory_state *ms, enum lfds710_misc_validity *dvs )
24 {
25   lfds710_pal_uint_t
26     loop,
27     number_logical_processors;
28
29   struct lfds710_list_asu_element
30     *lasue;
31
32   struct lfds710_queue_bss_element
33     element_array[4];
34
35   struct lfds710_queue_bss_state
36     qs;
37
38   struct libtest_logical_processor
39     *lp,
40     *lp_first;
41
42   struct libtest_threadset_per_thread_state
43     *pts;
44
45   struct libtest_threadset_state
46     ts;
47
48   struct test_per_thread_state
49     *tpts;
50
51   LFDS710_PAL_ASSERT( list_of_logical_processors != NULL );
52   LFDS710_PAL_ASSERT( ms != NULL );
53   LFDS710_PAL_ASSERT( dvs != NULL );
54
55   /* TRD : so, this is the real test
56            problem is, because we use memory barriers only
57            and we only support one producer and one consumer
58            we need to ensure these threads are on different physical cores
59            if they're on the same core, the code would work even without memory barriers
60
61            problem is, in the test application, we only know the *number* of logical cores
62            obtaining topology information adds a great deal of complexity to the test app
63            and makes porting much harder
64
65            so, we know how many logical cores there are; my thought is to partially
66            permutate over them - we always run the producer on core 0, but we iterate
67            over the other logical cores, running the test once each time, with the
68            consumer being run on core 0, then core 1, then core 2, etc
69
70            (we run on core 0 for the single-cpu case; it's redundent, since a single
71             logical core running both producer and consumer will work, but otherwise
72             we have to skip the test, which is confusing for the user)
73
74            the test is one thread enqueuing and one thread dequeuing for two seconds
75   */
76
77   *dvs = LFDS710_MISC_VALIDITY_VALID;
78
79   // TRD : allocate
80   lfds710_list_asu_query( list_of_logical_processors, LFDS710_LIST_ASU_QUERY_GET_POTENTIALLY_INACCURATE_COUNT, NULL, (void **) &number_logical_processors );
81
82   tpts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct test_per_thread_state) * 2, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
83   pts = libshared_memory_alloc_from_unknown_node( ms, sizeof(struct libtest_threadset_per_thread_state) * 2, LFDS710_PAL_ATOMIC_ISOLATION_IN_BYTES );
84
85   for( loop = 0 ; loop < 2 ; loop++ )
86   {
87     (tpts+loop)->qs = &qs;
88     (tpts+loop)->error_flag = LOWERED;
89   }
90
91   /* TRD : producer always on core 0
92            iterate over the other cores with consumer
93   */
94   
95   lasue = LFDS710_LIST_ASU_GET_START( *list_of_logical_processors );
96   lp_first = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
97
98   while( lasue != NULL )
99   {
100     lp = LFDS710_LIST_ASU_GET_VALUE_FROM_ELEMENT( *lasue );
101
102     lfds710_queue_bss_init_valid_on_current_logical_core( &qs, element_array, 4, NULL );
103
104     libtest_threadset_init( &ts, NULL );
105
106     LFDS710_MISC_BARRIER_STORE;
107     lfds710_misc_force_store();
108
109     libtest_threadset_add_thread( &ts, &pts[0], lp_first, thread_enqueuer, &tpts[0] );
110     libtest_threadset_add_thread( &ts, &pts[1], lp, thread_dequeuer, &tpts[1] );
111
112     libtest_threadset_run( &ts );
113     libtest_threadset_cleanup( &ts );
114
115     LFDS710_MISC_BARRIER_LOAD;
116
117     lfds710_queue_bss_cleanup( &qs, NULL );
118
119     lasue = LFDS710_LIST_ASU_GET_NEXT( *lasue );
120   }
121
122   if( (tpts+1)->error_flag == RAISED )
123     *dvs = LFDS710_MISC_VALIDITY_INVALID_TEST_DATA;
124
125   return;
126 }
127
128
129
130
131
132 /****************************************************************************/
133 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_enqueuer( void *libtest_threadset_per_thread_state )
134 {
135   int
136     rv;
137
138   lfds710_pal_uint_t
139     datum = 0,
140     time_loop = 0;
141
142   struct libtest_threadset_per_thread_state
143     *pts;
144
145   struct test_per_thread_state
146     *tpts;
147
148   time_t
149     current_time,
150     start_time;
151
152   LFDS710_MISC_MAKE_VALID_ON_CURRENT_LOGICAL_CORE_INITS_COMPLETED_BEFORE_NOW_ON_ANY_OTHER_LOGICAL_CORE;
153
154   LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
155
156   pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
157   tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
158
159   libtest_threadset_thread_ready_and_wait( pts );
160
161   current_time = start_time = time( NULL );
162
163   while( current_time < start_time + 2 )
164   {
165     rv = lfds710_queue_bss_enqueue( tpts->qs, NULL, (void *) datum );
166
167     if( rv == 1 )
168       if( ++datum == 4 )
169         datum = 0;
170
171     if( time_loop++ == TIME_LOOP_COUNT )
172     {
173       time_loop = 0;
174       time( &current_time );
175     }
176   }
177
178   LFDS710_MISC_BARRIER_STORE;
179
180   lfds710_misc_force_store();
181
182   return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
183 }
184
185
186
187
188
189 /****************************************************************************/
190 static libshared_pal_thread_return_t LIBSHARED_PAL_THREAD_CALLING_CONVENTION thread_dequeuer( void *libtest_threadset_per_thread_state )
191 {
192   int
193     rv;
194
195   lfds710_pal_uint_t
196     datum,
197     expected_datum = 0,
198     time_loop = 0;
199
200   struct libtest_threadset_per_thread_state
201     *pts;
202
203   struct test_per_thread_state
204     *tpts;
205
206   time_t
207     current_time,
208     start_time;
209
210   LFDS710_MISC_BARRIER_LOAD;
211
212   LFDS710_PAL_ASSERT( libtest_threadset_per_thread_state != NULL );
213
214   pts = (struct libtest_threadset_per_thread_state *) libtest_threadset_per_thread_state;
215   tpts = LIBTEST_THREADSET_GET_USER_STATE_FROM_PER_THREAD_STATE( *pts );
216
217   libtest_threadset_thread_ready_and_wait( pts );
218
219   current_time = start_time = time( NULL );
220
221   while( current_time < start_time + 2 )
222   {
223     rv = lfds710_queue_bss_dequeue( tpts->qs, NULL, (void *) &datum );
224
225     if( rv == 1 )
226     {
227       if( datum != expected_datum )
228         tpts->error_flag = RAISED;
229
230       if( ++expected_datum == 4 )
231         expected_datum = 0;
232     }
233
234     if( time_loop++ == TIME_LOOP_COUNT )
235     {
236       time_loop = 0;
237       time( &current_time );
238     }
239   }
240
241   LFDS710_MISC_BARRIER_STORE;
242
243   lfds710_misc_force_store();
244
245   return LIBSHARED_PAL_THREAD_RETURN_CAST(RETURN_SUCCESS);
246 }
247