|
| 1 | +#include <pthread.h> |
| 2 | +#include <stdatomic.h> |
| 3 | + |
| 4 | +struct barrier_struct { |
| 5 | + atomic_int flag; |
| 6 | + int count; |
| 7 | + pthread_mutex_t lock; |
| 8 | +}; |
| 9 | + |
| 10 | +static __thread int local_sense = 0; |
| 11 | + |
| 12 | +#define BARRIER_INIT \ |
| 13 | + { \ |
| 14 | + .flag = 0, .count = 0, .lock = PTHREAD_MUTEX_INITIALIZER \ |
| 15 | + } |
| 16 | + |
| 17 | +#define DEFINE_BARRIER(name) struct barrier_struct name = BARRIER_INIT |
| 18 | + |
| 19 | +static inline void thread_barrier(struct barrier_struct *b, size_t n) |
| 20 | +{ |
| 21 | + local_sense = !local_sense; |
| 22 | + |
| 23 | + pthread_mutex_lock(&b->lock); |
| 24 | + b->count++; |
| 25 | + if (b->count == n) { |
| 26 | + pthread_mutex_unlock(&b->lock); |
| 27 | + atomic_store_explicit(&b->flag, local_sense, memory_order_release); |
| 28 | + } else { |
| 29 | + pthread_mutex_unlock(&b->lock); |
| 30 | + while (atomic_load_explicit(&b->flag, memory_order_acquire) != |
| 31 | + local_sense) |
| 32 | + ; |
| 33 | + } |
| 34 | +} |
| 35 | + |
| 36 | +#include <stdint.h> |
| 37 | +#include <stdio.h> |
| 38 | +#include <stdlib.h> |
| 39 | + |
| 40 | +#include "rcu.h" |
| 41 | + |
| 42 | +#define GP_IDX_MAX N_UPDATE_RUN + 1 |
| 43 | + |
| 44 | +static DEFINE_BARRIER(test_barrier); |
| 45 | + |
| 46 | +struct test { |
| 47 | + unsigned int count; |
| 48 | +}; |
| 49 | +static struct test __rcu *dut; |
| 50 | +static atomic_uint gp_idx; |
| 51 | +static atomic_uint prev_count; |
| 52 | +static atomic_uint grace_periods[GP_IDX_MAX]; |
| 53 | + |
| 54 | +static void *reader_func(void *argv) |
| 55 | +{ |
| 56 | + struct test *tmp; |
| 57 | + unsigned int old_prev_count; |
| 58 | + |
| 59 | + if (rcu_init()) |
| 60 | + abort(); |
| 61 | + |
| 62 | + thread_barrier(&test_barrier, N_READERS + 1); |
| 63 | + |
| 64 | + rcu_read_lock(); |
| 65 | + |
| 66 | + tmp = rcu_dereference(dut); |
| 67 | + |
| 68 | + if (tmp->count != atomic_load_explicit(&prev_count, memory_order_acquire)) { |
| 69 | + old_prev_count = atomic_exchange_explicit(&prev_count, tmp->count, |
| 70 | + memory_order_release); |
| 71 | + if (tmp->count != old_prev_count) |
| 72 | + atomic_fetch_add_explicit(&gp_idx, 1, memory_order_release); |
| 73 | + if (atomic_load_explicit(&gp_idx, memory_order_acquire) > |
| 74 | + N_UPDATE_RUN + 1) { |
| 75 | + fprintf(stderr, "grace period index (%u) is over bound (%u).\n", |
| 76 | + atomic_load_explicit(&gp_idx, memory_order_acquire), |
| 77 | + N_UPDATE_RUN); |
| 78 | + abort(); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + atomic_fetch_add_explicit( |
| 83 | + &grace_periods[atomic_load_explicit(&gp_idx, memory_order_acquire)], 1, |
| 84 | + memory_order_relaxed); |
| 85 | + |
| 86 | + rcu_read_unlock(); |
| 87 | + |
| 88 | + pthread_exit(NULL); |
| 89 | +} |
| 90 | + |
| 91 | +static void *updater_func(void *argv) |
| 92 | +{ |
| 93 | + struct test *oldp; |
| 94 | + struct test *newval; |
| 95 | + unsigned int i = 0; |
| 96 | + |
| 97 | + thread_barrier(&test_barrier, N_READERS + 1); |
| 98 | + atomic_thread_fence(memory_order_seq_cst); |
| 99 | + |
| 100 | + while (i++ < N_UPDATE_RUN) { |
| 101 | + newval = malloc(sizeof(struct test)); |
| 102 | + newval->count = i; |
| 103 | + oldp = rcu_assign_pointer(dut, newval); |
| 104 | + synchronize_rcu(); |
| 105 | + free(oldp); |
| 106 | + } |
| 107 | + |
| 108 | + pthread_exit(NULL); |
| 109 | +} |
| 110 | + |
| 111 | +int main(int argc, char *argv[]) |
| 112 | +{ |
| 113 | + pthread_t reader[N_READERS]; |
| 114 | + pthread_t updater; |
| 115 | + unsigned int i, total = 0; |
| 116 | + |
| 117 | + dut = (struct test __rcu *) malloc(sizeof(struct test)); |
| 118 | + rcu_uncheck(dut)->count = 0; |
| 119 | + |
| 120 | + for (i = 0; i < N_READERS; i++) |
| 121 | + pthread_create(&reader[i], NULL, reader_func, NULL); |
| 122 | + pthread_create(&updater, NULL, updater_func, NULL); |
| 123 | + |
| 124 | + for (i = 0; i < N_READERS; i++) |
| 125 | + pthread_join(reader[i], NULL); |
| 126 | + pthread_join(updater, NULL); |
| 127 | + |
| 128 | + free(rcu_uncheck(dut)); |
| 129 | + rcu_clean(); |
| 130 | + |
| 131 | + atomic_thread_fence(memory_order_seq_cst); |
| 132 | + |
| 133 | + printf("%u reader(s), %u update run(s), %u grace period(s)\n", N_READERS, |
| 134 | + N_UPDATE_RUN, gp_idx + 1); |
| 135 | + for (i = 0; i < gp_idx + 1; i++) { |
| 136 | + printf("[grace period #%u] %4u reader(s)\n", i, grace_periods[i]); |
| 137 | + total += grace_periods[i]; |
| 138 | + } |
| 139 | + |
| 140 | + if (total != N_READERS) |
| 141 | + fprintf(stderr, |
| 142 | + "The Sum of records in the array of grace period(s) (%u) is " |
| 143 | + "not the same with number of reader(s) (%u)\n", |
| 144 | + total, N_READERS); |
| 145 | + |
| 146 | + return 0; |
| 147 | +} |
0 commit comments