1 /* 2 * Copyright (c) 2017 Richard Palethorpe <rpalethorpe (at) suse.com> 3 * 4 * This program is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 /* Basic functionality test for tst_fuzzy_sync.h similar to the atomic tests 18 * (test15.c). One thread writes to the odd indexes of an array while the 19 * other writes to the even. If the threads are not synchronised then they 20 * will probably write to the wrong indexes as they share an index variable 21 * which they should take it in turns to update. 22 */ 23 24 #include <stdlib.h> 25 #include "tst_test.h" 26 #include "tst_safe_pthread.h" 27 #include "tst_fuzzy_sync.h" 28 29 /* LOOPS * 2 + 1 must be less than INT_MAX */ 30 #define LOOPS 0xFFFFFFULL 31 32 static pthread_t thrd; 33 static volatile char seq[LOOPS * 2 + 1]; 34 static struct tst_fzsync_pair pair = TST_FZSYNC_PAIR_INIT; 35 static volatile int seq_n; 36 static volatile int iterations; 37 38 static void *worker(void *v LTP_ATTRIBUTE_UNUSED) 39 { 40 unsigned long long i; 41 42 for (i = 0; tst_fzsync_wait_update_b(&pair); i++) { 43 tst_fzsync_delay_b(&pair); 44 tst_fzsync_time_b(&pair); 45 if (!tst_fzsync_wait_b(&pair)) 46 break; 47 seq[seq_n] = 'B'; 48 seq_n = (i + 1) * 2 % (int)LOOPS * 2; 49 } 50 51 if (i > LOOPS * iterations) 52 tst_res(TWARN, "Worker performed too many iterations: %lld > %lld", 53 i, LOOPS * iterations); 54 55 return NULL; 56 } 57 58 static void setup(void) 59 { 60 SAFE_PTHREAD_CREATE(&thrd, NULL, worker, NULL); 61 } 62 63 static void run(void) 64 { 65 unsigned int i, j, fail = 0; 66 67 for (i = 0; i < LOOPS; i++) { 68 tst_fzsync_wait_update_a(&pair); 69 tst_fzsync_delay_a(&pair); 70 seq[seq_n] = 'A'; 71 seq_n = i * 2 + 1; 72 tst_fzsync_time_a(&pair); 73 if (!tst_fzsync_wait_a(&pair)) 74 break; 75 } 76 77 tst_res(TINFO, "Checking sequence..."); 78 for (i = 0; i < LOOPS; i++) { 79 j = i * 2; 80 if (seq[j] != 'A') { 81 tst_res(TFAIL, "Expected A, but found %c at %d", 82 seq[j], j); 83 fail = 1; 84 } 85 j = i * 2 + 1; 86 if (seq[j] != 'B') { 87 tst_res(TFAIL, "Expected A, but found %c at %d", 88 seq[j], j); 89 fail = 1; 90 } 91 } 92 93 if (!fail) 94 tst_res(TPASS, "Sequence is correct"); 95 96 if (labs(pair.delay) > 1000) 97 tst_res(TFAIL, "Delay is suspiciously large"); 98 99 iterations++; 100 } 101 102 static void cleanup(void) 103 { 104 tst_fzsync_pair_exit(&pair); 105 SAFE_PTHREAD_JOIN(thrd, NULL); 106 } 107 108 static struct tst_test test = { 109 .setup = setup, 110 .cleanup = cleanup, 111 .test_all = run, 112 }; 113