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