| /* |
| * Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com> |
| * |
| * This program is free software: you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation, either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| /* Basic functionality test for tst_fuzzy_sync.h similar to the atomic tests |
| * (test15.c). One thread writes to the odd indexes of an array while the |
| * other writes to the even. If the threads are not synchronised then they |
| * will probably write to the wrong indexes as they share an index variable |
| * which they should take it in turns to update. |
| */ |
| |
| #include <stdlib.h> |
| #include "tst_test.h" |
| #include "tst_safe_pthread.h" |
| #include "tst_fuzzy_sync.h" |
| |
| /* LOOPS * 2 + 1 must be less than INT_MAX */ |
| #define LOOPS 0xFFFFULL |
| |
| static volatile char seq[LOOPS * 2 + 1]; |
| static struct tst_fzsync_pair pair; |
| static volatile int seq_n; |
| static volatile char last_wins; |
| |
| static void setup(void) |
| { |
| pair.exec_loops = LOOPS; |
| tst_fzsync_pair_init(&pair); |
| } |
| |
| static void *worker(void *v LTP_ATTRIBUTE_UNUSED) |
| { |
| unsigned long long i; |
| |
| for (i = 0; tst_fzsync_run_b(&pair); i++) { |
| tst_fzsync_start_race_b(&pair); |
| usleep(1); |
| last_wins = 'B'; |
| tst_fzsync_end_race_b(&pair); |
| seq[seq_n] = 'B'; |
| seq_n = (i + 1) * 2 % (int)LOOPS * 2; |
| } |
| |
| if (i != LOOPS) { |
| tst_res(TFAIL, |
| "Worker performed wrong number of iterations: %lld != %lld", |
| i, LOOPS); |
| } |
| |
| return NULL; |
| } |
| |
| static void run(void) |
| { |
| unsigned int i, j, fail = 0, lost_race = 0; |
| |
| tst_fzsync_pair_reset(&pair, worker); |
| for (i = 0; tst_fzsync_run_a(&pair); i++) { |
| tst_fzsync_start_race_a(&pair); |
| seq[seq_n] = 'A'; |
| seq_n = i * 2 + 1; |
| last_wins = 'A'; |
| tst_fzsync_end_race_a(&pair); |
| if (last_wins == 'B') |
| lost_race++; |
| } |
| |
| tst_res(TINFO, "Checking sequence..."); |
| for (i = 0; i < LOOPS; i++) { |
| j = i * 2; |
| if (seq[j] != 'A') { |
| tst_res(TFAIL, "Expected A, but found %c at %d", |
| seq[j], j); |
| fail = 1; |
| } |
| j = i * 2 + 1; |
| if (seq[j] != 'B') { |
| tst_res(TFAIL, "Expected A, but found %c at %d", |
| seq[j], j); |
| fail = 1; |
| } |
| } |
| |
| if (!fail) |
| tst_res(TPASS, "Sequence is correct"); |
| |
| if (lost_race < 100) |
| tst_res(TFAIL, "A only lost the race %d times", lost_race); |
| else |
| tst_res(TPASS, "A lost the race %d times", lost_race); |
| } |
| |
| static void cleanup(void) |
| { |
| tst_fzsync_pair_cleanup(&pair); |
| } |
| |
| static struct tst_test test = { |
| .setup = setup, |
| .cleanup = cleanup, |
| .test_all = run, |
| }; |