* [PATCH v2 2/7] liblockdep: public headers for mutex implementation
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-01 16:47 ` [PATCH v2 3/7] liblockdep: mutex test suite Sasha Levin
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
These headers provide the same API as their pthread mutex counterparts.
The design here is to allow to easily switch to liblockdep lock validation
just by adding a "liblockdep_" to pthread_mutex_*() calls, which means that
it's easy to integrate liblockdep into existing codebases.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
tools/lib/lockdep/include/liblockdep/common.h | 42 +++++++++++++++
tools/lib/lockdep/include/liblockdep/mutex.h | 73 +++++++++++++++++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 tools/lib/lockdep/include/liblockdep/common.h
create mode 100644 tools/lib/lockdep/include/liblockdep/mutex.h
diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h
new file mode 100644
index 0000000..b72f9c1
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/common.h
@@ -0,0 +1,42 @@
+#ifndef _LIBLOCKDEP_COMMON_H
+#define _LIBLOCKDEP_COMMON_H
+
+#include <pthread.h>
+
+#define CALLER_ADDR0 (__builtin_return_address(0))
+#define _THIS_IP_ CALLER_ADDR0
+#define NR_LOCKDEP_CACHING_CLASSES 2
+#define MAX_LOCKDEP_SUBCLASSES 8UL
+
+struct lockdep_subclass_key {
+ char __one_byte;
+};
+
+struct lock_class_key {
+ struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES];
+};
+
+struct lockdep_map {
+ struct lock_class_key *key;
+ struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES];
+ const char *name;
+#ifdef CONFIG_LOCK_STAT
+ int cpu;
+ unsigned long ip;
+#endif
+};
+
+void liblockdep_init(void);
+void liblockdep_set_thread(void);
+void lockdep_init_map(struct lockdep_map *lock, const char *name,
+ struct lock_class_key *key, int subclass);
+void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
+ int trylock, int read, int check,
+ struct lockdep_map *nest_lock, unsigned long ip);
+void lock_release(struct lockdep_map *lock, int nested,
+ unsigned long ip);
+
+#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
+ { .name = (_name), .key = (void *)(_key), }
+
+#endif
diff --git a/tools/lib/lockdep/include/liblockdep/mutex.h b/tools/lib/lockdep/include/liblockdep/mutex.h
new file mode 100644
index 0000000..5154a9d
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/mutex.h
@@ -0,0 +1,73 @@
+#ifndef _LIBLOCKDEP_MUTEX_H
+#define _LIBLOCKDEP_MUTEX_H
+
+#ifdef __USE_LIBLOCKDEP
+
+#include <pthread.h>
+#include "common.h"
+
+struct liblockdep_pthread_mutex {
+ pthread_mutex_t mutex;
+ struct lockdep_map dep_map;
+};
+
+typedef struct liblockdep_pthread_mutex liblockdep_pthread_mutex_t;
+
+#define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx) \
+ (const struct liblockdep_pthread_mutex) { \
+ .mutex = PTHREAD_MUTEX_INITIALIZER, \
+ .dep_map = STATIC_LOCKDEP_MAP_INIT(#mtx, &((&(mtx))->dep_map)), \
+}
+
+static inline int __mutex_init(liblockdep_pthread_mutex_t *lock,
+ const char *name,
+ struct lock_class_key *key,
+ const pthread_mutexattr_t *__mutexattr)
+{
+ lockdep_init_map(&lock->dep_map, name, key, 0);
+ return pthread_mutex_init(&lock->mutex, __mutexattr);
+}
+
+#define liblockdep_pthread_mutex_init(mutex, mutexattr) \
+({ \
+ static struct lock_class_key __key; \
+ \
+ __mutex_init((mutex), #mutex, &__key, (mutexattr)); \
+})
+
+static inline int liblockdep_pthread_mutex_lock(liblockdep_pthread_mutex_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)ip);
+ return pthread_mutex_lock(&lock->mutex);
+}
+
+static inline int liblockdep_pthread_mutex_unlock(liblockdep_pthread_mutex_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_release(&lock->dep_map, 0, (unsigned long)ip);
+ return pthread_mutex_unlock(&lock->mutex);
+}
+
+static inline int liblockdep_pthread_mutex_trylock(liblockdep_pthread_mutex_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)ip);
+ return pthread_mutex_trylock(&lock->mutex) == 0 ? 1 : 0;
+}
+
+static inline int liblockdep_pthread_mutex_destroy(liblockdep_pthread_mutex_t *lock)
+{
+ return pthread_mutex_destroy(&lock->mutex);
+}
+
+#define pthread_mutex_t liblockdep_pthread_mutex_t
+#define pthread_mutex_init liblockdep_pthread_mutex_init
+#define pthread_mutex_lock liblockdep_pthread_mutex_lock
+#define pthread_mutex_unlock liblockdep_pthread_mutex_unlock
+#define pthread_mutex_trylock liblockdep_pthread_mutex_trylock
+#define pthread_mutex_destroy liblockdep_pthread_mutex_destroy
+
+#endif
+
+#endif
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 3/7] liblockdep: mutex test suite
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
2013-02-01 16:47 ` [PATCH v2 2/7] liblockdep: public headers for mutex implementation Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-01 16:47 ` [PATCH v2 4/7] liblockdep: public headers for rwlock implementation Sasha Levin
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
This is a rather simple and basic test suite to test common locking
issues.
Beyond tests, it also shows how to use the library.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
tools/lib/lockdep/run_tests.sh | 15 +++++++++++++++
tools/lib/lockdep/tests/AA.c | 16 ++++++++++++++++
tools/lib/lockdep/tests/ABBA.c | 16 ++++++++++++++++
tools/lib/lockdep/tests/ABBCCA.c | 18 ++++++++++++++++++
tools/lib/lockdep/tests/ABBCCDDA.c | 20 ++++++++++++++++++++
tools/lib/lockdep/tests/ABCABC.c | 18 ++++++++++++++++++
tools/lib/lockdep/tests/ABCDBCDA.c | 20 ++++++++++++++++++++
tools/lib/lockdep/tests/ABCDBDDA.c | 20 ++++++++++++++++++++
tools/lib/lockdep/tests/common.h | 12 ++++++++++++
tools/lib/lockdep/tests/unlock_balance.c | 15 +++++++++++++++
10 files changed, 170 insertions(+)
create mode 100755 tools/lib/lockdep/run_tests.sh
create mode 100644 tools/lib/lockdep/tests/AA.c
create mode 100644 tools/lib/lockdep/tests/ABBA.c
create mode 100644 tools/lib/lockdep/tests/ABBCCA.c
create mode 100644 tools/lib/lockdep/tests/ABBCCDDA.c
create mode 100644 tools/lib/lockdep/tests/ABCABC.c
create mode 100644 tools/lib/lockdep/tests/ABCDBCDA.c
create mode 100644 tools/lib/lockdep/tests/ABCDBDDA.c
create mode 100644 tools/lib/lockdep/tests/common.h
create mode 100644 tools/lib/lockdep/tests/unlock_balance.c
diff --git a/tools/lib/lockdep/run_tests.sh b/tools/lib/lockdep/run_tests.sh
new file mode 100755
index 0000000..4dd32d1
--- /dev/null
+++ b/tools/lib/lockdep/run_tests.sh
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+make &> /dev/null
+
+for i in `ls tests/*.c`; do
+ testname=$(basename -s .c "$i")
+ gcc -o tests/$testname -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null
+ echo -ne "$testname... "
+ if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then
+ echo "PASSED!"
+ else
+ echo "FAILED!"
+ fi
+ rm tests/$testname
+done
diff --git a/tools/lib/lockdep/tests/AA.c b/tools/lib/lockdep/tests/AA.c
new file mode 100644
index 0000000..933d32f
--- /dev/null
+++ b/tools/lib/lockdep/tests/AA.c
@@ -0,0 +1,16 @@
+#include <liblockdep/mutex.h>
+
+void main(void)
+{
+ pthread_mutex_t a, b;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+
+ pthread_mutex_lock(&a);
+ pthread_mutex_unlock(&b);
+ pthread_mutex_lock(&a);
+}
diff --git a/tools/lib/lockdep/tests/ABBA.c b/tools/lib/lockdep/tests/ABBA.c
new file mode 100644
index 0000000..9f5146b
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBA.c
@@ -0,0 +1,16 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ pthread_mutex_t a, b;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(b, a);
+}
diff --git a/tools/lib/lockdep/tests/ABBCCA.c b/tools/lib/lockdep/tests/ABBCCA.c
new file mode 100644
index 0000000..b7435d7
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBCCA.c
@@ -0,0 +1,18 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ pthread_mutex_t a, b, c;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+ pthread_mutex_init(&c, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(b, c);
+ LOCK_UNLOCK_2(c, a);
+}
diff --git a/tools/lib/lockdep/tests/ABBCCDDA.c b/tools/lib/lockdep/tests/ABBCCDDA.c
new file mode 100644
index 0000000..2425330
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABBCCDDA.c
@@ -0,0 +1,20 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ pthread_mutex_t a, b, c, d;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+ pthread_mutex_init(&c, NULL);
+ pthread_mutex_init(&d, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(b, c);
+ LOCK_UNLOCK_2(c, d);
+ LOCK_UNLOCK_2(d, a);
+}
diff --git a/tools/lib/lockdep/tests/ABCABC.c b/tools/lib/lockdep/tests/ABCABC.c
new file mode 100644
index 0000000..2ee30fe
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCABC.c
@@ -0,0 +1,18 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ pthread_mutex_t a, b, c;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+ pthread_mutex_init(&c, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(c, a);
+ LOCK_UNLOCK_2(b, c);
+}
diff --git a/tools/lib/lockdep/tests/ABCDBCDA.c b/tools/lib/lockdep/tests/ABCDBCDA.c
new file mode 100644
index 0000000..32d19d6
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCDBCDA.c
@@ -0,0 +1,20 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ liblockdep_pthread_mutex_t a, b, c, d;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ liblockdep_pthread_mutex_init(&a, NULL);
+ liblockdep_pthread_mutex_init(&b, NULL);
+ liblockdep_pthread_mutex_init(&c, NULL);
+ liblockdep_pthread_mutex_init(&d, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(c, d);
+ LOCK_UNLOCK_2(b, c);
+ LOCK_UNLOCK_2(d, a);
+}
diff --git a/tools/lib/lockdep/tests/ABCDBDDA.c b/tools/lib/lockdep/tests/ABCDBDDA.c
new file mode 100644
index 0000000..850eaca
--- /dev/null
+++ b/tools/lib/lockdep/tests/ABCDBDDA.c
@@ -0,0 +1,20 @@
+#include <liblockdep/mutex.h>
+#include "common.h"
+
+void main(void)
+{
+ pthread_mutex_t a, b, c, d;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+ pthread_mutex_init(&b, NULL);
+ pthread_mutex_init(&c, NULL);
+ pthread_mutex_init(&d, NULL);
+
+ LOCK_UNLOCK_2(a, b);
+ LOCK_UNLOCK_2(c, d);
+ LOCK_UNLOCK_2(b, d);
+ LOCK_UNLOCK_2(d, a);
+}
diff --git a/tools/lib/lockdep/tests/common.h b/tools/lib/lockdep/tests/common.h
new file mode 100644
index 0000000..d89e94d
--- /dev/null
+++ b/tools/lib/lockdep/tests/common.h
@@ -0,0 +1,12 @@
+#ifndef _LIBLOCKDEP_TEST_COMMON_H
+#define _LIBLOCKDEP_TEST_COMMON_H
+
+#define LOCK_UNLOCK_2(a, b) \
+ do { \
+ pthread_mutex_lock(&(a)); \
+ pthread_mutex_lock(&(b)); \
+ pthread_mutex_unlock(&(b)); \
+ pthread_mutex_unlock(&(a)); \
+ } while(0)
+
+#endif
diff --git a/tools/lib/lockdep/tests/unlock_balance.c b/tools/lib/lockdep/tests/unlock_balance.c
new file mode 100644
index 0000000..9dfaf97
--- /dev/null
+++ b/tools/lib/lockdep/tests/unlock_balance.c
@@ -0,0 +1,15 @@
+#include <liblockdep/mutex.h>
+
+void main(void)
+{
+ pthread_mutex_t a;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_mutex_init(&a, NULL);
+
+ pthread_mutex_lock(&a);
+ pthread_mutex_unlock(&a);
+ pthread_mutex_unlock(&a);
+}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 4/7] liblockdep: public headers for rwlock implementation
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
2013-02-01 16:47 ` [PATCH v2 2/7] liblockdep: public headers for mutex implementation Sasha Levin
2013-02-01 16:47 ` [PATCH v2 3/7] liblockdep: mutex test suite Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-01 16:47 ` [PATCH v2 5/7] liblockdep: rwlock test suite Sasha Levin
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
Both pthreads and lockdep support dealing with rwlocks, so here's the
liblockdep implementation for those.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
tools/lib/lockdep/include/liblockdep/rwlock.h | 91 +++++++++++++++++++++++++++
1 file changed, 91 insertions(+)
create mode 100644 tools/lib/lockdep/include/liblockdep/rwlock.h
diff --git a/tools/lib/lockdep/include/liblockdep/rwlock.h b/tools/lib/lockdep/include/liblockdep/rwlock.h
new file mode 100644
index 0000000..26f9a68
--- /dev/null
+++ b/tools/lib/lockdep/include/liblockdep/rwlock.h
@@ -0,0 +1,91 @@
+#ifndef _LIBLOCKDEP_RWLOCK_H
+#define _LIBLOCKDEP_RWLOCK_H
+
+#ifdef __USE_LIBLOCKDEP
+
+#include <pthread.h>
+#include "common.h"
+
+struct liblockdep_pthread_rwlock {
+ pthread_rwlock_t rwlock;
+ struct lockdep_map dep_map;
+};
+
+typedef struct liblockdep_pthread_rwlock liblockdep_pthread_rwlock_t;
+
+#define LIBLOCKDEP_PTHREAD_RWLOCK_INITIALIZER(rwl) \
+ (struct liblockdep_pthread_rwlock) { \
+ .rwlock = PTHREAD_RWLOCK_INITIALIZER, \
+ .dep_map = STATIC_LOCKDEP_MAP_INIT(#rwl, &((&(rwl))->dep_map)), \
+}
+
+static inline int __rwlock_init(liblockdep_pthread_rwlock_t *lock,
+ const char *name,
+ struct lock_class_key *key,
+ const pthread_rwlockattr_t *attr)
+{
+ lockdep_init_map(&lock->dep_map, name, key, 0);
+
+ return pthread_rwlock_init(&lock->rwlock, attr);
+}
+
+#define liblockdep_pthread_rwlock_init(lock, attr) \
+({ \
+ static struct lock_class_key __key; \
+ \
+ __rwlock_init((lock), #lock, &__key, (attr)); \
+})
+
+static inline int liblockdep_pthread_rwlock_rdlock(liblockdep_pthread_rwlock_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 0, 2, 2, NULL, (unsigned long)ip);
+ return pthread_rwlock_rdlock(&lock->rwlock);
+
+}
+
+static inline int liblockdep_pthread_rwlock_unlock(liblockdep_pthread_rwlock_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_release(&lock->dep_map, 0, (unsigned long)ip);
+ return pthread_rwlock_unlock(&lock->rwlock);
+}
+
+static inline int liblockdep_pthread_rwlock_wrlock(liblockdep_pthread_rwlock_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 0, 0, 2, NULL, (unsigned long)ip);
+ return pthread_rwlock_wrlock(&lock->rwlock);
+}
+
+static inline int liblockdep_pthread_rwlock_tryrdlock(liblockdep_pthread_rwlock_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 1, 2, 2, NULL, (unsigned long)ip);
+ return pthread_rwlock_tryrdlock(&lock->rwlock) == 0 ? 1 : 0;
+}
+
+static inline int liblockdep_pthread_rwlock_trywlock(liblockdep_pthread_rwlock_t *lock)
+{
+ void *ip = _THIS_IP_;
+ lock_acquire(&lock->dep_map, 0, 1, 0, 2, NULL, (unsigned long)ip);
+ return pthread_rwlock_trywlock(&lock->rwlock) == 0 ? 1 : 0;
+}
+
+static inline int liblockdep_rwlock_destroy(liblockdep_pthread_rwlock_t *lock)
+{
+ return pthread_rwlock_destroy(&lock->rwlock);
+}
+
+#define pthread_rwlock_t liblockdep_pthread_rwlock_t
+#define pthread_rwlock_init liblockdep_pthread_rwlock_init
+#define pthread_rwlock_rdlock liblockdep_pthread_rwlock_rdlock
+#define pthread_rwlock_unlock liblockdep_pthread_rwlock_unlock
+#define pthread_rwlock_wrlock liblockdep_pthread_rwlock_wrlock
+#define pthread_rwlock_tryrdlock liblockdep_pthread_rwlock_tryrdlock
+#define pthread_rwlock_trywlock liblockdep_pthread_rwlock_trywlock
+#define pthread_rwlock_destroy liblockdep_rwlock_destroy
+
+#endif
+
+#endif
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 5/7] liblockdep: rwlock test suite
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
` (2 preceding siblings ...)
2013-02-01 16:47 ` [PATCH v2 4/7] liblockdep: public headers for rwlock implementation Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-01 16:47 ` [PATCH v2 6/7] liblockdep: add a MAINTAINERS entry Sasha Levin
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
A simple test to make sure we handle rwlocks correctly.
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
tools/lib/lockdep/tests/WW.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
create mode 100644 tools/lib/lockdep/tests/WW.c
diff --git a/tools/lib/lockdep/tests/WW.c b/tools/lib/lockdep/tests/WW.c
new file mode 100644
index 0000000..4b1be0f
--- /dev/null
+++ b/tools/lib/lockdep/tests/WW.c
@@ -0,0 +1,16 @@
+#include <liblockdep/rwlock.h>
+
+void main(void)
+{
+ pthread_rwlock_t a, b;
+
+ liblockdep_init();
+ liblockdep_set_thread();
+
+ pthread_rwlock_init(&a, NULL);
+ pthread_rwlock_init(&b, NULL);
+
+ pthread_rwlock_wrlock(&a);
+ pthread_rwlock_rdlock(&b);
+ pthread_rwlock_wrlock(&a);
+}
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 6/7] liblockdep: add a MAINTAINERS entry
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
` (3 preceding siblings ...)
2013-02-01 16:47 ` [PATCH v2 5/7] liblockdep: rwlock test suite Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-01 16:47 ` [PATCH v2 7/7] perf: integrate liblockdep support into perf Sasha Levin
2013-02-03 11:04 ` [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Ingo Molnar
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
MAINTAINERS | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 212c255..a64abfb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4637,6 +4637,11 @@ F: drivers/lguest/
F: include/linux/lguest*.h
F: tools/lguest/
+LIBLOCK
+M: Sasha Levin <sasha.levin@oracle.com>
+S: Maintained
+F: tools/lib/lockdep/
+
LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <paulus@au.ibm.com>
W: http://www.ibm.com/linux/ltc/projects/ppc
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v2 7/7] perf: integrate liblockdep support into perf
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
` (4 preceding siblings ...)
2013-02-01 16:47 ` [PATCH v2 6/7] liblockdep: add a MAINTAINERS entry Sasha Levin
@ 2013-02-01 16:47 ` Sasha Levin
2013-02-03 11:04 ` [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Ingo Molnar
6 siblings, 0 replies; 10+ messages in thread
From: Sasha Levin @ 2013-02-01 16:47 UTC (permalink / raw)
To: mingo, peterz; +Cc: paulus, acme, penberg, linux-kernel, Sasha Levin
liblockdep is simply userspace lockdep. We can use that to analyze and
verify the locking in perf.
Usage is simple, to compile perf with liblockdep all that's needed it:
make LIBLOCK=[path to liblockdep]
Once liblockdep support is compiled in, perf will yell if locking goes
wrong for any reason:
=============================================
[ INFO: possible recursive locking detected ]
liblockdep 0.0.1
---------------------------------------------
perf/23237 is trying to acquire lock:
(sched.start_work_mutex){......}, at: ./perf() [0x419793]
but task is already holding lock:
(sched.start_work_mutex){......}, at: ./perf() [0x419793]
other info that might help us debug this:
Possible unsafe locking scenario:
CPU0
----
lock(sched.start_work_mutex);
lock(sched.start_work_mutex);
*** DEADLOCK ***
May be due to missing lock nesting notation
2 locks held by perf/23237:
#0: (sched.start_work_mutex){......}, at: ./perf() [0x419793]
#1: (sched.work_done_wait_mutex){......}, at: ./perf() [0x419793]
stack backtrace:
/usr/lib64/liblockdep.so(+0x1ba0)[0x7fa067f99ba0]
/usr/lib64/liblockdep.so(+0x37bf)[0x7fa067f9b7bf]
/usr/lib64/liblockdep.so(+0x3899)[0x7fa067f9b899]
/usr/lib64/liblockdep.so(+0x429a)[0x7fa067f9c29a]
/usr/lib64/liblockdep.so(+0x4db1)[0x7fa067f9cdb1]
/usr/lib64/liblockdep.so(lock_acquire+0x97)[0x7fa067f9d8b4]
./perf(cmd_sched+0xb166)[0x42d976]
./perf[0x419793]
./perf(main+0x529)[0x418f59]
/lib64/libc.so.6(__libc_start_main+0xed)[0x7fa063ae591d]
./perf[0x4190d9]
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
---
tools/perf/Makefile | 22 ++++++++++++++++++++++
tools/perf/builtin-sched.c | 6 ++++--
tools/perf/builtin-top.c | 4 ++++
tools/perf/config/feature-tests.mak | 12 ++++++++++++
tools/perf/perf.c | 3 +++
tools/perf/ui/setup.c | 5 ++++-
tools/perf/util/hist.h | 1 +
tools/perf/util/liblockdep.h | 11 +++++++++++
tools/perf/util/util.h | 1 +
9 files changed, 62 insertions(+), 3 deletions(-)
create mode 100644 tools/perf/util/liblockdep.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 8ab05e5..994329d 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -572,6 +572,21 @@ ifneq ($(call try-cc,$(SOURCE_LIBUNWIND),$(FLAGS_UNWIND),libunwind),y)
endif # Libunwind support
endif # NO_LIBUNWIND
+ifndef NO_LIBLOCKDEP
+# for linking with liblockdep library, run like:
+# make DEBUG=1 LIBLOCK_DIR=/path/to/linux.git/tools/lib/lockdep/
+ifdef LIBLOCKDEP_DIR
+ LIBLOCKDEP_CFLAGS := -I$(LIBLOCKDEP_DIR)/include -D__USE_LIBLOCKDEP
+ LIBLOCKDEP_LDFLAGS := -L$(LIBLOCKDEP_DIR)/ -llockdep
+endif
+
+FLAGS_LIBLOCKDEP=$(LIBLOCKDEP_CFLAGS) $(ALL_CFLAGS) $(LIBLOCKDEP_LDFLAGS) $(ALL_LDFLAGS) $(EXTLIBS)
+ifneq ($(call try-cc,$(SOURCE_LIBLOCKDEP),$(FLAGS_LIBLOCKDEP),liblockdep),y)
+ msg := $(warning No liblockdep found.);
+ NO_LIBLOCKDEP := 1
+endif # liblockdep support
+endif # NO_LIBLOCKDEP
+
-include arch/$(ARCH)/Makefile
ifneq ($(OUTPUT),)
@@ -621,6 +636,13 @@ ifndef NO_LIBUNWIND
LIB_OBJS += $(OUTPUT)util/unwind.o
endif
+ifndef NO_LIBLOCKDEP
+ BASIC_CFLAGS += -D__USE_LIBLOCKDEP
+ EXTLIBS += $(LIBLOCKDEP_LIBS)
+ BASIC_CFLAGS := $(LIBLOCKDEP_CFLAGS) $(BASIC_CFLAGS)
+ BASIC_LDFLAGS := $(LIBLOCKDEP_LDFLAGS) $(BASIC_LDFLAGS)
+endif
+
ifndef NO_LIBAUDIT
FLAGS_LIBAUDIT = $(ALL_CFLAGS) $(ALL_LDFLAGS) -laudit
ifneq ($(call try-cc,$(SOURCE_LIBAUDIT),$(FLAGS_LIBAUDIT),libaudit),y)
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index cc28b85..53d9225 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -468,6 +468,8 @@ static void *thread_func(void *ctx)
char comm2[22];
int fd;
+ liblockdep_set_thread();
+
free(parms);
sprintf(comm2, ":%s", this_task->comm);
@@ -1677,8 +1679,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
},
.cmp_pid = LIST_HEAD_INIT(sched.cmp_pid),
.sort_list = LIST_HEAD_INIT(sched.sort_list),
- .start_work_mutex = PTHREAD_MUTEX_INITIALIZER,
- .work_done_wait_mutex = PTHREAD_MUTEX_INITIALIZER,
+ .start_work_mutex = LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(sched.start_work_mutex),
+ .work_done_wait_mutex = LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(sched.work_done_wait_mutex),
.curr_pid = { [0 ... MAX_CPUS - 1] = -1 },
.sort_order = default_sort_order,
.replay_repeat = 10,
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index c9ff395..c9b99ef 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -588,6 +588,8 @@ static void *display_thread_tui(void *arg)
.refresh = top->delay_secs,
};
+ liblockdep_set_thread();
+
perf_top__sort_new_samples(top);
/*
@@ -613,6 +615,8 @@ static void *display_thread(void *arg)
struct perf_top *top = arg;
int delay_msecs, c;
+ liblockdep_set_thread();
+
tcgetattr(0, &save);
tc = save;
tc.c_lflag &= ~(ICANON | ECHO);
diff --git a/tools/perf/config/feature-tests.mak b/tools/perf/config/feature-tests.mak
index f5ac774..1f5a37e 100644
--- a/tools/perf/config/feature-tests.mak
+++ b/tools/perf/config/feature-tests.mak
@@ -217,6 +217,18 @@ int main(void)
endef
endif
+ifndef NO_LIBLOCKDEP
+define SOURCE_LIBLOCKDEP
+#include <liblockdep/mutex.h>
+
+int main(void)
+{
+ liblockdep_init();
+ return 0;
+}
+endef
+endif
+
define SOURCE_ON_EXIT
#include <stdio.h>
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 0f661fb..ddbd315 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -446,6 +446,9 @@ int main(int argc, const char **argv)
{
const char *cmd;
+ liblockdep_init();
+ liblockdep_set_thread();
+
page_size = sysconf(_SC_PAGE_SIZE);
cmd = perf_extract_argv0_path(argv[0]);
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c
index ebb4cc1..5c0cdeb 100644
--- a/tools/perf/ui/setup.c
+++ b/tools/perf/ui/setup.c
@@ -3,14 +3,17 @@
#include "../util/cache.h"
#include "../util/debug.h"
#include "../util/hist.h"
+#include "../util/liblockdep.h"
-pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t ui__lock;
void setup_browser(bool fallback_to_pager)
{
if (!isatty(1) || dump_trace)
use_browser = 0;
+ pthread_mutex_init(&ui__lock, NULL);
+
/* default to TUI */
if (use_browser < 0)
use_browser = 1;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 8b091a5..328afe0 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -5,6 +5,7 @@
#include <pthread.h>
#include "callchain.h"
#include "header.h"
+#include "liblockdep.h"
extern struct callchain_param callchain_param;
diff --git a/tools/perf/util/liblockdep.h b/tools/perf/util/liblockdep.h
new file mode 100644
index 0000000..a996259
--- /dev/null
+++ b/tools/perf/util/liblockdep.h
@@ -0,0 +1,11 @@
+#ifdef __USE_LIBLOCKDEP
+
+#include <liblockdep/mutex.h>
+
+#else
+#error WHAT?!
+#define LIBLOCKDEP_PTHREAD_MUTEX_INITIALIZER(mtx) PTHREAD_MUTEX_INITIALIZER
+#define liblockdep_init()
+#define liblockdep_set_thread()
+
+#endif
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index c233091..06e6244 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -73,6 +73,7 @@
#include <linux/magic.h>
#include "types.h"
#include <sys/ttydefaults.h>
+#include "liblockdep.h"
extern const char *graph_line;
extern const char *graph_dotted_line;
--
1.8.1.2
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace
2013-02-01 16:47 [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Sasha Levin
` (5 preceding siblings ...)
2013-02-01 16:47 ` [PATCH v2 7/7] perf: integrate liblockdep support into perf Sasha Levin
@ 2013-02-03 11:04 ` Ingo Molnar
2013-02-03 16:19 ` Sasha Levin
6 siblings, 1 reply; 10+ messages in thread
From: Ingo Molnar @ 2013-02-03 11:04 UTC (permalink / raw)
To: Sasha Levin; +Cc: mingo, peterz, paulus, acme, penberg, linux-kernel
So I applied your patches and did:
cd tools/lib/lockdep
make
and got:
comet:~/tip/tools/lib/lockdep> make
CC FPIC common.o
In file included from ./uinclude/linux/lockdep.h:13:0,
from
/fast/mingo/tip/tools/lib/lockdep/common.c:4:
./../../../include/linux/lockdep.h:21:27: fatal error: linux/linkage.h: No such file or directory
compilation terminated.
make: *** [common.o] Error 1
Thanks,
Ingo
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace
2013-02-03 11:04 ` [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace Ingo Molnar
@ 2013-02-03 16:19 ` Sasha Levin
2013-02-03 19:10 ` Ingo Molnar
0 siblings, 1 reply; 10+ messages in thread
From: Sasha Levin @ 2013-02-03 16:19 UTC (permalink / raw)
To: Ingo Molnar; +Cc: mingo, peterz, paulus, acme, penberg, linux-kernel
On 02/03/2013 06:04 AM, Ingo Molnar wrote:
>
> So I applied your patches and did:
>
> cd tools/lib/lockdep
> make
>
> and got:
>
> comet:~/tip/tools/lib/lockdep> make
> CC FPIC common.o
> In file included from ./uinclude/linux/lockdep.h:13:0,
> from
> /fast/mingo/tip/tools/lib/lockdep/common.c:4:
> ./../../../include/linux/lockdep.h:21:27: fatal error: linux/linkage.h: No such file or directory
> compilation terminated.
> make: *** [common.o] Error 1
That's odd, uinclude/linux/linkage.h is an empty file which is needed there just
so gcc won't complain (like it did in the example above).
Can you please verify that uinclude/linux/linkage.h actually exists after you've
applied the patches? If it does, I'm not really sure why it's not getting found.
Thanks,
Sasha
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/7] liblockdep: wrap kernel/lockdep.c to allow usage from userspace
2013-02-03 16:19 ` Sasha Levin
@ 2013-02-03 19:10 ` Ingo Molnar
0 siblings, 0 replies; 10+ messages in thread
From: Ingo Molnar @ 2013-02-03 19:10 UTC (permalink / raw)
To: Sasha Levin; +Cc: mingo, peterz, paulus, acme, penberg, linux-kernel
* Sasha Levin <sasha.levin@oracle.com> wrote:
> On 02/03/2013 06:04 AM, Ingo Molnar wrote:
> >
> > So I applied your patches and did:
> >
> > cd tools/lib/lockdep
> > make
> >
> > and got:
> >
> > comet:~/tip/tools/lib/lockdep> make
> > CC FPIC common.o
> > In file included from ./uinclude/linux/lockdep.h:13:0,
> > from
> > /fast/mingo/tip/tools/lib/lockdep/common.c:4:
> > ./../../../include/linux/lockdep.h:21:27: fatal error: linux/linkage.h: No such file or directory
> > compilation terminated.
> > make: *** [common.o] Error 1
>
> That's odd, uinclude/linux/linkage.h is an empty file which is
> needed there just so gcc won't complain (like it did in the
> example above).
Ah, indeed - an empty file that Quilt mishandles, so the problem
is on my side.
Thanks,
Ingo
^ permalink raw reply [flat|nested] 10+ messages in thread