1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=4:tabstop=4:
4 * Copyright (c) 2004 Cluster File Systems, Inc.
6 * This file is part of Lustre, http://www.lustre.org.
8 * Lustre is free software; you can redistribute it and/or modify it under
9 * the terms of version 2 of the GNU General Public License as published by
10 * the Free Software Foundation. Lustre is distributed in the hope that it
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details. You should have received a
14 * copy of the GNU General Public License along with Lustre; if not, write
15 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
19 #define DEBUG_SUBSYSTEM S_LIBCFS
21 #include <libcfs/libcfs.h>
22 #include <libcfs/kp30.h>
31 * To initialize the wait queue
34 * waitq: pointer to the cfs_waitq_t structure
43 void cfs_waitq_init(cfs_waitq_t *waitq)
45 waitq->magic = CFS_WAITQ_MAGIC;
47 INIT_LIST_HEAD(&(waitq->waiters));
48 spin_lock_init(&(waitq->guard));
53 * To initialize the wake link node
56 * link: pointer to the cfs_waitlink_t structure
65 void cfs_waitlink_init(cfs_waitlink_t *link)
67 cfs_task_t * task = cfs_current();
68 PTASK_SLOT slot = NULL;
71 /* should bugchk here */
76 slot = CONTAINING_RECORD(task, TASK_SLOT, task);
77 cfs_assert(slot->Magic == TASKSLT_MAGIC);
79 memset(link, 0, sizeof(cfs_waitlink_t));
81 link->magic = CFS_WAITLINK_MAGIC;
84 link->event = &(slot->Event);
85 link->hits = &(slot->hits);
87 atomic_inc(&slot->count);
89 INIT_LIST_HEAD(&(link->waitq[0].link));
90 INIT_LIST_HEAD(&(link->waitq[1].link));
92 link->waitq[0].waitl = link->waitq[1].waitl = link;
98 * To finilize the wake link node
101 * link: pointer to the cfs_waitlink_t structure
110 void cfs_waitlink_fini(cfs_waitlink_t *link)
112 cfs_task_t * task = cfs_current();
113 PTASK_SLOT slot = NULL;
116 /* should bugchk here */
117 cfs_enter_debugger();
121 slot = CONTAINING_RECORD(task, TASK_SLOT, task);
122 cfs_assert(slot->Magic == TASKSLT_MAGIC);
123 cfs_assert(link->magic == CFS_WAITLINK_MAGIC);
124 cfs_assert(link->waitq[0].waitq == NULL);
125 cfs_assert(link->waitq[1].waitq == NULL);
127 atomic_dec(&slot->count);
132 * cfs_waitq_add_internal
133 * To queue the wait link node to the wait queue
136 * waitq: pointer to the cfs_waitq_t structure
137 * link: pointer to the cfs_waitlink_t structure
138 * int: queue no (Normal or Forward waitq)
147 void cfs_waitq_add_internal(cfs_waitq_t *waitq,
148 cfs_waitlink_t *link,
151 LASSERT(waitq != NULL);
152 LASSERT(link != NULL);
153 LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
154 LASSERT(link->magic == CFS_WAITLINK_MAGIC);
155 LASSERT(waitqid < CFS_WAITQ_CHANNELS);
157 spin_lock(&(waitq->guard));
158 LASSERT(link->waitq[waitqid].waitq == NULL);
159 link->waitq[waitqid].waitq = waitq;
160 if (link->flags & CFS_WAITQ_EXCLUSIVE) {
161 list_add_tail(&link->waitq[waitqid].link, &waitq->waiters);
163 list_add(&link->waitq[waitqid].link, &waitq->waiters);
165 spin_unlock(&(waitq->guard));
169 * To queue the wait link node to the wait queue
172 * waitq: pointer to the cfs_waitq_t structure
173 * link: pointer to the cfs_waitlink_t structure
182 void cfs_waitq_add(cfs_waitq_t *waitq,
183 cfs_waitlink_t *link)
185 cfs_waitq_add_internal(waitq, link, CFS_WAITQ_CHAN_NORMAL);
189 * cfs_waitq_add_exclusive
190 * To set the wait link node to exclusive mode
191 * and queue it to the wait queue
194 * waitq: pointer to the cfs_waitq_t structure
195 * link: pointer to the cfs_wait_link structure
204 void cfs_waitq_add_exclusive( cfs_waitq_t *waitq,
205 cfs_waitlink_t *link)
207 LASSERT(waitq != NULL);
208 LASSERT(link != NULL);
209 LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
210 LASSERT(link->magic == CFS_WAITLINK_MAGIC);
212 link->flags |= CFS_WAITQ_EXCLUSIVE;
213 cfs_waitq_add(waitq, link);
218 * To be determinated.
221 * waitq: pointer to the cfs_waitq_t structure
222 * link: pointer to the cfs_waitlink_t structure
231 void cfs_waitq_forward( cfs_waitlink_t *link,
234 cfs_waitq_add_internal(waitq, link, CFS_WAITQ_CHAN_FORWARD);
239 * To remove the wait link node from the waitq
242 * waitq: pointer to the cfs_ waitq_t structure
243 * link: pointer to the cfs_waitlink_t structure
252 void cfs_waitq_del( cfs_waitq_t *waitq,
253 cfs_waitlink_t *link)
257 LASSERT(waitq != NULL);
258 LASSERT(link != NULL);
260 LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
261 LASSERT(link->magic == CFS_WAITLINK_MAGIC);
263 spin_lock(&(waitq->guard));
265 for (i=0; i < CFS_WAITQ_CHANNELS; i++) {
266 if (link->waitq[i].waitq == waitq)
270 if (i < CFS_WAITQ_CHANNELS) {
271 link->waitq[i].waitq = NULL;
272 list_del_init(&link->waitq[i].link);
274 cfs_enter_debugger();
277 spin_unlock(&(waitq->guard));
282 * Is the waitq active (not empty) ?
285 * waitq: pointer to the cfs_ waitq_t structure
288 * Zero: the waitq is empty
289 * Non-Zero: the waitq is active
292 * We always returns TRUE here, the same to Darwin.
295 int cfs_waitq_active(cfs_waitq_t *waitq)
297 LASSERT(waitq != NULL);
298 LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
304 * cfs_waitq_signal_nr
305 * To wake up all the non-exclusive tasks plus nr exclusive
309 * waitq: pointer to the cfs_waitq_t structure
310 * nr: number of exclusive tasks to be woken up
320 void cfs_waitq_signal_nr(cfs_waitq_t *waitq, int nr)
323 cfs_waitlink_channel_t * scan;
325 LASSERT(waitq != NULL);
326 LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
328 spin_lock(&waitq->guard);
330 list_for_each_entry(scan, &waitq->waiters, cfs_waitlink_channel_t, link) {
332 cfs_waitlink_t *waitl = scan->waitl;
334 result = cfs_wake_event(waitl->event);
335 LASSERT( result == FALSE || result == TRUE );
338 atomic_inc(waitl->hits);
341 if ((waitl->flags & CFS_WAITQ_EXCLUSIVE) && --nr == 0)
345 spin_unlock(&waitq->guard);
351 * To wake up all the non-exclusive tasks and 1 exclusive
354 * waitq: pointer to the cfs_waitq_t structure
363 void cfs_waitq_signal(cfs_waitq_t *waitq)
365 cfs_waitq_signal_nr(waitq, 1);
370 * cfs_waitq_broadcast
371 * To wake up all the tasks in the waitq
374 * waitq: pointer to the cfs_waitq_t structure
383 void cfs_waitq_broadcast(cfs_waitq_t *waitq)
385 LASSERT(waitq != NULL);
386 LASSERT(waitq->magic ==CFS_WAITQ_MAGIC);
388 cfs_waitq_signal_nr(waitq, 0);
393 * To wait on the link node until it is signaled.
396 * link: pointer to the cfs_waitlink_t structure
405 void cfs_waitq_wait(cfs_waitlink_t *link, cfs_task_state_t state)
407 LASSERT(link != NULL);
408 LASSERT(link->magic == CFS_WAITLINK_MAGIC);
410 if (atomic_read(link->hits) > 0) {
411 atomic_dec(link->hits);
412 LASSERT((__u32)atomic_read(link->hits) < (__u32)0xFFFFFF00);
414 cfs_wait_event(link->event, 0);
419 * cfs_waitq_timedwait
420 * To wait the link node to be signaled with a timeout limit
423 * link: pointer to the cfs_waitlink_t structure
424 * timeout: the timeout limitation
427 * Woken up: return the difference of the current time and
432 * What if it happens to be woken up at the just timeout time !?
435 cfs_duration_t cfs_waitq_timedwait( cfs_waitlink_t *link,
436 cfs_task_state_t state,
437 cfs_duration_t timeout)
440 if (atomic_read(link->hits) > 0) {
441 atomic_dec(link->hits);
442 LASSERT((__u32)atomic_read(link->hits) < (__u32)0xFFFFFF00);
446 return (cfs_duration_t)cfs_wait_event(link->event, timeout);