bit removed = 0; bit free = 0; #define RCU_GP_CTR_BIT (1 << 7) #define RCU_GP_CTR_NEST_MASK (RCU_GP_CTR_BIT - 1) bit need_mb = 0; byte urcu_gp_ctr = 1; byte urcu_active_readers = 0; byte reader_progress[4]; proctype urcu_reader() { bit done = 0; byte tmp; byte tmp_removed; byte tmp_free; do :: 1 -> if :: need_mb == 1 -> need_mb = 0; :: else -> break; fi od; do :: 1 -> if :: reader_progress[0] < 2 -> tmp = urcu_active_readers; if :: (tmp & RCU_GP_CTR_NEST_MASK) == 0 -> urcu_active_readers = urcu_gp_ctr; :: else -> urcu_active_readers = tmp + 1; fi; reader_progress[0] = 1; :: reader_progress[1] == 0 -> tmp_removed = removed; reader_progress[1] = 1; :: reader_progress[2] == 0 -> tmp_free = free; reader_progress[2] = 1; :: ((reader_progress[0] > reader_progress[3]) && (reader_progress[3] < 2)) -> urcu_active_readers = urcu_active_readers - 1; :: else -> break; fi; atomic { tmp = 0; do :: reader_progress[tmp] == 0 -> tmp = tmp + 1; break; :: reader_progress[tmp] == 1 && tmp < 4 -> tmp = tmp + 1; :: tmp >= 4 -> done = 1; break; od; do :: tmp < 4 && reader_progress[tmp] == 0 -> tmp = tmp + 1; :: tmp < 4 && reader_progress[tmp] == 1 -> break; :: tmp >= 4 -> if :: need_mb == 1 -> need_mb = 0; :: else -> skip; fi; done = 1; break; od } if :: done == 1 -> break; :: else -> skip; fi od; do :: 1 -> if :: need_mb == 1 -> need_mb = 0; :: else -> skip; fi; assert((free == 0) || (removed == 1)); od; } proctype urcu_updater() { removed = 1; need_mb = 1; do :: need_mb == 1 -> skip; :: need_mb == 0 -> break; od; urcu_gp_ctr = urcu_gp_ctr + RCU_GP_CTR_BIT; do :: 1 -> if :: (urcu_active_readers & RCU_GP_CTR_NEST_MASK) != 0 && (urcu_active_readers & ~RCU_GP_CTR_NEST_MASK) != (urcu_gp_ctr & ~RCU_GP_CTR_NEST_MASK) -> skip; :: else -> break; fi od; need_mb = 1; do :: need_mb == 1 -> skip; :: need_mb == 0 -> break; od; urcu_gp_ctr = urcu_gp_ctr + RCU_GP_CTR_BIT; do :: 1 -> if :: (urcu_active_readers & RCU_GP_CTR_NEST_MASK) != 0 && (urcu_active_readers & ~RCU_GP_CTR_NEST_MASK) != (urcu_gp_ctr & ~RCU_GP_CTR_NEST_MASK) -> skip; :: else -> break; fi; od; free = 1; } init { atomic { reader_progress[0] = 0; reader_progress[1] = 0; reader_progress[2] = 0; reader_progress[3] = 0; run urcu_reader(); run urcu_updater(); } }