![Ingo Molnar](/assets/img/avatar_default.png)
This code (CONFIG_LOCKDEP_CROSSRELEASE=y and CONFIG_LOCKDEP_COMPLETIONS=y), while it found a number of old bugs initially, was also causing too many false positives that caused people to disable lockdep - which is arguably a worse overall outcome. If we disable cross-release by default but keep the code upstream then in practice the most likely outcome is that we'll allow the situation to degrade gradually, by allowing entropy to introduce more and more false positives, until it overwhelms maintenance capacity. Another bad side effect was that people were trying to work around the false positives by uglifying/complicating unrelated code. There's a marked difference between annotating locking operations and uglifying good code just due to bad lock debugging code ... This gradual decrease in quality happened to a number of debugging facilities in the kernel, and lockdep is pretty complex already, so we cannot risk this outcome. Either cross-release checking can be done right with no false positives, or it should not be included in the upstream kernel. ( Note that it might make sense to maintain it out of tree and go through the false positives every now and then and see whether new bugs were introduced. ) Cc: Byungchul Park <byungchul.park@lge.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
123 lines
4.1 KiB
C
123 lines
4.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __LINUX_COMPLETION_H
|
|
#define __LINUX_COMPLETION_H
|
|
|
|
/*
|
|
* (C) Copyright 2001 Linus Torvalds
|
|
*
|
|
* Atomic wait-for-completion handler data structures.
|
|
* See kernel/sched/completion.c for details.
|
|
*/
|
|
|
|
#include <linux/wait.h>
|
|
|
|
/*
|
|
* struct completion - structure used to maintain state for a "completion"
|
|
*
|
|
* This is the opaque structure used to maintain the state for a "completion".
|
|
* Completions currently use a FIFO to queue threads that have to wait for
|
|
* the "completion" event.
|
|
*
|
|
* See also: complete(), wait_for_completion() (and friends _timeout,
|
|
* _interruptible, _interruptible_timeout, and _killable), init_completion(),
|
|
* reinit_completion(), and macros DECLARE_COMPLETION(),
|
|
* DECLARE_COMPLETION_ONSTACK().
|
|
*/
|
|
struct completion {
|
|
unsigned int done;
|
|
wait_queue_head_t wait;
|
|
};
|
|
|
|
#define init_completion_map(x, m) __init_completion(x)
|
|
#define init_completion(x) __init_completion(x)
|
|
static inline void complete_acquire(struct completion *x) {}
|
|
static inline void complete_release(struct completion *x) {}
|
|
static inline void complete_release_commit(struct completion *x) {}
|
|
|
|
#define COMPLETION_INITIALIZER(work) \
|
|
{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
|
|
|
|
#define COMPLETION_INITIALIZER_ONSTACK_MAP(work, map) \
|
|
(*({ init_completion_map(&(work), &(map)); &(work); }))
|
|
|
|
#define COMPLETION_INITIALIZER_ONSTACK(work) \
|
|
(*({ init_completion(&work); &work; }))
|
|
|
|
/**
|
|
* DECLARE_COMPLETION - declare and initialize a completion structure
|
|
* @work: identifier for the completion structure
|
|
*
|
|
* This macro declares and initializes a completion structure. Generally used
|
|
* for static declarations. You should use the _ONSTACK variant for automatic
|
|
* variables.
|
|
*/
|
|
#define DECLARE_COMPLETION(work) \
|
|
struct completion work = COMPLETION_INITIALIZER(work)
|
|
|
|
/*
|
|
* Lockdep needs to run a non-constant initializer for on-stack
|
|
* completions - so we use the _ONSTACK() variant for those that
|
|
* are on the kernel stack:
|
|
*/
|
|
/**
|
|
* DECLARE_COMPLETION_ONSTACK - declare and initialize a completion structure
|
|
* @work: identifier for the completion structure
|
|
*
|
|
* This macro declares and initializes a completion structure on the kernel
|
|
* stack.
|
|
*/
|
|
#ifdef CONFIG_LOCKDEP
|
|
# define DECLARE_COMPLETION_ONSTACK(work) \
|
|
struct completion work = COMPLETION_INITIALIZER_ONSTACK(work)
|
|
# define DECLARE_COMPLETION_ONSTACK_MAP(work, map) \
|
|
struct completion work = COMPLETION_INITIALIZER_ONSTACK_MAP(work, map)
|
|
#else
|
|
# define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work)
|
|
# define DECLARE_COMPLETION_ONSTACK_MAP(work, map) DECLARE_COMPLETION(work)
|
|
#endif
|
|
|
|
/**
|
|
* init_completion - Initialize a dynamically allocated completion
|
|
* @x: pointer to completion structure that is to be initialized
|
|
*
|
|
* This inline function will initialize a dynamically created completion
|
|
* structure.
|
|
*/
|
|
static inline void __init_completion(struct completion *x)
|
|
{
|
|
x->done = 0;
|
|
init_waitqueue_head(&x->wait);
|
|
}
|
|
|
|
/**
|
|
* reinit_completion - reinitialize a completion structure
|
|
* @x: pointer to completion structure that is to be reinitialized
|
|
*
|
|
* This inline function should be used to reinitialize a completion structure so it can
|
|
* be reused. This is especially important after complete_all() is used.
|
|
*/
|
|
static inline void reinit_completion(struct completion *x)
|
|
{
|
|
x->done = 0;
|
|
}
|
|
|
|
extern void wait_for_completion(struct completion *);
|
|
extern void wait_for_completion_io(struct completion *);
|
|
extern int wait_for_completion_interruptible(struct completion *x);
|
|
extern int wait_for_completion_killable(struct completion *x);
|
|
extern unsigned long wait_for_completion_timeout(struct completion *x,
|
|
unsigned long timeout);
|
|
extern unsigned long wait_for_completion_io_timeout(struct completion *x,
|
|
unsigned long timeout);
|
|
extern long wait_for_completion_interruptible_timeout(
|
|
struct completion *x, unsigned long timeout);
|
|
extern long wait_for_completion_killable_timeout(
|
|
struct completion *x, unsigned long timeout);
|
|
extern bool try_wait_for_completion(struct completion *x);
|
|
extern bool completion_done(struct completion *x);
|
|
|
|
extern void complete(struct completion *);
|
|
extern void complete_all(struct completion *);
|
|
|
|
#endif
|