[Skiboot] [PATCH] core/lock: Add deadlock detection

Andrew Donnellan andrew.donnellan at au1.ibm.com
Fri Jun 23 16:43:20 AEST 2017


On 23/06/17 14:35, Matt Brown wrote:
> This adds simple deadlock detection.
> The detection looks for circular dependencies in the lock requests.
> It will abort and display a stack trace when a deadlock occurs.
> The detection will reduce performance so only use for debugging.
> To use, enable DEBUG_DEADLOCKS in include/config.h (disabled by default).
>
> Signed-off-by: Matt Brown <matthew.brown.dev at gmail.com>
> ---
>  core/lock.c      | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  include/config.h |  3 ++
>  include/lock.h   |  5 ++++
>  3 files changed, 90 insertions(+), 1 deletion(-)
>

This looks like it might need a respin on top of master.

> diff --git a/core/lock.c b/core/lock.c
> index e82048b..0379fb0 100644
> --- a/core/lock.c
> +++ b/core/lock.c
> @@ -1,4 +1,4 @@
> -/* Copyright 2013-2014 IBM Corp.
> +/* Copyright 2013-2017 IBM Corp.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -66,6 +66,73 @@ static inline void lock_check(struct lock *l) { };
>  static inline void unlock_check(struct lock *l) { };
>  #endif /* DEBUG_LOCKS */
>
> +#ifdef DEBUG_DEADLOCKS
> +
> +#define MAX_THREADS 2048
> +static struct lock *lock_table[MAX_THREADS];
> +
> +/* Find circular dependencies in the lock requests. */
> +static bool check_deadlock(void)
> +{
> +	int lock_owner, i, start;
> +	struct lock *next;
> +
> +	start = this_cpu()->pir;
> +	next = lock_table[start];
> +	i = 0;
> +
> +	while (i < MAX_THREADS) {
> +
> +		if (!next)
> +			return false;
> +
> +		if (!(next->lock_val & 1) || next->in_con_path)
> +			return false;
> +
> +		lock_owner = next->lock_val >> 32;
> +
> +		if (lock_owner >= MAX_THREADS)
> +			return false;
> +
> +		if (lock_owner == start && i > 0)
> +			return true;
> +
> +		next = lock_table[lock_owner];
> +		i++;
> +	}
> +
> +	return false;
> +}
> +
> +void add_lock_request(struct lock *l)

Can this + remove_lock_request() be static and get rid of the definition 
in the headers too?

> +{
> +	if (this_cpu()->state == cpu_state_active ||
> +	    this_cpu()->state == cpu_state_os) {
> +
> +		if (this_cpu()->pir >= MAX_THREADS)
> +			return;
> +
> +		lock_table[this_cpu()->pir] = l;
> +
> +		if (check_deadlock() && check_deadlock()) {
> +#ifdef DEBUG_LOCKS
> +			lock_error(l, "Deadlock detected", 0);
> +#else
> +			prlog(PR_EMERG, "LOCK: Deadlock detected\n");
> +			backtrace();
> +			abort();
> +#endif /* DEBUG_LOCKS */
> +		}
> +	}
> +}
> +
> +void remove_lock_request(void)
> +{
> +	if (this_cpu()->pir < MAX_THREADS)
> +		lock_table[this_cpu()->pir] = NULL;
> +}
> +#endif /* DEBUG_DEADLOCKS */
> +
>  bool lock_held_by_me(struct lock *l)
>  {
>  	uint64_t pir64 = this_cpu()->pir;
> @@ -86,15 +153,29 @@ bool try_lock(struct lock *l)
>
>  void lock(struct lock *l)
>  {
> +
>  	if (bust_locks)
>  		return;
>
>  	lock_check(l);
> +
> +#ifdef DEBUG_DEADLOCKS
> +	if (try_lock(l))
> +		return;
> +
> +	add_lock_request(l);
> +#endif
> +
>  	for (;;) {
>  		if (try_lock(l))
>  			break;
>  		cpu_relax();
>  	}
> +
> +#ifdef DEBUG_DEADLOCKS
> +	remove_lock_request();
> +#endif
> +
>  }
>
>  void unlock(struct lock *l)
> diff --git a/include/config.h b/include/config.h
> index cd8a0a6..c2f80e9 100644
> --- a/include/config.h
> +++ b/include/config.h
> @@ -39,6 +39,9 @@
>  /* Enable lock debugging */
>  #define DEBUG_LOCKS		1
>
> +/* Enable deadlock detection */
> +//#define DEBUG_DEADLOCKS	1
> +
>  /* Enable malloc debugging */
>  #define DEBUG_MALLOC		1
>
> diff --git a/include/lock.h b/include/lock.h
> index 0ac943d..27bedc7 100644
> --- a/include/lock.h
> +++ b/include/lock.h
> @@ -81,4 +81,9 @@ extern bool lock_recursive(struct lock *l);
>  /* Called after per-cpu data structures are available */
>  extern void init_locks(void);
>
> +#ifdef DEBUG_DEADLOCKS
> +extern void add_lock_request(struct lock *l);
> +extern void remove_lock_request(void);
> +#endif /* DEBUG_DEADLOCKS*/
> +
>  #endif /* __LOCK_H */
>

-- 
Andrew Donnellan              OzLabs, ADL Canberra
andrew.donnellan at au1.ibm.com  IBM Australia Limited



More information about the Skiboot mailing list