Commit cae2ed9a authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] lockdep: locking API self tests

Introduce DEBUG_LOCKING_API_SELFTESTS, which uses the generic lock debugging
code's silent-failure feature to run a matrix of testcases.  There are 210
testcases currently:

  +-----------------------
  | Locking API testsuite:
  +------------------------------+------+------+------+------+------+------+
                                 | spin |wlock |rlock |mutex | wsem | rsem |
  -------------------------------+------+------+------+------+------+------+
                     A-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
                 A-B-B-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
             A-B-B-C-C-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
             A-B-C-A-B-C deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
         A-B-B-C-C-D-D-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
         A-B-C-D-B-D-D-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
         A-B-C-D-B-C-D-A deadlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
                    double unlock:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
                 bad unlock order:  ok  |  ok  |  ok  |  ok  |  ok  |  ok  |
  --------------------------------------+------+------+------+------+------+
              recursive read-lock:             |  ok  |             |  ok  |
  --------------------------------------+------+------+------+------+------+
                non-nested unlock:  ok  |  ok  |  ok  |  ok  |
  --------------------------------------+------+------+------+
     hard-irqs-on + irq-safe-A/12:  ok  |  ok  |  ok  |
     soft-irqs-on + irq-safe-A/12:  ok  |  ok  |  ok  |
     hard-irqs-on + irq-safe-A/21:  ok  |  ok  |  ok  |
     soft-irqs-on + irq-safe-A/21:  ok  |  ok  |  ok  |
       sirq-safe-A => hirqs-on/12:  ok  |  ok  |  ok  |
       sirq-safe-A => hirqs-on/21:  ok  |  ok  |  ok  |
         hard-safe-A + irqs-on/12:  ok  |  ok  |  ok  |
         soft-safe-A + irqs-on/12:  ok  |  ok  |  ok  |
         hard-safe-A + irqs-on/21:  ok  |  ok  |  ok  |
         soft-safe-A + irqs-on/21:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/123:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/123:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/132:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/132:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/213:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/213:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/231:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/231:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/312:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/312:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #1/321:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #1/321:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/123:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/123:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/132:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/132:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/213:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/213:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/231:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/231:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/312:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/312:  ok  |  ok  |  ok  |
    hard-safe-A + unsafe-B #2/321:  ok  |  ok  |  ok  |
    soft-safe-A + unsafe-B #2/321:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/123:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/123:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/132:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/132:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/213:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/213:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/231:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/231:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/312:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/312:  ok  |  ok  |  ok  |
      hard-irq lock-inversion/321:  ok  |  ok  |  ok  |
      soft-irq lock-inversion/321:  ok  |  ok  |  ok  |
      hard-irq read-recursion/123:  ok  |
      soft-irq read-recursion/123:  ok  |
      hard-irq read-recursion/132:  ok  |
      soft-irq read-recursion/132:  ok  |
      hard-irq read-recursion/213:  ok  |
      soft-irq read-recursion/213:  ok  |
      hard-irq read-recursion/231:  ok  |
      soft-irq read-recursion/231:  ok  |
      hard-irq read-recursion/312:  ok  |
      soft-irq read-recursion/312:  ok  |
      hard-irq read-recursion/321:  ok  |
      soft-irq read-recursion/321:  ok  |
  --------------------------------+-----+----------------
  Good, all 210 testcases passed! |
  --------------------------------+
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarArjan van de Ven <arjan@linux.intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1f194a4c
......@@ -435,6 +435,15 @@ running once the system is up.
debug [KNL] Enable kernel debugging (events log level).
debug_locks_verbose=
[KNL] verbose self-tests
Format=<0|1>
Print debugging info while doing the locking API
self-tests.
We default to 0 (no extra messages), setting it to
1 will print _a lot_ more information - normally
only useful to kernel developers.
decnet= [HW,NET]
Format: <area>[,<node>]
See also Documentation/networking/decnet.txt.
......
......@@ -149,6 +149,17 @@ config DEBUG_SPINLOCK_SLEEP
If you say Y here, various routines which may sleep will become very
noisy if they are called with a spinlock held.
config DEBUG_LOCKING_API_SELFTESTS
bool "Locking API boot-time self-tests"
depends on DEBUG_KERNEL
help
Say Y here if you want the kernel to run a short self-test during
bootup. The self-test checks whether common types of locking bugs
are detected by debugging mechanisms or not. (if you disable
lock debugging then those bugs wont be detected of course.)
The following locking APIs are covered: spinlocks, rwlocks,
mutexes and rwsems.
config STACKTRACE
bool
depends on STACKTRACE_SUPPORT
......
......@@ -18,6 +18,7 @@ CFLAGS_kobject.o += -DDEBUG
CFLAGS_kobject_uevent.o += -DDEBUG
endif
obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o
obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o
lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
......
#undef IRQ_DISABLE
#undef IRQ_ENABLE
#undef IRQ_ENTER
#undef IRQ_EXIT
#define IRQ_ENABLE HARDIRQ_ENABLE
#define IRQ_DISABLE HARDIRQ_DISABLE
#define IRQ_ENTER HARDIRQ_ENTER
#define IRQ_EXIT HARDIRQ_EXIT
#undef LOCK
#define LOCK ML
#undef UNLOCK
#define UNLOCK MU
#undef RLOCK
#undef WLOCK
#undef INIT
#define INIT MI
#include "locking-selftest-rlock.h"
#include "locking-selftest-hardirq.h"
#include "locking-selftest-rlock.h"
#include "locking-selftest-softirq.h"
#undef LOCK
#define LOCK RL
#undef UNLOCK
#define UNLOCK RU
#undef RLOCK
#define RLOCK RL
#undef WLOCK
#define WLOCK WL
#undef INIT
#define INIT RWI
#undef LOCK
#define LOCK RSL
#undef UNLOCK
#define UNLOCK RSU
#undef RLOCK
#define RLOCK RSL
#undef WLOCK
#define WLOCK WSL
#undef INIT
#define INIT RWSI
#undef IRQ_DISABLE
#undef IRQ_ENABLE
#undef IRQ_ENTER
#undef IRQ_EXIT
#define IRQ_DISABLE SOFTIRQ_DISABLE
#define IRQ_ENABLE SOFTIRQ_ENABLE
#define IRQ_ENTER SOFTIRQ_ENTER
#define IRQ_EXIT SOFTIRQ_EXIT
#include "locking-selftest-spin.h"
#include "locking-selftest-hardirq.h"
#include "locking-selftest-spin.h"
#include "locking-selftest-softirq.h"
#undef LOCK
#define LOCK L
#undef UNLOCK
#define UNLOCK U
#undef RLOCK
#undef WLOCK
#undef INIT
#define INIT SI
#include "locking-selftest-wlock.h"
#include "locking-selftest-hardirq.h"
#include "locking-selftest-wlock.h"
#include "locking-selftest-softirq.h"
#undef LOCK
#define LOCK WL
#undef UNLOCK
#define UNLOCK WU
#undef RLOCK
#define RLOCK RL
#undef WLOCK
#define WLOCK WL
#undef INIT
#define INIT RWI
#undef LOCK
#define LOCK WSL
#undef UNLOCK
#define UNLOCK WSU
#undef RLOCK
#define RLOCK RSL
#undef WLOCK
#define WLOCK WSL
#undef INIT
#define INIT RWSI
/*
* lib/locking-selftest.c
*
* Testsuite for various locking APIs: spinlocks, rwlocks,
* mutexes and rw-semaphores.
*
* It is checking both false positives and false negatives.
*
* Started by Ingo Molnar:
*
* Copyright (C) 2006 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
*/
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/debug_locks.h>
#include <linux/irqflags.h>
/*
* Change this to 1 if you want to see the failure printouts:
*/
static unsigned int debug_locks_verbose;
static int __init setup_debug_locks_verbose(char *str)
{
get_option(&str, &debug_locks_verbose);
return 1;
}
__setup("debug_locks_verbose=", setup_debug_locks_verbose);
#define FAILURE 0
#define SUCCESS 1
#define LOCKTYPE_SPIN 0x1
#define LOCKTYPE_RWLOCK 0x2
#define LOCKTYPE_MUTEX 0x4
#define LOCKTYPE_RWSEM 0x8
/*
* Normal standalone locks, for the circular and irq-context
* dependency tests:
*/
static DEFINE_SPINLOCK(lock_A);
static DEFINE_SPINLOCK(lock_B);
static DEFINE_SPINLOCK(lock_C);
static DEFINE_SPINLOCK(lock_D);
static DEFINE_RWLOCK(rwlock_A);
static DEFINE_RWLOCK(rwlock_B);
static DEFINE_RWLOCK(rwlock_C);
static DEFINE_RWLOCK(rwlock_D);
static DEFINE_MUTEX(mutex_A);
static DEFINE_MUTEX(mutex_B);
static DEFINE_MUTEX(mutex_C);
static DEFINE_MUTEX(mutex_D);
static DECLARE_RWSEM(rwsem_A);
static DECLARE_RWSEM(rwsem_B);
static DECLARE_RWSEM(rwsem_C);
static DECLARE_RWSEM(rwsem_D);
/*
* Locks that we initialize dynamically as well so that
* e.g. X1 and X2 becomes two instances of the same class,
* but X* and Y* are different classes. We do this so that
* we do not trigger a real lockup:
*/
static DEFINE_SPINLOCK(lock_X1);
static DEFINE_SPINLOCK(lock_X2);
static DEFINE_SPINLOCK(lock_Y1);
static DEFINE_SPINLOCK(lock_Y2);
static DEFINE_SPINLOCK(lock_Z1);
static DEFINE_SPINLOCK(lock_Z2);
static DEFINE_RWLOCK(rwlock_X1);
static DEFINE_RWLOCK(rwlock_X2);
static DEFINE_RWLOCK(rwlock_Y1);
static DEFINE_RWLOCK(rwlock_Y2);
static DEFINE_RWLOCK(rwlock_Z1);
static DEFINE_RWLOCK(rwlock_Z2);
static DEFINE_MUTEX(mutex_X1);
static DEFINE_MUTEX(mutex_X2);
static DEFINE_MUTEX(mutex_Y1);
static DEFINE_MUTEX(mutex_Y2);
static DEFINE_MUTEX(mutex_Z1);
static DEFINE_MUTEX(mutex_Z2);
static DECLARE_RWSEM(rwsem_X1);
static DECLARE_RWSEM(rwsem_X2);
static DECLARE_RWSEM(rwsem_Y1);
static DECLARE_RWSEM(rwsem_Y2);
static DECLARE_RWSEM(rwsem_Z1);
static DECLARE_RWSEM(rwsem_Z2);
/*
* non-inlined runtime initializers, to let separate locks share
* the same lock-class:
*/
#define INIT_CLASS_FUNC(class) \
static noinline void \
init_class_##class(spinlock_t *lock, rwlock_t *rwlock, struct mutex *mutex, \
struct rw_semaphore *rwsem) \
{ \
spin_lock_init(lock); \
rwlock_init(rwlock); \
mutex_init(mutex); \
init_rwsem(rwsem); \
}
INIT_CLASS_FUNC(X)
INIT_CLASS_FUNC(Y)
INIT_CLASS_FUNC(Z)
static void init_shared_classes(void)
{
init_class_X(&lock_X1, &rwlock_X1, &mutex_X1, &rwsem_X1);
init_class_X(&lock_X2, &rwlock_X2, &mutex_X2, &rwsem_X2);
init_class_Y(&lock_Y1, &rwlock_Y1, &mutex_Y1, &rwsem_Y1);
init_class_Y(&lock_Y2, &rwlock_Y2, &mutex_Y2, &rwsem_Y2);
init_class_Z(&lock_Z1, &rwlock_Z1, &mutex_Z1, &rwsem_Z1);
init_class_Z(&lock_Z2, &rwlock_Z2, &mutex_Z2, &rwsem_Z2);
}
/*
* For spinlocks and rwlocks we also do hardirq-safe / softirq-safe tests.
* The following functions use a lock from a simulated hardirq/softirq
* context, causing the locks to be marked as hardirq-safe/softirq-safe:
*/
#define HARDIRQ_DISABLE local_irq_disable
#define HARDIRQ_ENABLE local_irq_enable
#define HARDIRQ_ENTER() \
local_irq_disable(); \
irq_enter(); \
WARN_ON(!in_irq());
#define HARDIRQ_EXIT() \
__irq_exit(); \
local_irq_enable();
#define SOFTIRQ_DISABLE local_bh_disable
#define SOFTIRQ_ENABLE local_bh_enable
#define SOFTIRQ_ENTER() \
local_bh_disable(); \
local_irq_disable(); \
trace_softirq_enter(); \
WARN_ON(!in_softirq());
#define SOFTIRQ_EXIT() \
trace_softirq_exit(); \
local_irq_enable(); \
local_bh_enable();
/*
* Shortcuts for lock/unlock API variants, to keep
* the testcases compact:
*/
#define L(x) spin_lock(&lock_##x)
#define U(x) spin_unlock(&lock_##x)
#define LU(x) L(x); U(x)
#define SI(x) spin_lock_init(&lock_##x)
#define WL(x) write_lock(&rwlock_##x)
#define WU(x) write_unlock(&rwlock_##x)
#define WLU(x) WL(x); WU(x)
#define RL(x) read_lock(&rwlock_##x)
#define RU(x) read_unlock(&rwlock_##x)
#define RLU(x) RL(x); RU(x)
#define RWI(x) rwlock_init(&rwlock_##x)
#define ML(x) mutex_lock(&mutex_##x)
#define MU(x) mutex_unlock(&mutex_##x)
#define MI(x) mutex_init(&mutex_##x)
#define WSL(x) down_write(&rwsem_##x)
#define WSU(x) up_write(&rwsem_##x)
#define RSL(x) down_read(&rwsem_##x)
#define RSU(x) up_read(&rwsem_##x)
#define RWSI(x) init_rwsem(&rwsem_##x)
#define LOCK_UNLOCK_2(x,y) LOCK(x); LOCK(y); UNLOCK(y); UNLOCK(x)
/*
* Generate different permutations of the same testcase, using
* the same basic lock-dependency/state events:
*/
#define GENERATE_TESTCASE(name) \
\
static void name(void) { E(); }
#define GENERATE_PERMUTATIONS_2_EVENTS(name) \
\
static void name##_12(void) { E1(); E2(); } \
static void name##_21(void) { E2(); E1(); }
#define GENERATE_PERMUTATIONS_3_EVENTS(name) \
\
static void name##_123(void) { E1(); E2(); E3(); } \
static void name##_132(void) { E1(); E3(); E2(); } \
static void name##_213(void) { E2(); E1(); E3(); } \
static void name##_231(void) { E2(); E3(); E1(); } \
static void name##_312(void) { E3(); E1(); E2(); } \
static void name##_321(void) { E3(); E2(); E1(); }
/*
* AA deadlock:
*/
#define E() \
\
LOCK(X1); \
LOCK(X2); /* this one should fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(AA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(AA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(AA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(AA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(AA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(AA_rsem)
#undef E
/*
* Special-case for read-locking, they are
* allowed to recurse on the same lock instance:
*/
static void rlock_AA1(void)
{
RL(X1);
RL(X1); // this one should NOT fail
}
static void rlock_AA1B(void)
{
RL(X1);
RL(X2); // this one should fail
}
static void rsem_AA1(void)
{
RSL(X1);
RSL(X1); // this one should fail
}
static void rsem_AA1B(void)
{
RSL(X1);
RSL(X2); // this one should fail
}
/*
* The mixing of read and write locks is not allowed:
*/
static void rlock_AA2(void)
{
RL(X1);
WL(X2); // this one should fail
}
static void rsem_AA2(void)
{
RSL(X1);
WSL(X2); // this one should fail
}
static void rlock_AA3(void)
{
WL(X1);
RL(X2); // this one should fail
}
static void rsem_AA3(void)
{
WSL(X1);
RSL(X2); // this one should fail
}
/*
* ABBA deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(B, A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBA_rsem)
#undef E
/*
* AB BC CA deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(B, C); \
LOCK_UNLOCK_2(C, A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBCCA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBCCA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBCCA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBCCA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBCCA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBCCA_rsem)
#undef E
/*
* AB CA BC deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(C, A); \
LOCK_UNLOCK_2(B, C); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCABC_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCABC_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCABC_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCABC_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCABC_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCABC_rsem)
#undef E
/*
* AB BC CD DA deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(B, C); \
LOCK_UNLOCK_2(C, D); \
LOCK_UNLOCK_2(D, A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABBCCDDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABBCCDDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABBCCDDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABBCCDDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABBCCDDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABBCCDDA_rsem)
#undef E
/*
* AB CD BD DA deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(C, D); \
LOCK_UNLOCK_2(B, D); \
LOCK_UNLOCK_2(D, A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCDBDDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCDBDDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCDBDDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCDBDDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCDBDDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCDBDDA_rsem)
#undef E
/*
* AB CD BC DA deadlock:
*/
#define E() \
\
LOCK_UNLOCK_2(A, B); \
LOCK_UNLOCK_2(C, D); \
LOCK_UNLOCK_2(B, C); \
LOCK_UNLOCK_2(D, A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(ABCDBCDA_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(ABCDBCDA_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(ABCDBCDA_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(ABCDBCDA_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(ABCDBCDA_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(ABCDBCDA_rsem)
#undef E
/*
* Double unlock:
*/
#define E() \
\
LOCK(A); \
UNLOCK(A); \
UNLOCK(A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(double_unlock_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(double_unlock_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(double_unlock_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(double_unlock_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(double_unlock_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(double_unlock_rsem)
#undef E
/*
* Bad unlock ordering:
*/
#define E() \
\
LOCK(A); \
LOCK(B); \
UNLOCK(A); /* fail */ \
UNLOCK(B);
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(bad_unlock_order_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(bad_unlock_order_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(bad_unlock_order_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(bad_unlock_order_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(bad_unlock_order_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(bad_unlock_order_rsem)
#undef E
/*
* initializing a held lock:
*/
#define E() \
\
LOCK(A); \
INIT(A); /* fail */
/*
* 6 testcases:
*/
#include "locking-selftest-spin.h"
GENERATE_TESTCASE(init_held_spin)
#include "locking-selftest-wlock.h"
GENERATE_TESTCASE(init_held_wlock)
#include "locking-selftest-rlock.h"
GENERATE_TESTCASE(init_held_rlock)
#include "locking-selftest-mutex.h"
GENERATE_TESTCASE(init_held_mutex)
#include "locking-selftest-wsem.h"
GENERATE_TESTCASE(init_held_wsem)
#include "locking-selftest-rsem.h"
GENERATE_TESTCASE(init_held_rsem)
#undef E
/*
* locking an irq-safe lock with irqs enabled:
*/
#define E1() \
\
IRQ_ENTER(); \
LOCK(A); \
UNLOCK(A); \
IRQ_EXIT();
#define E2() \
\
LOCK(A); \
UNLOCK(A);
/*
* Generate 24 testcases:
*/
#include "locking-selftest-spin-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_spin)
#include "locking-selftest-rlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_rlock)
#include "locking-selftest-wlock-hardirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_hard_wlock)
#include "locking-selftest-spin-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_spin)
#include "locking-selftest-rlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_rlock)
#include "locking-selftest-wlock-softirq.h"
GENERATE_PERMUTATIONS_2_EVENTS(irqsafe1_soft_wlock)
#undef E1
#undef E2