X-Git-Url: http://git.liburcu.org/?a=blobdiff_plain;f=formal-model%2Furcu%2Furcu.spin;h=f4d3ea78ade593788bf9d97710e7c8bda5ace2ff;hb=a570e118a8f9ed38d5eaebf8d21b65d2b6f5cf40;hp=e9271f82bb58e3acdef1db13aa7226e011d48200;hpb=89674313b5ff1209dc090e3b2c48680d222e81cd;p=urcu.git diff --git a/formal-model/urcu/urcu.spin b/formal-model/urcu/urcu.spin index e9271f8..f4d3ea7 100644 --- a/formal-model/urcu/urcu.spin +++ b/formal-model/urcu/urcu.spin @@ -80,6 +80,68 @@ :: 1 -> skip \ fi; +/* + * Remote barriers tests the scheme where a signal (or IPI) is sent to all + * reader threads to promote their compiler barrier to a smp_mb(). + */ +#ifdef REMOTE_BARRIERS + +inline smp_rmb_pid(i) +{ + atomic { + CACHE_READ_FROM_MEM(urcu_gp_ctr, i); + CACHE_READ_FROM_MEM(urcu_active_readers_one, i); + CACHE_READ_FROM_MEM(generation_ptr, i); + } +} + +inline smp_wmb_pid(i) +{ + atomic { + CACHE_WRITE_TO_MEM(urcu_gp_ctr, i); + CACHE_WRITE_TO_MEM(urcu_active_readers_one, i); + CACHE_WRITE_TO_MEM(generation_ptr, i); + } +} + +inline smp_mb_pid(i) +{ + atomic { +#ifndef NO_WMB + smp_wmb_pid(i); +#endif +#ifndef NO_RMB + smp_rmb_pid(i); +#endif + skip; + } +} + +/* + * Readers do a simple barrier(), writers are doing a smp_mb() _and_ sending a + * signal or IPI to have all readers execute a smp_mb. + * We are not modeling the whole rendez-vous between readers and writers here, + * we just let the writer update each reader's caches remotely. + */ +inline smp_mb(i) +{ + if + :: get_pid() >= NR_READERS -> + smp_mb_pid(get_pid()); + i = 0; + do + :: i < NR_READERS -> + smp_mb_pid(i); + i++; + :: i >= NR_READERS -> break + od; + smp_mb_pid(get_pid()); + :: else -> skip; + fi; +} + +#else + inline smp_rmb(i) { atomic { @@ -111,6 +173,8 @@ inline smp_mb(i) } } +#endif + /* Keep in sync manually with smp_rmb, wmp_wmb and ooo_mem */ DECLARE_CACHED_VAR(byte, urcu_gp_ctr, 1); /* Note ! currently only one reader */ @@ -148,6 +212,7 @@ inline wait_for_reader(tmp, id, i) :: 1 -> ooo_mem(i); tmp = READ_CACHED_VAR(urcu_active_readers_one); + ooo_mem(i); if :: (tmp & RCU_GP_CTR_NEST_MASK) && ((tmp ^ READ_CACHED_VAR(urcu_gp_ctr)) @@ -176,26 +241,11 @@ inline wait_for_quiescent_state(tmp, i, j) /* Model the RCU read-side critical section. */ -active [NR_READERS] proctype urcu_reader() +inline urcu_one_read(i, nest_i, tmp, tmp2) { - byte i; - byte tmp, tmp2; - - assert(get_pid() < NR_PROCS); - -end_reader: + nest_i = 0; do - :: 1 -> - /* - * We do not test reader's progress here, because we are mainly - * interested in writer's progress. The reader never blocks - * anyway. We have to test for reader/writer's progress - * separately, otherwise we could think the writer is doing - * progress when it's blocked by an always progressing reader. - */ -#ifdef READER_PROGRESS -progress_reader: -#endif + :: nest_i < READER_NEST_LEVEL -> ooo_mem(i); tmp = READ_CACHED_VAR(urcu_active_readers_one); ooo_mem(i); @@ -206,27 +256,61 @@ progress_reader: ooo_mem(i); WRITE_CACHED_VAR(urcu_active_readers_one, tmp2); :: else -> - WRITE_CACHED_VAR(urcu_active_readers_one, tmp + 1); + WRITE_CACHED_VAR(urcu_active_readers_one, + tmp + 1); fi; ooo_mem(i); smp_mb(i); - read_generation = READ_CACHED_VAR(generation_ptr); - ooo_mem(i); - data_access = 1; - ooo_mem(i); - data_access = 0; + nest_i++; + :: nest_i >= READER_NEST_LEVEL -> break; + od; + + ooo_mem(i); + read_generation = READ_CACHED_VAR(generation_ptr); + ooo_mem(i); + data_access = 1; + ooo_mem(i); + data_access = 0; + + nest_i = 0; + do + :: nest_i < READER_NEST_LEVEL -> ooo_mem(i); smp_mb(i); ooo_mem(i); tmp2 = READ_CACHED_VAR(urcu_active_readers_one); ooo_mem(i); WRITE_CACHED_VAR(urcu_active_readers_one, tmp2 - 1); - ooo_mem(i); - //wakeup_all(i); - //smp_mc(i); /* added */ + nest_i++; + :: nest_i >= READER_NEST_LEVEL -> break; od; + ooo_mem(i); + //smp_mc(i); /* added */ } +active [NR_READERS] proctype urcu_reader() +{ + byte i, nest_i; + byte tmp, tmp2; + + assert(get_pid() < NR_PROCS); + +end_reader: + do + :: 1 -> + /* + * We do not test reader's progress here, because we are mainly + * interested in writer's progress. The reader never blocks + * anyway. We have to test for reader/writer's progress + * separately, otherwise we could think the writer is doing + * progress when it's blocked by an always progressing reader. + */ +#ifdef READER_PROGRESS +progress_reader: +#endif + urcu_one_read(i, nest_i, tmp, tmp2); + od; +} /* Model the RCU update process. */ @@ -271,7 +355,7 @@ progress_writer1: //smp_mc(i); wait_for_quiescent_state(tmp, i, j); //smp_mc(i); - #ifndef SINGLE_FLIP +#ifndef SINGLE_FLIP ooo_mem(i); tmp = READ_CACHED_VAR(urcu_gp_ctr); ooo_mem(i); @@ -279,7 +363,7 @@ progress_writer1: //smp_mc(i); ooo_mem(i); wait_for_quiescent_state(tmp, i, j); - #endif +#endif ooo_mem(i); smp_mb(i); ooo_mem(i);