aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Brown <matthew.brown.dev@gmail.com>2017-07-07 11:52:44 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2018-03-07 17:21:13 +1100
commit84186ef0944c9413262f0974ddab3fb1343ccfe8 (patch)
treee3dfc69286b036f7faa9e0bf344e58bd303b86c6
parent2d4c774c2a3ad5413272e9d17827e4eb3956be87 (diff)
downloadskiboot-84186ef0944c9413262f0974ddab3fb1343ccfe8.zip
skiboot-84186ef0944c9413262f0974ddab3fb1343ccfe8.tar.gz
skiboot-84186ef0944c9413262f0974ddab3fb1343ccfe8.tar.bz2
core/lock: Add lock timeout warnings
There are currently no timeout warnings for locks in skiboot. We assume that the lock will eventually become free, which may not always be the case. This patch adds timeout warnings for locks. Any lock which spins for more than 5 seconds will throw a warning and stacktrace for that thread. This is useful for debugging siturations where a lock which hang, waiting for the lock to be freed. Signed-off-by: Matt Brown <matthew.brown.dev@gmail.com> Reviewed-by: Cyril Bur <cyril.bur@au1.ibm.com> [stewart: make code match comment, have 5s timeout] Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/lock.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/core/lock.c b/core/lock.c
index d8a0e00..2d94ebb 100644
--- a/core/lock.c
+++ b/core/lock.c
@@ -20,6 +20,7 @@
#include <processor.h>
#include <cpu.h>
#include <console.h>
+#include <timebase.h>
/* Set to bust locks. Note, this is initialized to true because our
* lock debugging code is not going to work until we have the per
@@ -132,11 +133,27 @@ static void remove_lock_request(void)
this_cpu()->requested_lock = NULL;
}
+#define LOCK_TIMEOUT_MS 5000
+static inline bool lock_timeout(unsigned long start)
+{
+ /* Print warning if lock has been spinning for more than TIMEOUT_MS */
+ unsigned long wait = tb_to_msecs(mftb());
+
+ if (wait - start > LOCK_TIMEOUT_MS) {
+ prlog(PR_WARNING, "WARNING: Lock has been "\
+ "spinning for %lums\n", wait - start);
+ backtrace();
+ return true;
+ }
+
+ return false;
+}
#else
static inline void lock_check(struct lock *l) { };
static inline void unlock_check(struct lock *l) { };
static inline void add_lock_request(struct lock *l) { };
static inline void remove_lock_request(void) { };
+static inline bool lock_timeout(unsigned long s) { return false; }
#endif /* DEBUG_LOCKS */
bool lock_held_by_me(struct lock *l)
@@ -181,6 +198,9 @@ bool try_lock_caller(struct lock *l, const char *owner)
void lock_caller(struct lock *l, const char *owner)
{
+ bool timeout_warn = false;
+ unsigned long start;
+
if (bust_locks)
return;
@@ -190,6 +210,10 @@ void lock_caller(struct lock *l, const char *owner)
return;
add_lock_request(l);
+#ifdef DEBUG_LOCKS
+ start = tb_to_msecs(mftb());
+#endif
+
for (;;) {
if (try_lock_caller(l, owner))
break;
@@ -197,6 +221,9 @@ void lock_caller(struct lock *l, const char *owner)
while (l->lock_val)
barrier();
smt_medium();
+
+ if (!timeout_warn)
+ timeout_warn = lock_timeout(start);
}
remove_lock_request();