diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-20 14:21:17 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-02-20 14:21:17 -0500 |
commit | f7458a5d631df2ecdbfe4a606053aba19913cc41 (patch) | |
tree | 26df2860fe3a750ed3b0359178d2b4c4fe8798d2 /tools | |
parent | 575260e3f8f8ac72dc0c41a4a20190d1a5f2b887 (diff) | |
parent | a8709fa4a06d4af5f86e3660839531cbe0f2a19b (diff) |
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU updates from Ingo Molnar:
"The RCU changes in this cycle are:
- Dynticks updates, consolidating open-coded counter accesses into a
well-defined API
- SRCU updates: Simplify algorithm, add formal verification
- Documentation updates
- Miscellaneous fixes
- Torture-test updates
Most of the diffstat comes from the relatively large documentation
update"
* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (42 commits)
srcu: Reduce probability of SRCU ->unlock_count[] counter overflow
rcutorture: Add CBMC-based formal verification for SRCU
srcu: Force full grace-period ordering
srcu: Implement more-efficient reader counts
rcu: Adjust FQS offline checks for exact online-CPU detection
rcu: Check cond_resched_rcu_qs() state less often to reduce GP overhead
rcu: Abstract extended quiescent state determination
rcu: Abstract dynticks extended quiescent state enter/exit operations
rcu: Add lockdep checks to synchronous expedited primitives
rcu: Eliminate unused expedited_normal counter
llist: Clarify comments about when locking is needed
rcu: Fix comment in rcu_organize_nocb_kthreads()
rcu: Enable RCU tracepoints by default to aid in debugging
rcu: Make rcu_cpu_starting() use its "cpu" argument
rcu: Add comment headers to expedited-grace-period counter functions
rcu: Don't wake rcuc/X kthreads on NOCB CPUs
rcu: Re-enable TASKS_RCU for User Mode Linux
rcu: Once again use NMI-based stack traces in stall warnings
rcu: Remove short-term CPU kicking
rcu: Add long-term CPU kicking
...
Diffstat (limited to 'tools')
52 files changed, 1641 insertions, 8 deletions
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon index f824b4c9d9d9..d2d2a86139db 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/CFcommon +++ b/tools/testing/selftests/rcutorture/configs/rcu/CFcommon | |||
@@ -1,5 +1,2 @@ | |||
1 | CONFIG_RCU_TORTURE_TEST=y | 1 | CONFIG_RCU_TORTURE_TEST=y |
2 | CONFIG_PRINTK_TIME=y | 2 | CONFIG_PRINTK_TIME=y |
3 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
4 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
5 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY01 b/tools/testing/selftests/rcutorture/configs/rcu/TINY01 index 0a63e073a00c..6db705e55487 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TINY01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY01 | |||
@@ -7,6 +7,7 @@ CONFIG_HZ_PERIODIC=n | |||
7 | CONFIG_NO_HZ_IDLE=y | 7 | CONFIG_NO_HZ_IDLE=y |
8 | CONFIG_NO_HZ_FULL=n | 8 | CONFIG_NO_HZ_FULL=n |
9 | CONFIG_RCU_TRACE=n | 9 | CONFIG_RCU_TRACE=n |
10 | #CHECK#CONFIG_RCU_STALL_COMMON=n | ||
10 | CONFIG_DEBUG_LOCK_ALLOC=n | 11 | CONFIG_DEBUG_LOCK_ALLOC=n |
11 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 12 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
12 | CONFIG_PREEMPT_COUNT=n | 13 | CONFIG_PREEMPT_COUNT=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02 index f1892e0371c9..a59f7686e219 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02 | |||
@@ -8,7 +8,8 @@ CONFIG_NO_HZ_IDLE=n | |||
8 | CONFIG_NO_HZ_FULL=n | 8 | CONFIG_NO_HZ_FULL=n |
9 | CONFIG_RCU_TRACE=y | 9 | CONFIG_RCU_TRACE=y |
10 | CONFIG_PROVE_LOCKING=y | 10 | CONFIG_PROVE_LOCKING=y |
11 | CONFIG_PROVE_RCU_REPEATEDLY=y | ||
11 | #CHECK#CONFIG_PROVE_RCU=y | 12 | #CHECK#CONFIG_PROVE_RCU=y |
12 | CONFIG_DEBUG_LOCK_ALLOC=y | 13 | CONFIG_DEBUG_LOCK_ALLOC=y |
13 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 14 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y |
14 | CONFIG_PREEMPT_COUNT=y | 15 | CONFIG_PREEMPT_COUNT=y |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index f572b873c620..359cb258f639 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 | |||
@@ -16,3 +16,6 @@ CONFIG_DEBUG_LOCK_ALLOC=n | |||
16 | CONFIG_RCU_BOOST=n | 16 | CONFIG_RCU_BOOST=n |
17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 17 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
18 | CONFIG_RCU_EXPERT=y | 18 | CONFIG_RCU_EXPERT=y |
19 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
20 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
21 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index ef6a22c44dea..c1ab5926568b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 | |||
@@ -20,3 +20,7 @@ CONFIG_PROVE_LOCKING=n | |||
20 | CONFIG_RCU_BOOST=n | 20 | CONFIG_RCU_BOOST=n |
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
22 | CONFIG_RCU_EXPERT=y | 22 | CONFIG_RCU_EXPERT=y |
23 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
25 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
26 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index 7a17c503b382..3b93ee544e70 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 | |||
@@ -17,3 +17,6 @@ CONFIG_RCU_BOOST=y | |||
17 | CONFIG_RCU_KTHREAD_PRIO=2 | 17 | CONFIG_RCU_KTHREAD_PRIO=2 |
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
19 | CONFIG_RCU_EXPERT=y | 19 | CONFIG_RCU_EXPERT=y |
20 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
21 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
22 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 17cbe098b115..5af758e783c7 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 | |||
@@ -19,3 +19,7 @@ CONFIG_RCU_NOCB_CPU=n | |||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 19 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 21 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
25 | CONFIG_RCU_EQS_DEBUG=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 index 1257d3227b1e..d4cdc0d74e16 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 | |||
@@ -19,3 +19,6 @@ CONFIG_PROVE_LOCKING=y | |||
19 | #CHECK#CONFIG_PROVE_RCU=y | 19 | #CHECK#CONFIG_PROVE_RCU=y |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 21 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 index d3e456b74cbe..4cb02bd28f08 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 | |||
@@ -20,3 +20,6 @@ CONFIG_PROVE_LOCKING=y | |||
20 | #CHECK#CONFIG_PROVE_RCU=y | 20 | #CHECK#CONFIG_PROVE_RCU=y |
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y | 21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=y |
22 | CONFIG_RCU_EXPERT=y | 22 | CONFIG_RCU_EXPERT=y |
23 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
25 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index 3956b4131f72..b12a3ea1867e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 | |||
@@ -19,3 +19,6 @@ CONFIG_RCU_NOCB_CPU=n | |||
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 19 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
21 | CONFIG_RCU_EXPERT=y | 21 | CONFIG_RCU_EXPERT=y |
22 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP=y | ||
23 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT=y | ||
24 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index bb9b0c1a23c2..099cc63c6a3b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 | |||
@@ -17,8 +17,8 @@ CONFIG_RCU_FANOUT_LEAF=2 | |||
17 | CONFIG_RCU_NOCB_CPU=y | 17 | CONFIG_RCU_NOCB_CPU=y |
18 | CONFIG_RCU_NOCB_CPU_ALL=y | 18 | CONFIG_RCU_NOCB_CPU_ALL=y |
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 19 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_PROVE_LOCKING=y | 20 | CONFIG_PROVE_LOCKING=n |
21 | #CHECK#CONFIG_PROVE_RCU=y | ||
22 | CONFIG_RCU_BOOST=n | 21 | CONFIG_RCU_BOOST=n |
23 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 22 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
24 | CONFIG_RCU_EXPERT=y | 23 | CONFIG_RCU_EXPERT=y |
24 | CONFIG_RCU_EQS_DEBUG=y | ||
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index 4e2b1893d40d..364801b1a230 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt | |||
@@ -14,6 +14,7 @@ CONFIG_NO_HZ_FULL_SYSIDLE -- Do one. | |||
14 | CONFIG_PREEMPT -- Do half. (First three and #8.) | 14 | CONFIG_PREEMPT -- Do half. (First three and #8.) |
15 | CONFIG_PROVE_LOCKING -- Do several, covering CONFIG_DEBUG_LOCK_ALLOC=y and not. | 15 | CONFIG_PROVE_LOCKING -- Do several, covering CONFIG_DEBUG_LOCK_ALLOC=y and not. |
16 | CONFIG_PROVE_RCU -- Hardwired to CONFIG_PROVE_LOCKING. | 16 | CONFIG_PROVE_RCU -- Hardwired to CONFIG_PROVE_LOCKING. |
17 | CONFIG_PROVE_RCU_REPEATEDLY -- Do one. | ||
17 | CONFIG_RCU_BOOST -- one of PREEMPT_RCU. | 18 | CONFIG_RCU_BOOST -- one of PREEMPT_RCU. |
18 | CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. | 19 | CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing. |
19 | CONFIG_RCU_FANOUT -- Cover hierarchy, but overlap with others. | 20 | CONFIG_RCU_FANOUT -- Cover hierarchy, but overlap with others. |
@@ -25,7 +26,12 @@ CONFIG_RCU_NOCB_CPU_NONE -- Do one. | |||
25 | CONFIG_RCU_NOCB_CPU_ZERO -- Do one. | 26 | CONFIG_RCU_NOCB_CPU_ZERO -- Do one. |
26 | CONFIG_RCU_TRACE -- Do half. | 27 | CONFIG_RCU_TRACE -- Do half. |
27 | CONFIG_SMP -- Need one !SMP for PREEMPT_RCU. | 28 | CONFIG_SMP -- Need one !SMP for PREEMPT_RCU. |
28 | !RCU_EXPERT -- Do a few, but these have to be vanilla configurations. | 29 | CONFIG_RCU_EXPERT=n -- Do a few, but these have to be vanilla configurations. |
30 | CONFIG_RCU_EQS_DEBUG -- Do at least one for CONFIG_NO_HZ_FULL and not. | ||
31 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP -- Do for all but a couple TREE scenarios. | ||
32 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT -- Do for all but a couple TREE scenarios. | ||
33 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT -- Do for all but a couple TREE scenarios. | ||
34 | |||
29 | RCU-bh: Do one with PREEMPT and one with !PREEMPT. | 35 | RCU-bh: Do one with PREEMPT and one with !PREEMPT. |
30 | RCU-sched: Do one with PREEMPT but not BOOST. | 36 | RCU-sched: Do one with PREEMPT but not BOOST. |
31 | 37 | ||
@@ -72,7 +78,30 @@ CONFIG_RCU_TORTURE_TEST_RUNNABLE | |||
72 | 78 | ||
73 | Always used in KVM testing. | 79 | Always used in KVM testing. |
74 | 80 | ||
81 | CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT_DELAY | ||
82 | CONFIG_RCU_TORTURE_TEST_SLOW_INIT_DELAY | ||
83 | CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP_DELAY | ||
84 | |||
85 | Inspection suffices, ignore. | ||
86 | |||
75 | CONFIG_PREEMPT_RCU | 87 | CONFIG_PREEMPT_RCU |
76 | CONFIG_TREE_RCU | 88 | CONFIG_TREE_RCU |
89 | CONFIG_TINY_RCU | ||
90 | |||
91 | These are controlled by CONFIG_PREEMPT and/or CONFIG_SMP. | ||
92 | |||
93 | CONFIG_SPARSE_RCU_POINTER | ||
94 | |||
95 | Makes sense only for sparse runs, not for kernel builds. | ||
96 | |||
97 | CONFIG_SRCU | ||
98 | CONFIG_TASKS_RCU | ||
99 | |||
100 | Selected by CONFIG_RCU_TORTURE_TEST, so cannot disable. | ||
101 | |||
102 | CONFIG_RCU_TRACE | ||
103 | |||
104 | Implied by CONFIG_RCU_TRACE for Tree RCU. | ||
105 | |||
77 | 106 | ||
78 | These are controlled by CONFIG_PREEMPT. | 107 | boot parameters ignored: TBD |
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore new file mode 100644 index 000000000000..712a3d41a325 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/.gitignore | |||
@@ -0,0 +1 @@ | |||
srcu.c | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile new file mode 100644 index 000000000000..16b01559fa55 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | all: srcu.c store_buffering | ||
2 | |||
3 | LINUX_SOURCE = ../../../../../.. | ||
4 | |||
5 | modified_srcu_input = $(LINUX_SOURCE)/include/linux/srcu.h \ | ||
6 | $(LINUX_SOURCE)/kernel/rcu/srcu.c | ||
7 | |||
8 | modified_srcu_output = include/linux/srcu.h srcu.c | ||
9 | |||
10 | include/linux/srcu.h: srcu.c | ||
11 | |||
12 | srcu.c: modify_srcu.awk Makefile $(modified_srcu_input) | ||
13 | awk -f modify_srcu.awk $(modified_srcu_input) $(modified_srcu_output) | ||
14 | |||
15 | store_buffering: | ||
16 | @cd tests/store_buffering; make | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/delay.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/export.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/mutex.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/percpu.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/preempt.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/rcupdate.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/sched.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/smp.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/linux/workqueue.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/empty_includes/uapi/linux/types.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/.gitignore b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/.gitignore new file mode 100644 index 000000000000..1d016e66980a --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/.gitignore | |||
@@ -0,0 +1 @@ | |||
srcu.h | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h new file mode 100644 index 000000000000..f2860dd1b407 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/kconfig.h | |||
@@ -0,0 +1 @@ | |||
#include <LINUX_SOURCE/linux/kconfig.h> | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h new file mode 100644 index 000000000000..4a3d538fef12 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/include/linux/types.h | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * This header has been modifies to remove definitions of types that | ||
3 | * are defined in standard userspace headers or are problematic for some | ||
4 | * other reason. | ||
5 | */ | ||
6 | |||
7 | #ifndef _LINUX_TYPES_H | ||
8 | #define _LINUX_TYPES_H | ||
9 | |||
10 | #define __EXPORTED_HEADERS__ | ||
11 | #include <uapi/linux/types.h> | ||
12 | |||
13 | #ifndef __ASSEMBLY__ | ||
14 | |||
15 | #define DECLARE_BITMAP(name, bits) \ | ||
16 | unsigned long name[BITS_TO_LONGS(bits)] | ||
17 | |||
18 | typedef __u32 __kernel_dev_t; | ||
19 | |||
20 | /* bsd */ | ||
21 | typedef unsigned char u_char; | ||
22 | typedef unsigned short u_short; | ||
23 | typedef unsigned int u_int; | ||
24 | typedef unsigned long u_long; | ||
25 | |||
26 | /* sysv */ | ||
27 | typedef unsigned char unchar; | ||
28 | typedef unsigned short ushort; | ||
29 | typedef unsigned int uint; | ||
30 | typedef unsigned long ulong; | ||
31 | |||
32 | #ifndef __BIT_TYPES_DEFINED__ | ||
33 | #define __BIT_TYPES_DEFINED__ | ||
34 | |||
35 | typedef __u8 u_int8_t; | ||
36 | typedef __s8 int8_t; | ||
37 | typedef __u16 u_int16_t; | ||
38 | typedef __s16 int16_t; | ||
39 | typedef __u32 u_int32_t; | ||
40 | typedef __s32 int32_t; | ||
41 | |||
42 | #endif /* !(__BIT_TYPES_DEFINED__) */ | ||
43 | |||
44 | typedef __u8 uint8_t; | ||
45 | typedef __u16 uint16_t; | ||
46 | typedef __u32 uint32_t; | ||
47 | |||
48 | /* this is a special 64bit data type that is 8-byte aligned */ | ||
49 | #define aligned_u64 __u64 __attribute__((aligned(8))) | ||
50 | #define aligned_be64 __be64 __attribute__((aligned(8))) | ||
51 | #define aligned_le64 __le64 __attribute__((aligned(8))) | ||
52 | |||
53 | /** | ||
54 | * The type used for indexing onto a disc or disc partition. | ||
55 | * | ||
56 | * Linux always considers sectors to be 512 bytes long independently | ||
57 | * of the devices real block size. | ||
58 | * | ||
59 | * blkcnt_t is the type of the inode's block count. | ||
60 | */ | ||
61 | #ifdef CONFIG_LBDAF | ||
62 | typedef u64 sector_t; | ||
63 | #else | ||
64 | typedef unsigned long sector_t; | ||
65 | #endif | ||
66 | |||
67 | /* | ||
68 | * The type of an index into the pagecache. | ||
69 | */ | ||
70 | #define pgoff_t unsigned long | ||
71 | |||
72 | /* | ||
73 | * A dma_addr_t can hold any valid DMA address, i.e., any address returned | ||
74 | * by the DMA API. | ||
75 | * | ||
76 | * If the DMA API only uses 32-bit addresses, dma_addr_t need only be 32 | ||
77 | * bits wide. Bus addresses, e.g., PCI BARs, may be wider than 32 bits, | ||
78 | * but drivers do memory-mapped I/O to ioremapped kernel virtual addresses, | ||
79 | * so they don't care about the size of the actual bus addresses. | ||
80 | */ | ||
81 | #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT | ||
82 | typedef u64 dma_addr_t; | ||
83 | #else | ||
84 | typedef u32 dma_addr_t; | ||
85 | #endif | ||
86 | |||
87 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | ||
88 | typedef u64 phys_addr_t; | ||
89 | #else | ||
90 | typedef u32 phys_addr_t; | ||
91 | #endif | ||
92 | |||
93 | typedef phys_addr_t resource_size_t; | ||
94 | |||
95 | /* | ||
96 | * This type is the placeholder for a hardware interrupt number. It has to be | ||
97 | * big enough to enclose whatever representation is used by a given platform. | ||
98 | */ | ||
99 | typedef unsigned long irq_hw_number_t; | ||
100 | |||
101 | typedef struct { | ||
102 | int counter; | ||
103 | } atomic_t; | ||
104 | |||
105 | #ifdef CONFIG_64BIT | ||
106 | typedef struct { | ||
107 | long counter; | ||
108 | } atomic64_t; | ||
109 | #endif | ||
110 | |||
111 | struct list_head { | ||
112 | struct list_head *next, *prev; | ||
113 | }; | ||
114 | |||
115 | struct hlist_head { | ||
116 | struct hlist_node *first; | ||
117 | }; | ||
118 | |||
119 | struct hlist_node { | ||
120 | struct hlist_node *next, **pprev; | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * struct callback_head - callback structure for use with RCU and task_work | ||
125 | * @next: next update requests in a list | ||
126 | * @func: actual update function to call after the grace period. | ||
127 | * | ||
128 | * The struct is aligned to size of pointer. On most architectures it happens | ||
129 | * naturally due ABI requirements, but some architectures (like CRIS) have | ||
130 | * weird ABI and we need to ask it explicitly. | ||
131 | * | ||
132 | * The alignment is required to guarantee that bits 0 and 1 of @next will be | ||
133 | * clear under normal conditions -- as long as we use call_rcu(), | ||
134 | * call_rcu_bh(), call_rcu_sched(), or call_srcu() to queue callback. | ||
135 | * | ||
136 | * This guarantee is important for few reasons: | ||
137 | * - future call_rcu_lazy() will make use of lower bits in the pointer; | ||
138 | * - the structure shares storage spacer in struct page with @compound_head, | ||
139 | * which encode PageTail() in bit 0. The guarantee is needed to avoid | ||
140 | * false-positive PageTail(). | ||
141 | */ | ||
142 | struct callback_head { | ||
143 | struct callback_head *next; | ||
144 | void (*func)(struct callback_head *head); | ||
145 | } __attribute__((aligned(sizeof(void *)))); | ||
146 | #define rcu_head callback_head | ||
147 | |||
148 | typedef void (*rcu_callback_t)(struct rcu_head *head); | ||
149 | typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func); | ||
150 | |||
151 | /* clocksource cycle base type */ | ||
152 | typedef u64 cycle_t; | ||
153 | |||
154 | #endif /* __ASSEMBLY__ */ | ||
155 | #endif /* _LINUX_TYPES_H */ | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk new file mode 100755 index 000000000000..8ff89043d0a9 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/modify_srcu.awk | |||
@@ -0,0 +1,375 @@ | |||
1 | #!/bin/awk -f | ||
2 | |||
3 | # Modify SRCU for formal verification. The first argument should be srcu.h and | ||
4 | # the second should be srcu.c. Outputs modified srcu.h and srcu.c into the | ||
5 | # current directory. | ||
6 | |||
7 | BEGIN { | ||
8 | if (ARGC != 5) { | ||
9 | print "Usange: input.h input.c output.h output.c" > "/dev/stderr"; | ||
10 | exit 1; | ||
11 | } | ||
12 | h_output = ARGV[3]; | ||
13 | c_output = ARGV[4]; | ||
14 | ARGC = 3; | ||
15 | |||
16 | # Tokenize using FS and not RS as FS supports regular expressions. Each | ||
17 | # record is one line of source, except that backslashed lines are | ||
18 | # combined. Comments are treated as field separators, as are quotes. | ||
19 | quote_regexp="\"([^\\\\\"]|\\\\.)*\""; | ||
20 | comment_regexp="\\/\\*([^*]|\\*+[^*/])*\\*\\/|\\/\\/.*(\n|$)"; | ||
21 | FS="([ \\\\\t\n\v\f;,.=(){}+*/<>&|^-]|\\[|\\]|" comment_regexp "|" quote_regexp ")+"; | ||
22 | |||
23 | inside_srcu_struct = 0; | ||
24 | inside_srcu_init_def = 0; | ||
25 | srcu_init_param_name = ""; | ||
26 | in_macro = 0; | ||
27 | brace_nesting = 0; | ||
28 | paren_nesting = 0; | ||
29 | |||
30 | # Allow the manipulation of the last field separator after has been | ||
31 | # seen. | ||
32 | last_fs = ""; | ||
33 | # Whether the last field separator was intended to be output. | ||
34 | last_fs_print = 0; | ||
35 | |||
36 | # rcu_batches stores the initialization for each instance of struct | ||
37 | # rcu_batch | ||
38 | |||
39 | in_comment = 0; | ||
40 | |||
41 | outputfile = ""; | ||
42 | } | ||
43 | |||
44 | { | ||
45 | prev_outputfile = outputfile; | ||
46 | if (FILENAME ~ /\.h$/) { | ||
47 | outputfile = h_output; | ||
48 | if (FNR != NR) { | ||
49 | print "Incorrect file order" > "/dev/stderr"; | ||
50 | exit 1; | ||
51 | } | ||
52 | } | ||
53 | else | ||
54 | outputfile = c_output; | ||
55 | |||
56 | if (prev_outputfile && outputfile != prev_outputfile) { | ||
57 | new_outputfile = outputfile; | ||
58 | outputfile = prev_outputfile; | ||
59 | update_fieldsep("", 0); | ||
60 | outputfile = new_outputfile; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | # Combine the next line into $0. | ||
65 | function combine_line() { | ||
66 | ret = getline next_line; | ||
67 | if (ret == 0) { | ||
68 | # Don't allow two consecutive getlines at the end of the file | ||
69 | if (eof_found) { | ||
70 | print "Error: expected more input." > "/dev/stderr"; | ||
71 | exit 1; | ||
72 | } else { | ||
73 | eof_found = 1; | ||
74 | } | ||
75 | } else if (ret == -1) { | ||
76 | print "Error reading next line of file" FILENAME > "/dev/stderr"; | ||
77 | exit 1; | ||
78 | } | ||
79 | $0 = $0 "\n" next_line; | ||
80 | } | ||
81 | |||
82 | # Combine backslashed lines and multiline comments. | ||
83 | function combine_backslashes() { | ||
84 | while (/\\$|\/\*([^*]|\*+[^*\/])*\**$/) { | ||
85 | combine_line(); | ||
86 | } | ||
87 | } | ||
88 | |||
89 | function read_line() { | ||
90 | combine_line(); | ||
91 | combine_backslashes(); | ||
92 | } | ||
93 | |||
94 | # Print out field separators and update variables that depend on them. Only | ||
95 | # print if p is true. Call with sep="" and p=0 to print out the last field | ||
96 | # separator. | ||
97 | function update_fieldsep(sep, p) { | ||
98 | # Count braces | ||
99 | sep_tmp = sep; | ||
100 | gsub(quote_regexp "|" comment_regexp, "", sep_tmp); | ||
101 | while (1) | ||
102 | { | ||
103 | if (sub("[^{}()]*\\{", "", sep_tmp)) { | ||
104 | brace_nesting++; | ||
105 | continue; | ||
106 | } | ||
107 | if (sub("[^{}()]*\\}", "", sep_tmp)) { | ||
108 | brace_nesting--; | ||
109 | if (brace_nesting < 0) { | ||
110 | print "Unbalanced braces!" > "/dev/stderr"; | ||
111 | exit 1; | ||
112 | } | ||
113 | continue; | ||
114 | } | ||
115 | if (sub("[^{}()]*\\(", "", sep_tmp)) { | ||
116 | paren_nesting++; | ||
117 | continue; | ||
118 | } | ||
119 | if (sub("[^{}()]*\\)", "", sep_tmp)) { | ||
120 | paren_nesting--; | ||
121 | if (paren_nesting < 0) { | ||
122 | print "Unbalanced parenthesis!" > "/dev/stderr"; | ||
123 | exit 1; | ||
124 | } | ||
125 | continue; | ||
126 | } | ||
127 | |||
128 | break; | ||
129 | } | ||
130 | |||
131 | if (last_fs_print) | ||
132 | printf("%s", last_fs) > outputfile; | ||
133 | last_fs = sep; | ||
134 | last_fs_print = p; | ||
135 | } | ||
136 | |||
137 | # Shifts the fields down by n positions. Calls next if there are no more. If p | ||
138 | # is true then print out field separators. | ||
139 | function shift_fields(n, p) { | ||
140 | do { | ||
141 | if (match($0, FS) > 0) { | ||
142 | update_fieldsep(substr($0, RSTART, RLENGTH), p); | ||
143 | if (RSTART + RLENGTH <= length()) | ||
144 | $0 = substr($0, RSTART + RLENGTH); | ||
145 | else | ||
146 | $0 = ""; | ||
147 | } else { | ||
148 | update_fieldsep("", 0); | ||
149 | print "" > outputfile; | ||
150 | next; | ||
151 | } | ||
152 | } while (--n > 0); | ||
153 | } | ||
154 | |||
155 | # Shifts and prints the first n fields. | ||
156 | function print_fields(n) { | ||
157 | do { | ||
158 | update_fieldsep("", 0); | ||
159 | printf("%s", $1) > outputfile; | ||
160 | shift_fields(1, 1); | ||
161 | } while (--n > 0); | ||
162 | } | ||
163 | |||
164 | { | ||
165 | combine_backslashes(); | ||
166 | } | ||
167 | |||
168 | # Print leading FS | ||
169 | { | ||
170 | if (match($0, "^(" FS ")+") > 0) { | ||
171 | update_fieldsep(substr($0, RSTART, RLENGTH), 1); | ||
172 | if (RSTART + RLENGTH <= length()) | ||
173 | $0 = substr($0, RSTART + RLENGTH); | ||
174 | else | ||
175 | $0 = ""; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | # Parse the line. | ||
180 | { | ||
181 | while (NF > 0) { | ||
182 | if ($1 == "struct" && NF < 3) { | ||
183 | read_line(); | ||
184 | continue; | ||
185 | } | ||
186 | |||
187 | if (FILENAME ~ /\.h$/ && !inside_srcu_struct && | ||
188 | brace_nesting == 0 && paren_nesting == 0 && | ||
189 | $1 == "struct" && $2 == "srcu_struct" && | ||
190 | $0 ~ "^struct(" FS ")+srcu_struct(" FS ")+\\{") { | ||
191 | inside_srcu_struct = 1; | ||
192 | print_fields(2); | ||
193 | continue; | ||
194 | } | ||
195 | if (inside_srcu_struct && brace_nesting == 0 && | ||
196 | paren_nesting == 0) { | ||
197 | inside_srcu_struct = 0; | ||
198 | update_fieldsep("", 0); | ||
199 | for (name in rcu_batches) | ||
200 | print "extern struct rcu_batch " name ";" > outputfile; | ||
201 | } | ||
202 | |||
203 | if (inside_srcu_struct && $1 == "struct" && $2 == "rcu_batch") { | ||
204 | # Move rcu_batches outside of the struct. | ||
205 | rcu_batches[$3] = ""; | ||
206 | shift_fields(3, 1); | ||
207 | sub(/;[[:space:]]*$/, "", last_fs); | ||
208 | continue; | ||
209 | } | ||
210 | |||
211 | if (FILENAME ~ /\.h$/ && !inside_srcu_init_def && | ||
212 | $1 == "#define" && $2 == "__SRCU_STRUCT_INIT") { | ||
213 | inside_srcu_init_def = 1; | ||
214 | srcu_init_param_name = $3; | ||
215 | in_macro = 1; | ||
216 | print_fields(3); | ||
217 | continue; | ||
218 | } | ||
219 | if (inside_srcu_init_def && brace_nesting == 0 && | ||
220 | paren_nesting == 0) { | ||
221 | inside_srcu_init_def = 0; | ||
222 | in_macro = 0; | ||
223 | continue; | ||
224 | } | ||
225 | |||
226 | if (inside_srcu_init_def && brace_nesting == 1 && | ||
227 | paren_nesting == 0 && last_fs ~ /\.[[:space:]]*$/ && | ||
228 | $1 ~ /^[[:alnum:]_]+$/) { | ||
229 | name = $1; | ||
230 | if (name in rcu_batches) { | ||
231 | # Remove the dot. | ||
232 | sub(/\.[[:space:]]*$/, "", last_fs); | ||
233 | |||
234 | old_record = $0; | ||
235 | do | ||
236 | shift_fields(1, 0); | ||
237 | while (last_fs !~ /,/ || paren_nesting > 0); | ||
238 | end_loc = length(old_record) - length($0); | ||
239 | end_loc += index(last_fs, ",") - length(last_fs); | ||
240 | |||
241 | last_fs = substr(last_fs, index(last_fs, ",") + 1); | ||
242 | last_fs_print = 1; | ||
243 | |||
244 | match(old_record, "^"name"("FS")+="); | ||
245 | start_loc = RSTART + RLENGTH; | ||
246 | |||
247 | len = end_loc - start_loc; | ||
248 | initializer = substr(old_record, start_loc, len); | ||
249 | gsub(srcu_init_param_name "\\.", "", initializer); | ||
250 | rcu_batches[name] = initializer; | ||
251 | continue; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | # Don't include a nonexistent file | ||
256 | if (!in_macro && $1 == "#include" && /^#include[[:space:]]+"rcu\.h"/) { | ||
257 | update_fieldsep("", 0); | ||
258 | next; | ||
259 | } | ||
260 | |||
261 | # Ignore most preprocessor stuff. | ||
262 | if (!in_macro && $1 ~ /#/) { | ||
263 | break; | ||
264 | } | ||
265 | |||
266 | if (brace_nesting > 0 && $1 ~ "^[[:alnum:]_]+$" && NF < 2) { | ||
267 | read_line(); | ||
268 | continue; | ||
269 | } | ||
270 | if (brace_nesting > 0 && | ||
271 | $0 ~ "^[[:alnum:]_]+[[:space:]]*(\\.|->)[[:space:]]*[[:alnum:]_]+" && | ||
272 | $2 in rcu_batches) { | ||
273 | # Make uses of rcu_batches global. Somewhat unreliable. | ||
274 | shift_fields(1, 0); | ||
275 | print_fields(1); | ||
276 | continue; | ||
277 | } | ||
278 | |||
279 | if ($1 == "static" && NF < 3) { | ||
280 | read_line(); | ||
281 | continue; | ||
282 | } | ||
283 | if ($1 == "static" && ($2 == "bool" && $3 == "try_check_zero" || | ||
284 | $2 == "void" && $3 == "srcu_flip")) { | ||
285 | shift_fields(1, 1); | ||
286 | print_fields(2); | ||
287 | continue; | ||
288 | } | ||
289 | |||
290 | # Distinguish between read-side and write-side memory barriers. | ||
291 | if ($1 == "smp_mb" && NF < 2) { | ||
292 | read_line(); | ||
293 | continue; | ||
294 | } | ||
295 | if (match($0, /^smp_mb[[:space:]();\/*]*[[:alnum:]]/)) { | ||
296 | barrier_letter = substr($0, RLENGTH, 1); | ||
297 | if (barrier_letter ~ /A|D/) | ||
298 | new_barrier_name = "sync_smp_mb"; | ||
299 | else if (barrier_letter ~ /B|C/) | ||
300 | new_barrier_name = "rs_smp_mb"; | ||
301 | else { | ||
302 | print "Unrecognized memory barrier." > "/dev/null"; | ||
303 | exit 1; | ||
304 | } | ||
305 | |||
306 | shift_fields(1, 1); | ||
307 | printf("%s", new_barrier_name) > outputfile; | ||
308 | continue; | ||
309 | } | ||
310 | |||
311 | # Skip definition of rcu_synchronize, since it is already | ||
312 | # defined in misc.h. Only present in old versions of srcu. | ||
313 | if (brace_nesting == 0 && paren_nesting == 0 && | ||
314 | $1 == "struct" && $2 == "rcu_synchronize" && | ||
315 | $0 ~ "^struct(" FS ")+rcu_synchronize(" FS ")+\\{") { | ||
316 | shift_fields(2, 0); | ||
317 | while (brace_nesting) { | ||
318 | if (NF < 2) | ||
319 | read_line(); | ||
320 | shift_fields(1, 0); | ||
321 | } | ||
322 | } | ||
323 | |||
324 | # Skip definition of wakeme_after_rcu for the same reason | ||
325 | if (brace_nesting == 0 && $1 == "static" && $2 == "void" && | ||
326 | $3 == "wakeme_after_rcu") { | ||
327 | while (NF < 5) | ||
328 | read_line(); | ||
329 | shift_fields(3, 0); | ||
330 | do { | ||
331 | while (NF < 3) | ||
332 | read_line(); | ||
333 | shift_fields(1, 0); | ||
334 | } while (paren_nesting || brace_nesting); | ||
335 | } | ||
336 | |||
337 | if ($1 ~ /^(unsigned|long)$/ && NF < 3) { | ||
338 | read_line(); | ||
339 | continue; | ||
340 | } | ||
341 | |||
342 | # Give srcu_batches_completed the correct type for old SRCU. | ||
343 | if (brace_nesting == 0 && $1 == "long" && | ||
344 | $2 == "srcu_batches_completed") { | ||
345 | update_fieldsep("", 0); | ||
346 | printf("unsigned ") > outputfile; | ||
347 | print_fields(2); | ||
348 | continue; | ||
349 | } | ||
350 | if (brace_nesting == 0 && $1 == "unsigned" && $2 == "long" && | ||
351 | $3 == "srcu_batches_completed") { | ||
352 | print_fields(3); | ||
353 | continue; | ||
354 | } | ||
355 | |||
356 | # Just print out the input code by default. | ||
357 | print_fields(1); | ||
358 | } | ||
359 | update_fieldsep("", 0); | ||
360 | print > outputfile; | ||
361 | next; | ||
362 | } | ||
363 | |||
364 | END { | ||
365 | update_fieldsep("", 0); | ||
366 | |||
367 | if (brace_nesting != 0) { | ||
368 | print "Unbalanced braces!" > "/dev/stderr"; | ||
369 | exit 1; | ||
370 | } | ||
371 | |||
372 | # Define the rcu_batches | ||
373 | for (name in rcu_batches) | ||
374 | print "struct rcu_batch " name " = " rcu_batches[name] ";" > c_output; | ||
375 | } | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h new file mode 100644 index 000000000000..a64955447995 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/assume.h | |||
@@ -0,0 +1,16 @@ | |||
1 | #ifndef ASSUME_H | ||
2 | #define ASSUME_H | ||
3 | |||
4 | /* Provide an assumption macro that can be disabled for gcc. */ | ||
5 | #ifdef RUN | ||
6 | #define assume(x) \ | ||
7 | do { \ | ||
8 | /* Evaluate x to suppress warnings. */ \ | ||
9 | (void) (x); \ | ||
10 | } while (0) | ||
11 | |||
12 | #else | ||
13 | #define assume(x) __CPROVER_assume(x) | ||
14 | #endif | ||
15 | |||
16 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h new file mode 100644 index 000000000000..6687acc08e6d --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/barriers.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef BARRIERS_H | ||
2 | #define BARRIERS_H | ||
3 | |||
4 | #define barrier() __asm__ __volatile__("" : : : "memory") | ||
5 | |||
6 | #ifdef RUN | ||
7 | #define smp_mb() __sync_synchronize() | ||
8 | #define smp_mb__after_unlock_lock() __sync_synchronize() | ||
9 | #else | ||
10 | /* | ||
11 | * Copied from CBMC's implementation of __sync_synchronize(), which | ||
12 | * seems to be disabled by default. | ||
13 | */ | ||
14 | #define smp_mb() __CPROVER_fence("WWfence", "RRfence", "RWfence", "WRfence", \ | ||
15 | "WWcumul", "RRcumul", "RWcumul", "WRcumul") | ||
16 | #define smp_mb__after_unlock_lock() __CPROVER_fence("WWfence", "RRfence", "RWfence", "WRfence", \ | ||
17 | "WWcumul", "RRcumul", "RWcumul", "WRcumul") | ||
18 | #endif | ||
19 | |||
20 | /* | ||
21 | * Allow memory barriers to be disabled in either the read or write side | ||
22 | * of SRCU individually. | ||
23 | */ | ||
24 | |||
25 | #ifndef NO_SYNC_SMP_MB | ||
26 | #define sync_smp_mb() smp_mb() | ||
27 | #else | ||
28 | #define sync_smp_mb() do {} while (0) | ||
29 | #endif | ||
30 | |||
31 | #ifndef NO_READ_SIDE_SMP_MB | ||
32 | #define rs_smp_mb() smp_mb() | ||
33 | #else | ||
34 | #define rs_smp_mb() do {} while (0) | ||
35 | #endif | ||
36 | |||
37 | #define ACCESS_ONCE(x) (*(volatile typeof(x) *) &(x)) | ||
38 | #define READ_ONCE(x) ACCESS_ONCE(x) | ||
39 | #define WRITE_ONCE(x, val) (ACCESS_ONCE(x) = (val)) | ||
40 | |||
41 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h new file mode 100644 index 000000000000..2a80e91f78e7 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/bug_on.h | |||
@@ -0,0 +1,13 @@ | |||
1 | #ifndef BUG_ON_H | ||
2 | #define BUG_ON_H | ||
3 | |||
4 | #include <assert.h> | ||
5 | |||
6 | #define BUG() assert(0) | ||
7 | #define BUG_ON(x) assert(!(x)) | ||
8 | |||
9 | /* Does it make sense to treat warnings as errors? */ | ||
10 | #define WARN() BUG() | ||
11 | #define WARN_ON(x) (BUG_ON(x), false) | ||
12 | |||
13 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c new file mode 100644 index 000000000000..29eb5d2697ed --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/combined_source.c | |||
@@ -0,0 +1,13 @@ | |||
1 | #include <config.h> | ||
2 | |||
3 | /* Include all source files. */ | ||
4 | |||
5 | #include "include_srcu.c" | ||
6 | |||
7 | #include "preempt.c" | ||
8 | #include "misc.c" | ||
9 | |||
10 | /* Used by test.c files */ | ||
11 | #include <pthread.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <linux/srcu.h> | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h new file mode 100644 index 000000000000..a60038aeea7a --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/config.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* "Cheater" definitions based on restricted Kconfig choices. */ | ||
2 | |||
3 | #undef CONFIG_TINY_RCU | ||
4 | #undef __CHECKER__ | ||
5 | #undef CONFIG_DEBUG_LOCK_ALLOC | ||
6 | #undef CONFIG_DEBUG_OBJECTS_RCU_HEAD | ||
7 | #undef CONFIG_HOTPLUG_CPU | ||
8 | #undef CONFIG_MODULES | ||
9 | #undef CONFIG_NO_HZ_FULL_SYSIDLE | ||
10 | #undef CONFIG_PREEMPT_COUNT | ||
11 | #undef CONFIG_PREEMPT_RCU | ||
12 | #undef CONFIG_PROVE_RCU | ||
13 | #undef CONFIG_RCU_NOCB_CPU | ||
14 | #undef CONFIG_RCU_NOCB_CPU_ALL | ||
15 | #undef CONFIG_RCU_STALL_COMMON | ||
16 | #undef CONFIG_RCU_TRACE | ||
17 | #undef CONFIG_RCU_USER_QS | ||
18 | #undef CONFIG_TASKS_RCU | ||
19 | #define CONFIG_TREE_RCU | ||
20 | |||
21 | #define CONFIG_GENERIC_ATOMIC64 | ||
22 | |||
23 | #if NR_CPUS > 1 | ||
24 | #define CONFIG_SMP | ||
25 | #else | ||
26 | #undef CONFIG_SMP | ||
27 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c new file mode 100644 index 000000000000..5ec582a53018 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/include_srcu.c | |||
@@ -0,0 +1,31 @@ | |||
1 | #include <config.h> | ||
2 | |||
3 | #include <assert.h> | ||
4 | #include <errno.h> | ||
5 | #include <inttypes.h> | ||
6 | #include <pthread.h> | ||
7 | #include <stddef.h> | ||
8 | #include <string.h> | ||
9 | #include <sys/types.h> | ||
10 | |||
11 | #include "int_typedefs.h" | ||
12 | |||
13 | #include "barriers.h" | ||
14 | #include "bug_on.h" | ||
15 | #include "locks.h" | ||
16 | #include "misc.h" | ||
17 | #include "preempt.h" | ||
18 | #include "percpu.h" | ||
19 | #include "workqueues.h" | ||
20 | |||
21 | #ifdef USE_SIMPLE_SYNC_SRCU | ||
22 | #define synchronize_srcu(sp) synchronize_srcu_original(sp) | ||
23 | #endif | ||
24 | |||
25 | #include <srcu.c> | ||
26 | |||
27 | #ifdef USE_SIMPLE_SYNC_SRCU | ||
28 | #undef synchronize_srcu | ||
29 | |||
30 | #include "simple_sync_srcu.c" | ||
31 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h new file mode 100644 index 000000000000..3aad63917858 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/int_typedefs.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifndef INT_TYPEDEFS_H | ||
2 | #define INT_TYPEDEFS_H | ||
3 | |||
4 | #include <inttypes.h> | ||
5 | |||
6 | typedef int8_t s8; | ||
7 | typedef uint8_t u8; | ||
8 | typedef int16_t s16; | ||
9 | typedef uint16_t u16; | ||
10 | typedef int32_t s32; | ||
11 | typedef uint32_t u32; | ||
12 | typedef int64_t s64; | ||
13 | typedef uint64_t u64; | ||
14 | |||
15 | typedef int8_t __s8; | ||
16 | typedef uint8_t __u8; | ||
17 | typedef int16_t __s16; | ||
18 | typedef uint16_t __u16; | ||
19 | typedef int32_t __s32; | ||
20 | typedef uint32_t __u32; | ||
21 | typedef int64_t __s64; | ||
22 | typedef uint64_t __u64; | ||
23 | |||
24 | #define S8_C(x) INT8_C(x) | ||
25 | #define U8_C(x) UINT8_C(x) | ||
26 | #define S16_C(x) INT16_C(x) | ||
27 | #define U16_C(x) UINT16_C(x) | ||
28 | #define S32_C(x) INT32_C(x) | ||
29 | #define U32_C(x) UINT32_C(x) | ||
30 | #define S64_C(x) INT64_C(x) | ||
31 | #define U64_C(x) UINT64_C(x) | ||
32 | |||
33 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h new file mode 100644 index 000000000000..356004665576 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/locks.h | |||
@@ -0,0 +1,220 @@ | |||
1 | #ifndef LOCKS_H | ||
2 | #define LOCKS_H | ||
3 | |||
4 | #include <limits.h> | ||
5 | #include <pthread.h> | ||
6 | #include <stdbool.h> | ||
7 | |||
8 | #include "assume.h" | ||
9 | #include "bug_on.h" | ||
10 | #include "preempt.h" | ||
11 | |||
12 | int nondet_int(void); | ||
13 | |||
14 | #define __acquire(x) | ||
15 | #define __acquires(x) | ||
16 | #define __release(x) | ||
17 | #define __releases(x) | ||
18 | |||
19 | /* Only use one lock mechanism. Select which one. */ | ||
20 | #ifdef PTHREAD_LOCK | ||
21 | struct lock_impl { | ||
22 | pthread_mutex_t mutex; | ||
23 | }; | ||
24 | |||
25 | static inline void lock_impl_lock(struct lock_impl *lock) | ||
26 | { | ||
27 | BUG_ON(pthread_mutex_lock(&lock->mutex)); | ||
28 | } | ||
29 | |||
30 | static inline void lock_impl_unlock(struct lock_impl *lock) | ||
31 | { | ||
32 | BUG_ON(pthread_mutex_unlock(&lock->mutex)); | ||
33 | } | ||
34 | |||
35 | static inline bool lock_impl_trylock(struct lock_impl *lock) | ||
36 | { | ||
37 | int err = pthread_mutex_trylock(&lock->mutex); | ||
38 | |||
39 | if (!err) | ||
40 | return true; | ||
41 | else if (err == EBUSY) | ||
42 | return false; | ||
43 | BUG(); | ||
44 | } | ||
45 | |||
46 | static inline void lock_impl_init(struct lock_impl *lock) | ||
47 | { | ||
48 | pthread_mutex_init(&lock->mutex, NULL); | ||
49 | } | ||
50 | |||
51 | #define LOCK_IMPL_INITIALIZER {.mutex = PTHREAD_MUTEX_INITIALIZER} | ||
52 | |||
53 | #else /* !defined(PTHREAD_LOCK) */ | ||
54 | /* Spinlock that assumes that it always gets the lock immediately. */ | ||
55 | |||
56 | struct lock_impl { | ||
57 | bool locked; | ||
58 | }; | ||
59 | |||
60 | static inline bool lock_impl_trylock(struct lock_impl *lock) | ||
61 | { | ||
62 | #ifdef RUN | ||
63 | /* TODO: Should this be a test and set? */ | ||
64 | return __sync_bool_compare_and_swap(&lock->locked, false, true); | ||
65 | #else | ||
66 | __CPROVER_atomic_begin(); | ||
67 | bool old_locked = lock->locked; | ||
68 | lock->locked = true; | ||
69 | __CPROVER_atomic_end(); | ||
70 | |||
71 | /* Minimal barrier to prevent accesses leaking out of lock. */ | ||
72 | __CPROVER_fence("RRfence", "RWfence"); | ||
73 | |||
74 | return !old_locked; | ||
75 | #endif | ||
76 | } | ||
77 | |||
78 | static inline void lock_impl_lock(struct lock_impl *lock) | ||
79 | { | ||
80 | /* | ||
81 | * CBMC doesn't support busy waiting, so just assume that the | ||
82 | * lock is available. | ||
83 | */ | ||
84 | assume(lock_impl_trylock(lock)); | ||
85 | |||
86 | /* | ||
87 | * If the lock was already held by this thread then the assumption | ||
88 | * is unsatisfiable (deadlock). | ||
89 | */ | ||
90 | } | ||
91 | |||
92 | static inline void lock_impl_unlock(struct lock_impl *lock) | ||
93 | { | ||
94 | #ifdef RUN | ||
95 | BUG_ON(!__sync_bool_compare_and_swap(&lock->locked, true, false)); | ||
96 | #else | ||
97 | /* Minimal barrier to prevent accesses leaking out of lock. */ | ||
98 | __CPROVER_fence("RWfence", "WWfence"); | ||
99 | |||
100 | __CPROVER_atomic_begin(); | ||
101 | bool old_locked = lock->locked; | ||
102 | lock->locked = false; | ||
103 | __CPROVER_atomic_end(); | ||
104 | |||
105 | BUG_ON(!old_locked); | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | static inline void lock_impl_init(struct lock_impl *lock) | ||
110 | { | ||
111 | lock->locked = false; | ||
112 | } | ||
113 | |||
114 | #define LOCK_IMPL_INITIALIZER {.locked = false} | ||
115 | |||
116 | #endif /* !defined(PTHREAD_LOCK) */ | ||
117 | |||
118 | /* | ||
119 | * Implement spinlocks using the lock mechanism. Wrap the lock to prevent mixing | ||
120 | * locks of different types. | ||
121 | */ | ||
122 | typedef struct { | ||
123 | struct lock_impl internal_lock; | ||
124 | } spinlock_t; | ||
125 | |||
126 | #define SPIN_LOCK_UNLOCKED {.internal_lock = LOCK_IMPL_INITIALIZER} | ||
127 | #define __SPIN_LOCK_UNLOCKED(x) SPIN_LOCK_UNLOCKED | ||
128 | #define DEFINE_SPINLOCK(x) spinlock_t x = SPIN_LOCK_UNLOCKED | ||
129 | |||
130 | static inline void spin_lock_init(spinlock_t *lock) | ||
131 | { | ||
132 | lock_impl_init(&lock->internal_lock); | ||
133 | } | ||
134 | |||
135 | static inline void spin_lock(spinlock_t *lock) | ||
136 | { | ||
137 | /* | ||
138 | * Spin locks also need to be removed in order to eliminate all | ||
139 | * memory barriers. They are only used by the write side anyway. | ||
140 | */ | ||
141 | #ifndef NO_SYNC_SMP_MB | ||
142 | preempt_disable(); | ||
143 | lock_impl_lock(&lock->internal_lock); | ||
144 | #endif | ||
145 | } | ||
146 | |||
147 | static inline void spin_unlock(spinlock_t *lock) | ||
148 | { | ||
149 | #ifndef NO_SYNC_SMP_MB | ||
150 | lock_impl_unlock(&lock->internal_lock); | ||
151 | preempt_enable(); | ||
152 | #endif | ||
153 | } | ||
154 | |||
155 | /* Don't bother with interrupts */ | ||
156 | #define spin_lock_irq(lock) spin_lock(lock) | ||
157 | #define spin_unlock_irq(lock) spin_unlock(lock) | ||
158 | #define spin_lock_irqsave(lock, flags) spin_lock(lock) | ||
159 | #define spin_unlock_irqrestore(lock, flags) spin_unlock(lock) | ||
160 | |||
161 | /* | ||
162 | * This is supposed to return an int, but I think that a bool should work as | ||
163 | * well. | ||
164 | */ | ||
165 | static inline bool spin_trylock(spinlock_t *lock) | ||
166 | { | ||
167 | #ifndef NO_SYNC_SMP_MB | ||
168 | preempt_disable(); | ||
169 | return lock_impl_trylock(&lock->internal_lock); | ||
170 | #else | ||
171 | return true; | ||
172 | #endif | ||
173 | } | ||
174 | |||
175 | struct completion { | ||
176 | /* Hopefuly this won't overflow. */ | ||
177 | unsigned int count; | ||
178 | }; | ||
179 | |||
180 | #define COMPLETION_INITIALIZER(x) {.count = 0} | ||
181 | #define DECLARE_COMPLETION(x) struct completion x = COMPLETION_INITIALIZER(x) | ||
182 | #define DECLARE_COMPLETION_ONSTACK(x) DECLARE_COMPLETION(x) | ||
183 | |||
184 | static inline void init_completion(struct completion *c) | ||
185 | { | ||
186 | c->count = 0; | ||
187 | } | ||
188 | |||
189 | static inline void wait_for_completion(struct completion *c) | ||
190 | { | ||
191 | unsigned int prev_count = __sync_fetch_and_sub(&c->count, 1); | ||
192 | |||
193 | assume(prev_count); | ||
194 | } | ||
195 | |||
196 | static inline void complete(struct completion *c) | ||
197 | { | ||
198 | unsigned int prev_count = __sync_fetch_and_add(&c->count, 1); | ||
199 | |||
200 | BUG_ON(prev_count == UINT_MAX); | ||
201 | } | ||
202 | |||
203 | /* This function probably isn't very useful for CBMC. */ | ||
204 | static inline bool try_wait_for_completion(struct completion *c) | ||
205 | { | ||
206 | BUG(); | ||
207 | } | ||
208 | |||
209 | static inline bool completion_done(struct completion *c) | ||
210 | { | ||
211 | return c->count; | ||
212 | } | ||
213 | |||
214 | /* TODO: Implement complete_all */ | ||
215 | static inline void complete_all(struct completion *c) | ||
216 | { | ||
217 | BUG(); | ||
218 | } | ||
219 | |||
220 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c new file mode 100644 index 000000000000..ca892e3b2351 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.c | |||
@@ -0,0 +1,11 @@ | |||
1 | #include <config.h> | ||
2 | |||
3 | #include "misc.h" | ||
4 | #include "bug_on.h" | ||
5 | |||
6 | struct rcu_head; | ||
7 | |||
8 | void wakeme_after_rcu(struct rcu_head *head) | ||
9 | { | ||
10 | BUG(); | ||
11 | } | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h new file mode 100644 index 000000000000..aca50030f954 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/misc.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef MISC_H | ||
2 | #define MISC_H | ||
3 | |||
4 | #include "assume.h" | ||
5 | #include "int_typedefs.h" | ||
6 | #include "locks.h" | ||
7 | |||
8 | #include <linux/types.h> | ||
9 | |||
10 | /* Probably won't need to deal with bottom halves. */ | ||
11 | static inline void local_bh_disable(void) {} | ||
12 | static inline void local_bh_enable(void) {} | ||
13 | |||
14 | #define MODULE_ALIAS(X) | ||
15 | #define module_param(...) | ||
16 | #define EXPORT_SYMBOL_GPL(x) | ||
17 | |||
18 | #define container_of(ptr, type, member) ({ \ | ||
19 | const typeof(((type *)0)->member) *__mptr = (ptr); \ | ||
20 | (type *)((char *)__mptr - offsetof(type, member)); \ | ||
21 | }) | ||
22 | |||
23 | #ifndef USE_SIMPLE_SYNC_SRCU | ||
24 | /* Abuse udelay to make sure that busy loops terminate. */ | ||
25 | #define udelay(x) assume(0) | ||
26 | |||
27 | #else | ||
28 | |||
29 | /* The simple custom synchronize_srcu is ok with try_check_zero failing. */ | ||
30 | #define udelay(x) do { } while (0) | ||
31 | #endif | ||
32 | |||
33 | #define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ | ||
34 | do { } while (0) | ||
35 | |||
36 | #define notrace | ||
37 | |||
38 | /* Avoid including rcupdate.h */ | ||
39 | struct rcu_synchronize { | ||
40 | struct rcu_head head; | ||
41 | struct completion completion; | ||
42 | }; | ||
43 | |||
44 | void wakeme_after_rcu(struct rcu_head *head); | ||
45 | |||
46 | #define rcu_lock_acquire(a) do { } while (0) | ||
47 | #define rcu_lock_release(a) do { } while (0) | ||
48 | #define rcu_lockdep_assert(c, s) do { } while (0) | ||
49 | #define RCU_LOCKDEP_WARN(c, s) do { } while (0) | ||
50 | |||
51 | /* Let CBMC non-deterministically choose switch between normal and expedited. */ | ||
52 | bool rcu_gp_is_normal(void); | ||
53 | bool rcu_gp_is_expedited(void); | ||
54 | |||
55 | /* Do the same for old versions of rcu. */ | ||
56 | #define rcu_expedited (rcu_gp_is_expedited()) | ||
57 | |||
58 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h new file mode 100644 index 000000000000..3de5a49de49b --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/percpu.h | |||
@@ -0,0 +1,92 @@ | |||
1 | #ifndef PERCPU_H | ||
2 | #define PERCPU_H | ||
3 | |||
4 | #include <stddef.h> | ||
5 | #include "bug_on.h" | ||
6 | #include "preempt.h" | ||
7 | |||
8 | #define __percpu | ||
9 | |||
10 | /* Maximum size of any percpu data. */ | ||
11 | #define PERCPU_OFFSET (4 * sizeof(long)) | ||
12 | |||
13 | /* Ignore alignment, as CBMC doesn't care about false sharing. */ | ||
14 | #define alloc_percpu(type) __alloc_percpu(sizeof(type), 1) | ||
15 | |||
16 | static inline void *__alloc_percpu(size_t size, size_t align) | ||
17 | { | ||
18 | BUG(); | ||
19 | return NULL; | ||
20 | } | ||
21 | |||
22 | static inline void free_percpu(void *ptr) | ||
23 | { | ||
24 | BUG(); | ||
25 | } | ||
26 | |||
27 | #define per_cpu_ptr(ptr, cpu) \ | ||
28 | ((typeof(ptr)) ((char *) (ptr) + PERCPU_OFFSET * cpu)) | ||
29 | |||
30 | #define __this_cpu_inc(pcp) __this_cpu_add(pcp, 1) | ||
31 | #define __this_cpu_dec(pcp) __this_cpu_sub(pcp, 1) | ||
32 | #define __this_cpu_sub(pcp, n) __this_cpu_add(pcp, -(typeof(pcp)) (n)) | ||
33 | |||
34 | #define this_cpu_inc(pcp) this_cpu_add(pcp, 1) | ||
35 | #define this_cpu_dec(pcp) this_cpu_sub(pcp, 1) | ||
36 | #define this_cpu_sub(pcp, n) this_cpu_add(pcp, -(typeof(pcp)) (n)) | ||
37 | |||
38 | /* Make CBMC use atomics to work around bug. */ | ||
39 | #ifdef RUN | ||
40 | #define THIS_CPU_ADD_HELPER(ptr, x) (*(ptr) += (x)) | ||
41 | #else | ||
42 | /* | ||
43 | * Split the atomic into a read and a write so that it has the least | ||
44 | * possible ordering. | ||
45 | */ | ||
46 | #define THIS_CPU_ADD_HELPER(ptr, x) \ | ||
47 | do { \ | ||
48 | typeof(ptr) this_cpu_add_helper_ptr = (ptr); \ | ||
49 | typeof(ptr) this_cpu_add_helper_x = (x); \ | ||
50 | typeof(*ptr) this_cpu_add_helper_temp; \ | ||
51 | __CPROVER_atomic_begin(); \ | ||
52 | this_cpu_add_helper_temp = *(this_cpu_add_helper_ptr); \ | ||
53 | __CPROVER_atomic_end(); \ | ||
54 | this_cpu_add_helper_temp += this_cpu_add_helper_x; \ | ||
55 | __CPROVER_atomic_begin(); \ | ||
56 | *(this_cpu_add_helper_ptr) = this_cpu_add_helper_temp; \ | ||
57 | __CPROVER_atomic_end(); \ | ||
58 | } while (0) | ||
59 | #endif | ||
60 | |||
61 | /* | ||
62 | * For some reason CBMC needs an atomic operation even though this is percpu | ||
63 | * data. | ||
64 | */ | ||
65 | #define __this_cpu_add(pcp, n) \ | ||
66 | do { \ | ||
67 | BUG_ON(preemptible()); \ | ||
68 | THIS_CPU_ADD_HELPER(per_cpu_ptr(&(pcp), thread_cpu_id), \ | ||
69 | (typeof(pcp)) (n)); \ | ||
70 | } while (0) | ||
71 | |||
72 | #define this_cpu_add(pcp, n) \ | ||
73 | do { \ | ||
74 | int this_cpu_add_impl_cpu = get_cpu(); \ | ||
75 | THIS_CPU_ADD_HELPER(per_cpu_ptr(&(pcp), this_cpu_add_impl_cpu), \ | ||
76 | (typeof(pcp)) (n)); \ | ||
77 | put_cpu(); \ | ||
78 | } while (0) | ||
79 | |||
80 | /* | ||
81 | * This will cause a compiler warning because of the cast from char[][] to | ||
82 | * type*. This will cause a compile time error if type is too big. | ||
83 | */ | ||
84 | #define DEFINE_PER_CPU(type, name) \ | ||
85 | char name[NR_CPUS][PERCPU_OFFSET]; \ | ||
86 | typedef char percpu_too_big_##name \ | ||
87 | [sizeof(type) > PERCPU_OFFSET ? -1 : 1] | ||
88 | |||
89 | #define for_each_possible_cpu(cpu) \ | ||
90 | for ((cpu) = 0; (cpu) < NR_CPUS; ++(cpu)) | ||
91 | |||
92 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c new file mode 100644 index 000000000000..4f1b068e9b7a --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.c | |||
@@ -0,0 +1,78 @@ | |||
1 | #include <config.h> | ||
2 | |||
3 | #include "preempt.h" | ||
4 | |||
5 | #include "assume.h" | ||
6 | #include "locks.h" | ||
7 | |||
8 | /* Support NR_CPUS of at most 64 */ | ||
9 | #define CPU_PREEMPTION_LOCKS_INIT0 LOCK_IMPL_INITIALIZER | ||
10 | #define CPU_PREEMPTION_LOCKS_INIT1 \ | ||
11 | CPU_PREEMPTION_LOCKS_INIT0, CPU_PREEMPTION_LOCKS_INIT0 | ||
12 | #define CPU_PREEMPTION_LOCKS_INIT2 \ | ||
13 | CPU_PREEMPTION_LOCKS_INIT1, CPU_PREEMPTION_LOCKS_INIT1 | ||
14 | #define CPU_PREEMPTION_LOCKS_INIT3 \ | ||
15 | CPU_PREEMPTION_LOCKS_INIT2, CPU_PREEMPTION_LOCKS_INIT2 | ||
16 | #define CPU_PREEMPTION_LOCKS_INIT4 \ | ||
17 | CPU_PREEMPTION_LOCKS_INIT3, CPU_PREEMPTION_LOCKS_INIT3 | ||
18 | #define CPU_PREEMPTION_LOCKS_INIT5 \ | ||
19 | CPU_PREEMPTION_LOCKS_INIT4, CPU_PREEMPTION_LOCKS_INIT4 | ||
20 | |||
21 | /* | ||
22 | * Simulate disabling preemption by locking a particular cpu. NR_CPUS | ||
23 | * should be the actual number of cpus, not just the maximum. | ||
24 | */ | ||
25 | struct lock_impl cpu_preemption_locks[NR_CPUS] = { | ||
26 | CPU_PREEMPTION_LOCKS_INIT0 | ||
27 | #if (NR_CPUS - 1) & 1 | ||
28 | , CPU_PREEMPTION_LOCKS_INIT0 | ||
29 | #endif | ||
30 | #if (NR_CPUS - 1) & 2 | ||
31 | , CPU_PREEMPTION_LOCKS_INIT1 | ||
32 | #endif | ||
33 | #if (NR_CPUS - 1) & 4 | ||
34 | , CPU_PREEMPTION_LOCKS_INIT2 | ||
35 | #endif | ||
36 | #if (NR_CPUS - 1) & 8 | ||
37 | , CPU_PREEMPTION_LOCKS_INIT3 | ||
38 | #endif | ||
39 | #if (NR_CPUS - 1) & 16 | ||
40 | , CPU_PREEMPTION_LOCKS_INIT4 | ||
41 | #endif | ||
42 | #if (NR_CPUS - 1) & 32 | ||
43 | , CPU_PREEMPTION_LOCKS_INIT5 | ||
44 | #endif | ||
45 | }; | ||
46 | |||
47 | #undef CPU_PREEMPTION_LOCKS_INIT0 | ||
48 | #undef CPU_PREEMPTION_LOCKS_INIT1 | ||
49 | #undef CPU_PREEMPTION_LOCKS_INIT2 | ||
50 | #undef CPU_PREEMPTION_LOCKS_INIT3 | ||
51 | #undef CPU_PREEMPTION_LOCKS_INIT4 | ||
52 | #undef CPU_PREEMPTION_LOCKS_INIT5 | ||
53 | |||
54 | __thread int thread_cpu_id; | ||
55 | __thread int preempt_disable_count; | ||
56 | |||
57 | void preempt_disable(void) | ||
58 | { | ||
59 | BUG_ON(preempt_disable_count < 0 || preempt_disable_count == INT_MAX); | ||
60 | |||
61 | if (preempt_disable_count++) | ||
62 | return; | ||
63 | |||
64 | thread_cpu_id = nondet_int(); | ||
65 | assume(thread_cpu_id >= 0); | ||
66 | assume(thread_cpu_id < NR_CPUS); | ||
67 | lock_impl_lock(&cpu_preemption_locks[thread_cpu_id]); | ||
68 | } | ||
69 | |||
70 | void preempt_enable(void) | ||
71 | { | ||
72 | BUG_ON(preempt_disable_count < 1); | ||
73 | |||
74 | if (--preempt_disable_count) | ||
75 | return; | ||
76 | |||
77 | lock_impl_unlock(&cpu_preemption_locks[thread_cpu_id]); | ||
78 | } | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h new file mode 100644 index 000000000000..2f95ee0e4dd5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/preempt.h | |||
@@ -0,0 +1,58 @@ | |||
1 | #ifndef PREEMPT_H | ||
2 | #define PREEMPT_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | |||
6 | #include "bug_on.h" | ||
7 | |||
8 | /* This flag contains garbage if preempt_disable_count is 0. */ | ||
9 | extern __thread int thread_cpu_id; | ||
10 | |||
11 | /* Support recursive preemption disabling. */ | ||
12 | extern __thread int preempt_disable_count; | ||
13 | |||
14 | void preempt_disable(void); | ||
15 | void preempt_enable(void); | ||
16 | |||
17 | static inline void preempt_disable_notrace(void) | ||
18 | { | ||
19 | preempt_disable(); | ||
20 | } | ||
21 | |||
22 | static inline void preempt_enable_no_resched(void) | ||
23 | { | ||
24 | preempt_enable(); | ||
25 | } | ||
26 | |||
27 | static inline void preempt_enable_notrace(void) | ||
28 | { | ||
29 | preempt_enable(); | ||
30 | } | ||
31 | |||
32 | static inline int preempt_count(void) | ||
33 | { | ||
34 | return preempt_disable_count; | ||
35 | } | ||
36 | |||
37 | static inline bool preemptible(void) | ||
38 | { | ||
39 | return !preempt_count(); | ||
40 | } | ||
41 | |||
42 | static inline int get_cpu(void) | ||
43 | { | ||
44 | preempt_disable(); | ||
45 | return thread_cpu_id; | ||
46 | } | ||
47 | |||
48 | static inline void put_cpu(void) | ||
49 | { | ||
50 | preempt_enable(); | ||
51 | } | ||
52 | |||
53 | static inline void might_sleep(void) | ||
54 | { | ||
55 | BUG_ON(preempt_disable_count); | ||
56 | } | ||
57 | |||
58 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c new file mode 100644 index 000000000000..ac9cbc62b411 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/simple_sync_srcu.c | |||
@@ -0,0 +1,50 @@ | |||
1 | #include <config.h> | ||
2 | |||
3 | #include <assert.h> | ||
4 | #include <errno.h> | ||
5 | #include <inttypes.h> | ||
6 | #include <pthread.h> | ||
7 | #include <stddef.h> | ||
8 | #include <string.h> | ||
9 | #include <sys/types.h> | ||
10 | |||
11 | #include "int_typedefs.h" | ||
12 | |||
13 | #include "barriers.h" | ||
14 | #include "bug_on.h" | ||
15 | #include "locks.h" | ||
16 | #include "misc.h" | ||
17 | #include "preempt.h" | ||
18 | #include "percpu.h" | ||
19 | #include "workqueues.h" | ||
20 | |||
21 | #include <linux/srcu.h> | ||
22 | |||
23 | /* Functions needed from modify_srcu.c */ | ||
24 | bool try_check_zero(struct srcu_struct *sp, int idx, int trycount); | ||
25 | void srcu_flip(struct srcu_struct *sp); | ||
26 | |||
27 | /* Simpler implementation of synchronize_srcu that ignores batching. */ | ||
28 | void synchronize_srcu(struct srcu_struct *sp) | ||
29 | { | ||
30 | int idx; | ||
31 | /* | ||
32 | * This code assumes that try_check_zero will succeed anyway, | ||
33 | * so there is no point in multiple tries. | ||
34 | */ | ||
35 | const int trycount = 1; | ||
36 | |||
37 | might_sleep(); | ||
38 | |||
39 | /* Ignore the lock, as multiple writers aren't working yet anyway. */ | ||
40 | |||
41 | idx = 1 ^ (sp->completed & 1); | ||
42 | |||
43 | /* For comments see srcu_advance_batches. */ | ||
44 | |||
45 | assume(try_check_zero(sp, idx, trycount)); | ||
46 | |||
47 | srcu_flip(sp); | ||
48 | |||
49 | assume(try_check_zero(sp, idx^1, trycount)); | ||
50 | } | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h new file mode 100644 index 000000000000..e58c8dfd3e90 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/src/workqueues.h | |||
@@ -0,0 +1,102 @@ | |||
1 | #ifndef WORKQUEUES_H | ||
2 | #define WORKQUEUES_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | |||
6 | #include "barriers.h" | ||
7 | #include "bug_on.h" | ||
8 | #include "int_typedefs.h" | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | |||
12 | /* Stub workqueue implementation. */ | ||
13 | |||
14 | struct work_struct; | ||
15 | typedef void (*work_func_t)(struct work_struct *work); | ||
16 | void delayed_work_timer_fn(unsigned long __data); | ||
17 | |||
18 | struct work_struct { | ||
19 | /* atomic_long_t data; */ | ||
20 | unsigned long data; | ||
21 | |||
22 | struct list_head entry; | ||
23 | work_func_t func; | ||
24 | #ifdef CONFIG_LOCKDEP | ||
25 | struct lockdep_map lockdep_map; | ||
26 | #endif | ||
27 | }; | ||
28 | |||
29 | struct timer_list { | ||
30 | struct hlist_node entry; | ||
31 | unsigned long expires; | ||
32 | void (*function)(unsigned long); | ||
33 | unsigned long data; | ||
34 | u32 flags; | ||
35 | int slack; | ||
36 | }; | ||
37 | |||
38 | struct delayed_work { | ||
39 | struct work_struct work; | ||
40 | struct timer_list timer; | ||
41 | |||
42 | /* target workqueue and CPU ->timer uses to queue ->work */ | ||
43 | struct workqueue_struct *wq; | ||
44 | int cpu; | ||
45 | }; | ||
46 | |||
47 | |||
48 | static inline bool schedule_work(struct work_struct *work) | ||
49 | { | ||
50 | BUG(); | ||
51 | return true; | ||
52 | } | ||
53 | |||
54 | static inline bool schedule_work_on(int cpu, struct work_struct *work) | ||
55 | { | ||
56 | BUG(); | ||
57 | return true; | ||
58 | } | ||
59 | |||
60 | static inline bool queue_work(struct workqueue_struct *wq, | ||
61 | struct work_struct *work) | ||
62 | { | ||
63 | BUG(); | ||
64 | return true; | ||
65 | } | ||
66 | |||
67 | static inline bool queue_delayed_work(struct workqueue_struct *wq, | ||
68 | struct delayed_work *dwork, | ||
69 | unsigned long delay) | ||
70 | { | ||
71 | BUG(); | ||
72 | return true; | ||
73 | } | ||
74 | |||
75 | #define INIT_WORK(w, f) \ | ||
76 | do { \ | ||
77 | (w)->data = 0; \ | ||
78 | (w)->func = (f); \ | ||
79 | } while (0) | ||
80 | |||
81 | #define INIT_DELAYED_WORK(w, f) INIT_WORK(&(w)->work, (f)) | ||
82 | |||
83 | #define __WORK_INITIALIZER(n, f) { \ | ||
84 | .data = 0, \ | ||
85 | .entry = { &(n).entry, &(n).entry }, \ | ||
86 | .func = f \ | ||
87 | } | ||
88 | |||
89 | /* Don't bother initializing timer. */ | ||
90 | #define __DELAYED_WORK_INITIALIZER(n, f, tflags) { \ | ||
91 | .work = __WORK_INITIALIZER((n).work, (f)), \ | ||
92 | } | ||
93 | |||
94 | #define DECLARE_WORK(n, f) \ | ||
95 | struct workqueue_struct n = __WORK_INITIALIZER | ||
96 | |||
97 | #define DECLARE_DELAYED_WORK(n, f) \ | ||
98 | struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, 0) | ||
99 | |||
100 | #define system_power_efficient_wq ((struct workqueue_struct *) NULL) | ||
101 | |||
102 | #endif | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore new file mode 100644 index 000000000000..f47cb2045f13 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/.gitignore | |||
@@ -0,0 +1 @@ | |||
*.out | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile new file mode 100644 index 000000000000..3a3aee149225 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | CBMC_FLAGS = -I../.. -I../../src -I../../include -I../../empty_includes -32 -pointer-check -mm pso | ||
2 | |||
3 | all: | ||
4 | for i in ./*.pass; do \ | ||
5 | echo $$i ; \ | ||
6 | CBMC_FLAGS="$(CBMC_FLAGS)" sh ../test_script.sh --should-pass $$i > $$i.out 2>&1 ; \ | ||
7 | done | ||
8 | for i in ./*.fail; do \ | ||
9 | echo $$i ; \ | ||
10 | CBMC_FLAGS="$(CBMC_FLAGS)" sh ../test_script.sh --should-fail $$i > $$i.out 2>&1 ; \ | ||
11 | done | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail new file mode 100644 index 000000000000..40c8075919d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/assert_end.fail | |||
@@ -0,0 +1 @@ | |||
test_cbmc_options="-DASSERT_END" | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail new file mode 100644 index 000000000000..ada5baf0b60d --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force.fail | |||
@@ -0,0 +1 @@ | |||
test_cbmc_options="-DFORCE_FAILURE" | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail new file mode 100644 index 000000000000..8fe00c8db466 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force2.fail | |||
@@ -0,0 +1 @@ | |||
test_cbmc_options="-DFORCE_FAILURE_2" | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail new file mode 100644 index 000000000000..612ed6772844 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/force3.fail | |||
@@ -0,0 +1 @@ | |||
test_cbmc_options="-DFORCE_FAILURE_3" | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/main.pass | |||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c new file mode 100644 index 000000000000..470b1105a112 --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/store_buffering/test.c | |||
@@ -0,0 +1,72 @@ | |||
1 | #include <src/combined_source.c> | ||
2 | |||
3 | int x; | ||
4 | int y; | ||
5 | |||
6 | int __unbuffered_tpr_x; | ||
7 | int __unbuffered_tpr_y; | ||
8 | |||
9 | DEFINE_SRCU(ss); | ||
10 | |||
11 | void rcu_reader(void) | ||
12 | { | ||
13 | int idx; | ||
14 | |||
15 | #ifndef FORCE_FAILURE_3 | ||
16 | idx = srcu_read_lock(&ss); | ||
17 | #endif | ||
18 | might_sleep(); | ||
19 | |||
20 | __unbuffered_tpr_y = READ_ONCE(y); | ||
21 | #ifdef FORCE_FAILURE | ||
22 | srcu_read_unlock(&ss, idx); | ||
23 | idx = srcu_read_lock(&ss); | ||
24 | #endif | ||
25 | WRITE_ONCE(x, 1); | ||
26 | |||
27 | #ifndef FORCE_FAILURE_3 | ||
28 | srcu_read_unlock(&ss, idx); | ||
29 | #endif | ||
30 | might_sleep(); | ||
31 | } | ||
32 | |||
33 | void *thread_update(void *arg) | ||
34 | { | ||
35 | WRITE_ONCE(y, 1); | ||
36 | #ifndef FORCE_FAILURE_2 | ||
37 | synchronize_srcu(&ss); | ||
38 | #endif | ||
39 | might_sleep(); | ||
40 | __unbuffered_tpr_x = READ_ONCE(x); | ||
41 | |||
42 | return NULL; | ||
43 | } | ||
44 | |||
45 | void *thread_process_reader(void *arg) | ||
46 | { | ||
47 | rcu_reader(); | ||
48 | |||
49 | return NULL; | ||
50 | } | ||
51 | |||
52 | int main(int argc, char *argv[]) | ||
53 | { | ||
54 | pthread_t tu; | ||
55 | pthread_t tpr; | ||
56 | |||
57 | if (pthread_create(&tu, NULL, thread_update, NULL)) | ||
58 | abort(); | ||
59 | if (pthread_create(&tpr, NULL, thread_process_reader, NULL)) | ||
60 | abort(); | ||
61 | if (pthread_join(tu, NULL)) | ||
62 | abort(); | ||
63 | if (pthread_join(tpr, NULL)) | ||
64 | abort(); | ||
65 | assert(__unbuffered_tpr_y != 0 || __unbuffered_tpr_x != 0); | ||
66 | |||
67 | #ifdef ASSERT_END | ||
68 | assert(0); | ||
69 | #endif | ||
70 | |||
71 | return 0; | ||
72 | } | ||
diff --git a/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh new file mode 100755 index 000000000000..d1545972a0fa --- /dev/null +++ b/tools/testing/selftests/rcutorture/formal/srcu-cbmc/tests/test_script.sh | |||
@@ -0,0 +1,102 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | # This script expects a mode (either --should-pass or --should-fail) followed by | ||
4 | # an input file. The script uses the following environment variables. The test C | ||
5 | # source file is expected to be named test.c in the directory containing the | ||
6 | # input file. | ||
7 | # | ||
8 | # CBMC: The command to run CBMC. Default: cbmc | ||
9 | # CBMC_FLAGS: Additional flags to pass to CBMC | ||
10 | # NR_CPUS: Number of cpus to run tests with. Default specified by the test | ||
11 | # SYNC_SRCU_MODE: Choose implementation of synchronize_srcu. Defaults to simple. | ||
12 | # kernel: Version included in the linux kernel source. | ||
13 | # simple: Use try_check_zero directly. | ||
14 | # | ||
15 | # The input file is a script that is sourced by this file. It can define any of | ||
16 | # the following variables to configure the test. | ||
17 | # | ||
18 | # test_cbmc_options: Extra options to pass to CBMC. | ||
19 | # min_cpus_fail: Minimum number of CPUs (NR_CPUS) for verification to fail. | ||
20 | # The test is expected to pass if it is run with fewer. (Only | ||
21 | # useful for .fail files) | ||
22 | # default_cpus: Quantity of CPUs to use for the test, if not specified on the | ||
23 | # command line. Default: Larger of 2 and MIN_CPUS_FAIL. | ||
24 | |||
25 | set -e | ||
26 | |||
27 | if test "$#" -ne 2; then | ||
28 | echo "Expected one option followed by an input file" 1>&2 | ||
29 | exit 99 | ||
30 | fi | ||
31 | |||
32 | if test "x$1" = "x--should-pass"; then | ||
33 | should_pass="yes" | ||
34 | elif test "x$1" = "x--should-fail"; then | ||
35 | should_pass="no" | ||
36 | else | ||
37 | echo "Unrecognized argument '$1'" 1>&2 | ||
38 | |||
39 | # Exit code 99 indicates a hard error. | ||
40 | exit 99 | ||
41 | fi | ||
42 | |||
43 | CBMC=${CBMC:-cbmc} | ||
44 | |||
45 | SYNC_SRCU_MODE=${SYNC_SRCU_MODE:-simple} | ||
46 | |||
47 | case ${SYNC_SRCU_MODE} in | ||
48 | kernel) sync_srcu_mode_flags="" ;; | ||
49 | simple) sync_srcu_mode_flags="-DUSE_SIMPLE_SYNC_SRCU" ;; | ||
50 | |||
51 | *) | ||
52 | echo "Unrecognized argument '${SYNC_SRCU_MODE}'" 1>&2 | ||
53 | exit 99 | ||
54 | ;; | ||
55 | esac | ||
56 | |||
57 | min_cpus_fail=1 | ||
58 | |||
59 | c_file=`dirname "$2"`/test.c | ||
60 | |||
61 | # Source the input file. | ||
62 | . $2 | ||
63 | |||
64 | if test ${min_cpus_fail} -gt 2; then | ||
65 | default_default_cpus=${min_cpus_fail} | ||
66 | else | ||
67 | default_default_cpus=2 | ||
68 | fi | ||
69 | default_cpus=${default_cpus:-${default_default_cpus}} | ||
70 | cpus=${NR_CPUS:-${default_cpus}} | ||
71 | |||
72 | # Check if there are two few cpus to make the test fail. | ||
73 | if test $cpus -lt ${min_cpus_fail:-0}; then | ||
74 | should_pass="yes" | ||
75 | fi | ||
76 | |||
77 | cbmc_opts="-DNR_CPUS=${cpus} ${sync_srcu_mode_flags} ${test_cbmc_options} ${CBMC_FLAGS}" | ||
78 | |||
79 | echo "Running CBMC: ${CBMC} ${cbmc_opts} ${c_file}" | ||
80 | if ${CBMC} ${cbmc_opts} "${c_file}"; then | ||
81 | # Verification successful. Make sure that it was supposed to verify. | ||
82 | test "x${should_pass}" = xyes | ||
83 | else | ||
84 | cbmc_exit_status=$? | ||
85 | |||
86 | # An exit status of 10 indicates a failed verification. | ||
87 | # (see cbmc_parse_optionst::do_bmc in the CBMC source code) | ||
88 | if test ${cbmc_exit_status} -eq 10 && test "x${should_pass}" = xno; then | ||
89 | : | ||
90 | else | ||
91 | echo "CBMC returned ${cbmc_exit_status} exit status" 1>&2 | ||
92 | |||
93 | # Parse errors have exit status 6. Any other type of error | ||
94 | # should be considered a hard error. | ||
95 | if test ${cbmc_exit_status} -ne 6 && \ | ||
96 | test ${cbmc_exit_status} -ne 10; then | ||
97 | exit 99 | ||
98 | else | ||
99 | exit 1 | ||
100 | fi | ||
101 | fi | ||
102 | fi | ||