diff options
| author | riastradh <riastradh@NetBSD.org> | 2018-08-27 15:04:32 +0000 |
|---|---|---|
| committer | riastradh <riastradh@NetBSD.org> | 2018-08-27 15:04:32 +0000 |
| commit | 805f7c1875d443262eeea0d3f37ae1095500a847 (patch) | |
| tree | 368ad3771444e7f0c623ee2a348ec5bdde3bb35d /sys/external/bsd/common/linux | |
| parent | 75d2d8a662b2354b3e1fd2440f8f15dc90f129be (diff) | |
Factor out waiting for current work.
Diffstat (limited to 'sys/external/bsd/common/linux')
| -rw-r--r-- | sys/external/bsd/common/linux/linux_work.c | 44 |
1 files changed, 29 insertions, 15 deletions
diff --git a/sys/external/bsd/common/linux/linux_work.c b/sys/external/bsd/common/linux/linux_work.c index 4ef6f769254..17ce932b5d4 100644 --- a/sys/external/bsd/common/linux/linux_work.c +++ b/sys/external/bsd/common/linux/linux_work.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_work.c,v 1.32 2018/08/27 15:04:19 riastradh Exp $ */ +/* $NetBSD: linux_work.c,v 1.33 2018/08/27 15:04:32 riastradh Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.32 2018/08/27 15:04:19 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.33 2018/08/27 15:04:32 riastradh Exp $"); #include <sys/types.h> #include <sys/atomic.h> @@ -65,6 +65,8 @@ static struct workqueue_struct * struct workqueue_struct *); static void release_work(struct work_struct *, struct workqueue_struct *); +static void wait_for_current_work(struct work_struct *, + struct workqueue_struct *); static void dw_callout_init(struct workqueue_struct *, struct delayed_work *); static void dw_callout_destroy(struct workqueue_struct *, @@ -496,13 +498,9 @@ cancel_work_sync(struct work_struct *work) } else if (wq->wq_current_work == work) { /* * It has already begun execution, so it's too late to - * cancel now. Wait for it to complete. Don't wait - * more than one generation in case it gets requeued. + * cancel now. Wait for it to complete. */ - uint64_t gen = wq->wq_gen; - do { - cv_wait(&wq->wq_cv, &wq->wq_lock); - } while (wq->wq_current_work == work && wq->wq_gen == gen); + wait_for_current_work(work, wq); cancelled_p = false; } else { /* @@ -516,6 +514,27 @@ cancel_work_sync(struct work_struct *work) out: return cancelled_p; } + +/* + * wait_for_current_work(work, wq) + * + * wq must be currently executing work. Wait for it to finish. + */ +static void +wait_for_current_work(struct work_struct *work, struct workqueue_struct *wq) +{ + uint64_t gen; + + KASSERT(mutex_owned(&wq->wq_lock)); + KASSERT(work->work_queue == wq); + KASSERT(wq->wq_current_work == work); + + /* Wait only one generation in case it gets requeued quickly. */ + gen = wq->wq_gen; + do { + cv_wait(&wq->wq_cv, &wq->wq_lock); + } while (wq->wq_current_work == work && wq->wq_gen == gen); +} /* * Delayed work @@ -993,19 +1012,14 @@ cancel_delayed_work_sync(struct delayed_work *dw) /* * Too late, it's already running. * First, make sure it's not requeued. - * Then wait for it to complete, at - * most one generation. + * Then wait for it to complete. */ - uint64_t gen = wq->wq_gen; if (wq->wq_requeued) { TAILQ_REMOVE(&wq->wq_queue, &dw->work, work_entry); wq->wq_requeued = false; } - do { - cv_wait(&wq->wq_cv, &wq->wq_lock); - } while (wq->wq_current_work == &dw->work && - wq->wq_gen == gen); + wait_for_current_work(&dw->work, wq); cancelled_p = false; } else { /* Got in before it started. Remove it. */ |
