]> git.proxmox.com Git - mirror_zfs.git/blame - module/spl/spl-condvar.c
Merge remote branch 'eris/stats'
[mirror_zfs.git] / module / spl / spl-condvar.c
CommitLineData
716154c5
BB
1/*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
715f6251
BB
6 * UCRL-CODE-235197
7 *
716154c5
BB
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
715f6251 15 *
716154c5 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
715f6251
BB
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
716154c5
BB
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting Layer (SPL) Credential Implementation.
25\*****************************************************************************/
715f6251 26
4efd4118 27#include <sys/condvar.h>
55abb092 28#include <spl-debug.h>
4efd4118 29
b17edc10
BB
30#ifdef SS_DEBUG_SUBSYS
31#undef SS_DEBUG_SUBSYS
4efd4118
BB
32#endif
33
b17edc10 34#define SS_DEBUG_SUBSYS SS_CONDVAR
4efd4118
BB
35
36void
37__cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg)
38{
39 int flags = KM_SLEEP;
40
b17edc10 41 SENTRY;
4efd4118 42 ASSERT(cvp);
b29012b9 43 ASSERT(name == NULL);
4efd4118
BB
44 ASSERT(type == CV_DEFAULT);
45 ASSERT(arg == NULL);
46
47 cvp->cv_magic = CV_MAGIC;
48 init_waitqueue_head(&cvp->cv_event);
d599e4fa 49 init_waitqueue_head(&cvp->cv_destroy);
4efd4118
BB
50 atomic_set(&cvp->cv_waiters, 0);
51 cvp->cv_mutex = NULL;
4efd4118
BB
52
53 /* We may be called when there is a non-zero preempt_count or
54 * interrupts are disabled is which case we must not sleep.
55 */
56 if (current_thread_info()->preempt_count || irqs_disabled())
57 flags = KM_NOSLEEP;
58
b17edc10 59 SEXIT;
4efd4118
BB
60}
61EXPORT_SYMBOL(__cv_init);
62
d599e4fa
BB
63static int
64cv_destroy_wakeup(kcondvar_t *cvp)
65{
3c60f505
BB
66 if ((cvp->cv_mutex != NULL) ||
67 (waitqueue_active(&cvp->cv_event)) ||
d599e4fa
BB
68 (atomic_read(&cvp->cv_waiters) > 0))
69 return 0;
70
71 return 1;
72}
73
4efd4118
BB
74void
75__cv_destroy(kcondvar_t *cvp)
76{
b17edc10 77 SENTRY;
4efd4118
BB
78 ASSERT(cvp);
79 ASSERT(cvp->cv_magic == CV_MAGIC);
d599e4fa
BB
80
81 /* Block until all waiters have woken */
82 while (cv_destroy_wakeup(cvp) == 0)
83 wait_event_timeout(cvp->cv_destroy, cv_destroy_wakeup(cvp), 1);
84
3c60f505
BB
85 ASSERT3P(cvp->cv_mutex, ==, NULL);
86 ASSERT3S(atomic_read(&cvp->cv_waiters), ==, 0);
87 ASSERT3S(waitqueue_active(&cvp->cv_event), ==, 0);
4efd4118 88
b17edc10 89 SEXIT;
4efd4118
BB
90}
91EXPORT_SYMBOL(__cv_destroy);
92
f752b46e
BB
93static void
94cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state)
4efd4118
BB
95{
96 DEFINE_WAIT(wait);
b17edc10 97 SENTRY;
4efd4118
BB
98
99 ASSERT(cvp);
100 ASSERT(mp);
101 ASSERT(cvp->cv_magic == CV_MAGIC);
4efd4118
BB
102 ASSERT(mutex_owned(mp));
103
104 if (cvp->cv_mutex == NULL)
105 cvp->cv_mutex = mp;
106
107 /* Ensure the same mutex is used by all callers */
108 ASSERT(cvp->cv_mutex == mp);
4efd4118 109
f752b46e 110 prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
4efd4118
BB
111 atomic_inc(&cvp->cv_waiters);
112
113 /* Mutex should be dropped after prepare_to_wait() this
114 * ensures we're linked in to the waiters list and avoids the
115 * race where 'cvp->cv_waiters > 0' but the list is empty. */
116 mutex_exit(mp);
117 schedule();
118 mutex_enter(mp);
119
058de03c 120 /* No more waiters a different mutex could be used */
d599e4fa 121 if (atomic_dec_and_test(&cvp->cv_waiters)) {
058de03c 122 cvp->cv_mutex = NULL;
d599e4fa
BB
123 wake_up(&cvp->cv_destroy);
124 }
058de03c 125
4efd4118 126 finish_wait(&cvp->cv_event, &wait);
d599e4fa 127
b17edc10 128 SEXIT;
4efd4118 129}
f752b46e
BB
130
131void
132__cv_wait(kcondvar_t *cvp, kmutex_t *mp)
133{
134 cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE);
135}
4efd4118
BB
136EXPORT_SYMBOL(__cv_wait);
137
f752b46e
BB
138void
139__cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp)
140{
141 cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE);
142}
143EXPORT_SYMBOL(__cv_wait_interruptible);
144
4efd4118
BB
145/* 'expire_time' argument is an absolute wall clock time in jiffies.
146 * Return value is time left (expire_time - now) or -1 if timeout occurred.
147 */
3f688a8c
NK
148static clock_t
149__cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp,
150 clock_t expire_time, int state)
4efd4118
BB
151{
152 DEFINE_WAIT(wait);
153 clock_t time_left;
b17edc10 154 SENTRY;
4efd4118
BB
155
156 ASSERT(cvp);
157 ASSERT(mp);
158 ASSERT(cvp->cv_magic == CV_MAGIC);
4efd4118
BB
159 ASSERT(mutex_owned(mp));
160
161 if (cvp->cv_mutex == NULL)
162 cvp->cv_mutex = mp;
163
164 /* Ensure the same mutex is used by all callers */
165 ASSERT(cvp->cv_mutex == mp);
4efd4118
BB
166
167 /* XXX - Does not handle jiffie wrap properly */
168 time_left = expire_time - jiffies;
169 if (time_left <= 0)
b17edc10 170 SRETURN(-1);
4efd4118 171
3f688a8c 172 prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
4efd4118
BB
173 atomic_inc(&cvp->cv_waiters);
174
175 /* Mutex should be dropped after prepare_to_wait() this
176 * ensures we're linked in to the waiters list and avoids the
177 * race where 'cvp->cv_waiters > 0' but the list is empty. */
178 mutex_exit(mp);
179 time_left = schedule_timeout(time_left);
180 mutex_enter(mp);
181
058de03c 182 /* No more waiters a different mutex could be used */
d599e4fa 183 if (atomic_dec_and_test(&cvp->cv_waiters)) {
058de03c 184 cvp->cv_mutex = NULL;
d599e4fa
BB
185 wake_up(&cvp->cv_destroy);
186 }
058de03c 187
4efd4118
BB
188 finish_wait(&cvp->cv_event, &wait);
189
b17edc10 190 SRETURN(time_left > 0 ? time_left : -1);
4efd4118 191}
3f688a8c
NK
192
193clock_t
194__cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
195{
196 return __cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE);
197}
4efd4118
BB
198EXPORT_SYMBOL(__cv_timedwait);
199
3f688a8c
NK
200clock_t
201__cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
202{
203 return __cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE);
204}
205EXPORT_SYMBOL(__cv_timedwait_interruptible);
206
4efd4118
BB
207void
208__cv_signal(kcondvar_t *cvp)
209{
b17edc10 210 SENTRY;
4efd4118
BB
211 ASSERT(cvp);
212 ASSERT(cvp->cv_magic == CV_MAGIC);
213
214 /* All waiters are added with WQ_FLAG_EXCLUSIVE so only one
215 * waiter will be set runable with each call to wake_up().
216 * Additionally wake_up() holds a spin_lock assoicated with
217 * the wait queue to ensure we don't race waking up processes. */
218 if (atomic_read(&cvp->cv_waiters) > 0)
219 wake_up(&cvp->cv_event);
220
b17edc10 221 SEXIT;
4efd4118
BB
222}
223EXPORT_SYMBOL(__cv_signal);
224
225void
226__cv_broadcast(kcondvar_t *cvp)
227{
228 ASSERT(cvp);
229 ASSERT(cvp->cv_magic == CV_MAGIC);
b17edc10 230 SENTRY;
4efd4118
BB
231
232 /* Wake_up_all() will wake up all waiters even those which
233 * have the WQ_FLAG_EXCLUSIVE flag set. */
234 if (atomic_read(&cvp->cv_waiters) > 0)
235 wake_up_all(&cvp->cv_event);
236
b17edc10 237 SEXIT;
4efd4118
BB
238}
239EXPORT_SYMBOL(__cv_broadcast);