diff options
author | Maxime Ripard <mripard@kernel.org> | 2024-05-27 11:08:31 +0200 |
---|---|---|
committer | Maxime Ripard <mripard@kernel.org> | 2024-05-27 11:08:31 +0200 |
commit | 375c4d1583948cf2439833e4a85d5a0aee853895 (patch) | |
tree | 821f494e7df09af36887f710cfce1fb89600e666 /lib/closure.c | |
parent | 983095eaf6c161ef73d96152bfc1a99ca051cd57 (diff) | |
parent | 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0 (diff) |
Merge drm/drm-next into drm-misc-next
Let's start the new release cycle.
Signed-off-by: Maxime Ripard <mripard@kernel.org>
Diffstat (limited to 'lib/closure.c')
-rw-r--r-- | lib/closure.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/lib/closure.c b/lib/closure.c index c16540552d61..07409e9e35a5 100644 --- a/lib/closure.c +++ b/lib/closure.c @@ -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); |