Whamcloud - gitweb
update changelog section
[fs/lustre-release.git] / lnet / libcfs / winnt / winnt-sync.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36
37 #define DEBUG_SUBSYSTEM S_LIBCFS
38
39 #include <libcfs/libcfs.h>
40 #include <libcfs/kp30.h>
41
42
43 /*
44  * Wait queue routines
45  */
46
47 /*
48  * cfs_waitq_init
49  *   To initialize the wait queue
50  *
51  * Arguments:
52  *   waitq:  pointer to the cfs_waitq_t structure
53  *
54  * Return Value:
55  *   N/A
56  *
57  * Notes: 
58  *   N/A
59  */
60
61 void cfs_waitq_init(cfs_waitq_t *waitq)
62 {
63     waitq->magic = CFS_WAITQ_MAGIC;
64     waitq->flags = 0;
65     INIT_LIST_HEAD(&(waitq->waiters));
66     spin_lock_init(&(waitq->guard));
67 }
68
69 /*
70  * cfs_waitlink_init
71  *   To initialize the wake link node
72  *
73  * Arguments:
74  *   link:  pointer to the cfs_waitlink_t structure
75  *
76  * Return Value:
77  *   N/A
78  *
79  * Notes: 
80  *   N/A
81  */
82
83 void cfs_waitlink_init(cfs_waitlink_t *link)
84 {
85     cfs_task_t * task = cfs_current();
86     PTASK_SLOT   slot = NULL;
87
88     if (!task) {
89         /* should bugchk here */
90         cfs_enter_debugger();
91         return;
92     }
93
94     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
95     cfs_assert(slot->Magic == TASKSLT_MAGIC);
96
97     memset(link, 0, sizeof(cfs_waitlink_t));
98
99     link->magic = CFS_WAITLINK_MAGIC;
100     link->flags = 0;
101
102     link->event = &(slot->Event);
103     link->hits  = &(slot->hits);
104
105     atomic_inc(&slot->count);
106
107     INIT_LIST_HEAD(&(link->waitq[0].link));
108     INIT_LIST_HEAD(&(link->waitq[1].link));
109
110     link->waitq[0].waitl = link->waitq[1].waitl = link;
111 }
112
113
114 /*
115  * cfs_waitlink_fini
116  *   To finilize the wake link node
117  *
118  * Arguments:
119  *   link:  pointer to the cfs_waitlink_t structure
120  *
121  * Return Value:
122  *   N/A
123  *
124  * Notes: 
125  *   N/A
126  */
127
128 void cfs_waitlink_fini(cfs_waitlink_t *link)
129 {
130     cfs_task_t * task = cfs_current();
131     PTASK_SLOT   slot = NULL;
132
133     if (!task) {
134         /* should bugchk here */
135         cfs_enter_debugger();
136         return;
137     }
138
139     slot = CONTAINING_RECORD(task, TASK_SLOT, task);
140     cfs_assert(slot->Magic == TASKSLT_MAGIC);
141     cfs_assert(link->magic == CFS_WAITLINK_MAGIC);
142     cfs_assert(link->waitq[0].waitq == NULL);
143     cfs_assert(link->waitq[1].waitq == NULL);
144
145     atomic_dec(&slot->count);
146 }
147
148
149 /*
150  * cfs_waitq_add_internal
151  *   To queue the wait link node to the wait queue
152  *
153  * Arguments:
154  *   waitq:  pointer to the cfs_waitq_t structure
155  *   link:   pointer to the cfs_waitlink_t structure
156  *   int:    queue no (Normal or Forward waitq)
157  *
158  * Return Value:
159  *   N/A
160  *
161  * Notes: 
162  *   N/A
163  */
164
165 void cfs_waitq_add_internal(cfs_waitq_t *waitq,
166                             cfs_waitlink_t *link,
167                             __u32 waitqid )
168
169     LASSERT(waitq != NULL);
170     LASSERT(link != NULL);
171     LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
172     LASSERT(link->magic == CFS_WAITLINK_MAGIC);
173     LASSERT(waitqid < CFS_WAITQ_CHANNELS);
174
175     spin_lock(&(waitq->guard));
176     LASSERT(link->waitq[waitqid].waitq == NULL);
177     link->waitq[waitqid].waitq = waitq;
178     if (link->flags & CFS_WAITQ_EXCLUSIVE) {
179         list_add_tail(&link->waitq[waitqid].link, &waitq->waiters);
180     } else {
181         list_add(&link->waitq[waitqid].link, &waitq->waiters);
182     }
183     spin_unlock(&(waitq->guard));
184 }
185 /*
186  * cfs_waitq_add
187  *   To queue the wait link node to the wait queue
188  *
189  * Arguments:
190  *   waitq:  pointer to the cfs_waitq_t structure
191  *   link:  pointer to the cfs_waitlink_t structure
192  *
193  * Return Value:
194  *   N/A
195  *
196  * Notes: 
197  *   N/A
198  */
199
200 void cfs_waitq_add(cfs_waitq_t *waitq,
201                    cfs_waitlink_t *link)
202
203     cfs_waitq_add_internal(waitq, link, CFS_WAITQ_CHAN_NORMAL);
204 }
205
206 /*
207  * cfs_waitq_add_exclusive
208  *   To set the wait link node to exclusive mode
209  *   and queue it to the wait queue
210  *
211  * Arguments:
212  *   waitq:  pointer to the cfs_waitq_t structure
213  *   link:  pointer to the cfs_wait_link structure
214  *
215  * Return Value:
216  *   N/A
217  *
218  * Notes: 
219  *   N/A
220  */
221
222 void cfs_waitq_add_exclusive( cfs_waitq_t *waitq,
223                               cfs_waitlink_t *link)
224 {
225     LASSERT(waitq != NULL);
226     LASSERT(link != NULL);
227     LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
228     LASSERT(link->magic == CFS_WAITLINK_MAGIC);
229
230         link->flags |= CFS_WAITQ_EXCLUSIVE;
231     cfs_waitq_add(waitq, link);
232 }
233
234 /*
235  * cfs_waitq_forward
236  *   To be determinated.
237  *
238  * Arguments:
239  *   waitq:  pointer to the cfs_waitq_t structure
240  *   link:  pointer to the cfs_waitlink_t structure
241  *
242  * Return Value:
243  *   N/A
244  *
245  * Notes: 
246  *   N/A
247  */
248
249 void cfs_waitq_forward( cfs_waitlink_t *link,
250                         cfs_waitq_t *waitq)
251 {
252     cfs_waitq_add_internal(waitq, link, CFS_WAITQ_CHAN_FORWARD);
253 }
254
255 /*
256  * cfs_waitq_del
257  *   To remove the wait link node from the waitq
258  *
259  * Arguments:
260  *   waitq:  pointer to the cfs_ waitq_t structure
261  *   link:  pointer to the cfs_waitlink_t structure
262  *
263  * Return Value:
264  *   N/A
265  *
266  * Notes: 
267  *   N/A
268  */
269
270 void cfs_waitq_del( cfs_waitq_t *waitq,
271                     cfs_waitlink_t *link)
272 {
273     int i = 0;
274
275     LASSERT(waitq != NULL);
276     LASSERT(link != NULL);
277
278     LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
279     LASSERT(link->magic == CFS_WAITLINK_MAGIC);
280
281     spin_lock(&(waitq->guard));
282
283     for (i=0; i < CFS_WAITQ_CHANNELS; i++) {
284         if (link->waitq[i].waitq == waitq)
285             break;
286     }
287
288     if (i < CFS_WAITQ_CHANNELS) {
289         link->waitq[i].waitq = NULL;
290         list_del_init(&link->waitq[i].link);
291     } else {
292         cfs_enter_debugger();
293     }
294
295     spin_unlock(&(waitq->guard));
296 }
297
298 /*
299  * cfs_waitq_active
300  *   Is the waitq active (not empty) ?
301  *
302  * Arguments:
303  *   waitq:  pointer to the cfs_ waitq_t structure
304  *
305  * Return Value:
306  *   Zero: the waitq is empty
307  *   Non-Zero: the waitq is active
308  *
309  * Notes: 
310  *   We always returns TRUE here, the same to Darwin.
311  */
312
313 int cfs_waitq_active(cfs_waitq_t *waitq)
314 {
315     LASSERT(waitq != NULL);
316     LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
317
318         return (1);
319 }
320
321 /*
322  * cfs_waitq_signal_nr
323  *   To wake up all the non-exclusive tasks plus nr exclusive
324  *   ones in the waitq
325  *
326  * Arguments:
327  *   waitq:  pointer to the cfs_waitq_t structure
328  *   nr:    number of exclusive tasks to be woken up
329  *
330  * Return Value:
331  *   N/A
332  *
333  * Notes: 
334  *   N/A
335  */
336
337
338 void cfs_waitq_signal_nr(cfs_waitq_t *waitq, int nr)
339 {
340     int     result;
341     cfs_waitlink_channel_t * scan;
342
343     LASSERT(waitq != NULL);
344     LASSERT(waitq->magic == CFS_WAITQ_MAGIC);
345
346     spin_lock(&waitq->guard);
347
348     list_for_each_entry(scan, &waitq->waiters, cfs_waitlink_channel_t, link) {
349
350         cfs_waitlink_t *waitl = scan->waitl;
351
352         result = cfs_wake_event(waitl->event);
353         LASSERT( result == FALSE || result == TRUE );
354
355         if (result) {
356             atomic_inc(waitl->hits);
357         }
358
359         if ((waitl->flags & CFS_WAITQ_EXCLUSIVE) && --nr == 0)
360             break;
361     }
362
363     spin_unlock(&waitq->guard);
364     return;
365 }
366
367 /*
368  * cfs_waitq_signal
369  *   To wake up all the non-exclusive tasks and 1 exclusive
370  *
371  * Arguments:
372  *   waitq:  pointer to the cfs_waitq_t structure
373  *
374  * Return Value:
375  *   N/A
376  *
377  * Notes: 
378  *   N/A
379  */
380
381 void cfs_waitq_signal(cfs_waitq_t *waitq)
382 {
383     cfs_waitq_signal_nr(waitq, 1);
384 }
385
386
387 /*
388  * cfs_waitq_broadcast
389  *   To wake up all the tasks in the waitq
390  *
391  * Arguments:
392  *   waitq:  pointer to the cfs_waitq_t structure
393  *
394  * Return Value:
395  *   N/A
396  *
397  * Notes: 
398  *   N/A
399  */
400
401 void cfs_waitq_broadcast(cfs_waitq_t *waitq)
402 {
403     LASSERT(waitq != NULL);
404     LASSERT(waitq->magic ==CFS_WAITQ_MAGIC);
405
406         cfs_waitq_signal_nr(waitq, 0);
407 }
408
409 /*
410  * cfs_waitq_wait
411  *   To wait on the link node until it is signaled.
412  *
413  * Arguments:
414  *   link:  pointer to the cfs_waitlink_t structure
415  *
416  * Return Value:
417  *   N/A
418  *
419  * Notes: 
420  *   N/A
421  */
422
423 void cfs_waitq_wait(cfs_waitlink_t *link, cfs_task_state_t state)
424
425     LASSERT(link != NULL);
426     LASSERT(link->magic == CFS_WAITLINK_MAGIC);
427
428     if (atomic_read(link->hits) > 0) {
429         atomic_dec(link->hits);
430         LASSERT((__u32)atomic_read(link->hits) < (__u32)0xFFFFFF00);
431     } else {
432         cfs_wait_event(link->event, 0);
433     }
434 }
435
436 /*
437  * cfs_waitq_timedwait
438  *   To wait the link node to be signaled with a timeout limit
439  *
440  * Arguments:
441  *   link:   pointer to the cfs_waitlink_t structure
442  *   timeout: the timeout limitation
443  *
444  * Return Value:
445  *   Woken up: return the difference of the current time and
446  *             the timeout
447  *   Timeout:  return 0
448  *
449  * Notes: 
450  *   What if it happens to be woken up at the just timeout time !?
451  */
452
453 cfs_duration_t cfs_waitq_timedwait( cfs_waitlink_t *link,
454                                     cfs_task_state_t state,
455                                     cfs_duration_t timeout)
456
457
458     if (atomic_read(link->hits) > 0) {
459         atomic_dec(link->hits);
460         LASSERT((__u32)atomic_read(link->hits) < (__u32)0xFFFFFF00);
461         return TRUE;
462     }
463
464     return (cfs_duration_t)cfs_wait_event(link->event, timeout);
465 }