closures: closure_sync_timeout()
Add a new variant of closure_sync_timeout() that takes a timeout. Note that when this returns -ETIME the closure will still be waiting on something, i.e. it's not safe to return if you've got a stack allocated closure. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
9a768ab75b
commit
4c5b7294de
@ -194,6 +194,18 @@ static inline void closure_sync(struct closure *cl)
|
||||
__closure_sync(cl);
|
||||
}
|
||||
|
||||
int __closure_sync_timeout(struct closure *cl, unsigned long timeout);
|
||||
|
||||
static inline int closure_sync_timeout(struct closure *cl, unsigned long timeout)
|
||||
{
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
BUG_ON(closure_nr_remaining(cl) != 1 && !cl->closure_get_happened);
|
||||
#endif
|
||||
return cl->closure_get_happened
|
||||
? __closure_sync_timeout(cl, timeout)
|
||||
: 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
|
||||
void closure_debug_create(struct closure *cl);
|
||||
|
@ -139,6 +139,43 @@ void __sched __closure_sync(struct closure *cl)
|
||||
}
|
||||
EXPORT_SYMBOL(__closure_sync);
|
||||
|
||||
int __sched __closure_sync_timeout(struct closure *cl, unsigned long timeout)
|
||||
{
|
||||
struct closure_syncer s = { .task = current };
|
||||
int ret = 0;
|
||||
|
||||
cl->s = &s;
|
||||
continue_at(cl, closure_sync_fn, NULL);
|
||||
|
||||
while (1) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
if (s.done)
|
||||
break;
|
||||
if (!timeout) {
|
||||
/*
|
||||
* Carefully undo the continue_at() - but only if it
|
||||
* hasn't completed, i.e. the final closure_put() hasn't
|
||||
* happened yet:
|
||||
*/
|
||||
unsigned old, new, v = atomic_read(&cl->remaining);
|
||||
do {
|
||||
old = v;
|
||||
if (!old || (old & CLOSURE_RUNNING))
|
||||
goto success;
|
||||
|
||||
new = old + CLOSURE_REMAINING_INITIALIZER;
|
||||
} while ((v = atomic_cmpxchg(&cl->remaining, old, new)) != old);
|
||||
ret = -ETIME;
|
||||
}
|
||||
|
||||
timeout = schedule_timeout(timeout);
|
||||
}
|
||||
success:
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(__closure_sync_timeout);
|
||||
|
||||
#ifdef CONFIG_DEBUG_CLOSURES
|
||||
|
||||
static LIST_HEAD(closure_list);
|
||||
|
Loading…
Reference in New Issue
Block a user