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