Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / libcfs / include / libcfs / winnt / winnt-lock.h
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 [sun.com URL with a
20  * copy of GPLv2].
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  * libcfs/include/libcfs/winnt/winnt-lock.h
37  *
38  * Basic library routines.
39  */
40
41 #ifndef __LIBCFS_WINNT_CFS_LOCK_H__
42 #define __LIBCFS_WINNT_CFS_LOCK_H__
43
44 #ifndef __LIBCFS_LIBCFS_H__
45 #error Do not #include this file directly. #include <libcfs/libcfs.h> instead
46 #endif
47
48 #ifdef __KERNEL__
49
50
51 /*
52  *  nt specific part ...
53  */
54
55
56 /* atomic */
57
58 typedef struct { volatile int counter; } atomic_t;
59
60 #define ATOMIC_INIT(i)  { i }
61
62 #define atomic_read(v)  ((v)->counter)
63 #define atomic_set(v,i)         (((v)->counter) = (i))
64
65 void FASTCALL atomic_add(int i, atomic_t *v);
66 void FASTCALL atomic_sub(int i, atomic_t *v);
67
68 int FASTCALL atomic_sub_and_test(int i, atomic_t *v);
69
70 void FASTCALL atomic_inc(atomic_t *v);
71 void FASTCALL atomic_dec(atomic_t *v);
72
73 int FASTCALL atomic_dec_and_test(atomic_t *v);
74 int FASTCALL atomic_inc_and_test(atomic_t *v);
75
76
77 /* event */
78
79 typedef KEVENT          event_t;
80
81 /*
82  * cfs_init_event
83  *   To initialize the event object
84  *
85  * Arguments:
86  *   event:  pointer to the event object
87  *   type:   Non Zero: SynchronizationEvent
88  *           Zero: NotificationEvent
89  *   status: the initial stats of the event
90  *           Non Zero: signaled
91  *           Zero: un-signaled
92  *
93  * Return Value:
94  *   N/A
95  *
96  * Notes: 
97  *   N/A
98  */
99 static inline void
100     cfs_init_event(event_t *event, int type, int status)
101 {
102     KeInitializeEvent(
103             event,
104             (type) ? SynchronizationEvent: NotificationEvent,
105             (status) ? TRUE : FALSE
106             );
107 }
108
109 /*
110  * cfs_wait_event
111  *   To wait on an event to syncrhonize the process
112  *
113  * Arguments:
114  *   event:  pointer to the event object
115  *   timeout: the timeout for waitting or 0 means infinite time.
116  *
117  * Return Value:
118  *   Zero:   waiting timeouts
119  *   Non Zero: event signaled ...
120  *
121  * Notes: 
122  *   N/A
123  */
124
125 static inline int64_t
126 cfs_wait_event(event_t * event, int64_t timeout)
127 {
128     NTSTATUS        Status;
129     LARGE_INTEGER   TimeOut;
130
131     TimeOut.QuadPart = -1 * (10000000/HZ) * timeout;
132
133     Status = KeWaitForSingleObject(
134                 event,
135                 Executive,
136                 KernelMode,
137                 FALSE,
138                 (timeout != 0) ? (&TimeOut) : (NULL)
139                 );
140
141     if (Status == STATUS_TIMEOUT)  {
142         return 0;
143     }
144
145     return TRUE; // signaled case
146 }
147
148 /*
149  * cfs_wake_event
150  *   To signal the event object
151  *
152  * Arguments:
153  *   event:  pointer to the event object
154  *
155  * Return Value:
156  *   N/A
157  *
158  * Notes: 
159  *   N/A
160  */
161
162 static inline int
163 cfs_wake_event(event_t * event)
164 {
165     return (KeSetEvent(event, 0, FALSE) != 0);
166 }
167
168 /*
169  * cfs_clear_event
170  *   To clear/reset the status of the event object
171  *
172  * Arguments:
173  *   event:  pointer to the event object
174  *
175  * Return Value:
176  *   N/A
177  *
178  * Notes: 
179  *   N/A
180  */
181
182 static inline void
183 cfs_clear_event(event_t * event)
184 {
185     KeResetEvent(event);
186 }
187
188
189 /*
190  * IMPORTANT !!!!!!!!
191  *
192  * All locks' declaration are not guaranteed to be initialized,
193  * Althought some of they are initialized in Linux. All locks
194  * declared by CFS_DECL_* should be initialized explicitly.
195  */
196
197
198 /*
199  * spin lock defintions / routines
200  */
201
202 /*
203  * Warning:
204  *
205  * for spinlock operations, try to grab nesting acquisition of
206  * spinlock will cause dead-lock in MP system and current irql 
207  * overwritten for UP system. (UP system could allow nesting spin
208  * acqisition, because it's not spin at all just raising the irql.)
209  *
210  */
211
212 typedef struct spin_lock {
213
214     KSPIN_LOCK lock;
215     KIRQL      irql;
216
217 } spinlock_t;
218
219
220 #define CFS_DECL_SPIN(name)  spinlock_t name;
221 #define CFS_DECL_SPIN_EXTERN(name)  extern spinlock_t name;
222
223
224 static inline void spin_lock_init(spinlock_t *lock)
225 {
226     KeInitializeSpinLock(&(lock->lock));
227 }
228
229
230 static inline void spin_lock(spinlock_t *lock)
231 {
232     KeAcquireSpinLock(&(lock->lock), &(lock->irql));
233 }
234
235 static inline void spin_unlock(spinlock_t *lock)
236 {
237     KIRQL       irql = lock->irql;
238     KeReleaseSpinLock(&(lock->lock), irql);
239 }
240
241
242 #define spin_lock_irqsave(lock, flags)          do {(flags) = 0; spin_lock(lock);} while(0)
243 #define spin_unlock_irqrestore(lock, flags)     do {spin_unlock(lock);} while(0)
244
245
246 /* There's no  corresponding routine in windows kernel.
247    We must realize a light one of our own.  But there's
248    no way to identify the system is MP build or UP build
249    on the runtime. We just uses a workaround for it. */
250
251 extern int MPSystem;
252
253 static int spin_trylock(spinlock_t *lock)
254 {
255     KIRQL   Irql;
256     int     rc = 0;
257
258     ASSERT(lock != NULL);
259
260     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
261
262     if (MPSystem) {
263         if (0 == (ulong_ptr)lock->lock) {
264 #if _X86_
265             __asm {
266                 mov  edx, dword ptr [ebp + 8]
267                 lock bts dword ptr[edx], 0
268                 jb   lock_failed
269                 mov  rc, TRUE
270             lock_failed:
271             }
272 #else
273         KdBreakPoint();
274 #endif
275
276         }
277     } else {
278         rc = TRUE;
279     }
280
281     if (rc) {
282         lock->irql = Irql;
283     } else {
284         KeLowerIrql(Irql);
285     }
286
287     return rc;
288 }
289
290 /* synchronization between cpus: it will disable all DPCs
291    kernel task scheduler on the CPU */
292 #define spin_lock_bh(x)             spin_lock(x)
293 #define spin_unlock_bh(x)           spin_unlock(x)
294 #define spin_lock_bh_init(x)    spin_lock_init(x)
295
296 /*
297  * rw_semaphore (using ERESOURCE)
298  */
299
300
301 typedef struct rw_semaphore {
302     ERESOURCE   rwsem;
303 } rw_semaphore_t;
304
305
306 #define CFS_DECL_RWSEM(name) rw_semaphore_t name
307 #define CFS_DECL_RWSEM_EXTERN(name) extern rw_semaphore_t name
308
309
310 /*
311  * init_rwsem
312  *   To initialize the the rw_semaphore_t structure
313  *
314  * Arguments:
315  *   rwsem:  pointer to the rw_semaphore_t structure
316  *
317  * Return Value:
318  *   N/A
319  *
320  * Notes: 
321  *   N/A
322  */
323
324 static inline void init_rwsem(rw_semaphore_t *s)
325 {
326         ExInitializeResourceLite(&s->rwsem);
327 }
328
329
330 /*
331  * fini_rwsem
332  *   To finilize/destroy the the rw_semaphore_t structure
333  *
334  * Arguments:
335  *   rwsem:  pointer to the rw_semaphore_t structure
336  *
337  * Return Value:
338  *   N/A
339  *
340  * Notes: 
341  *   For winnt system, we need this routine to delete the ERESOURCE.
342  *   Just define it NULL for other systems.
343  */
344
345 static inline void fini_rwsem(rw_semaphore_t *s)
346 {
347     ExDeleteResourceLite(&s->rwsem);
348 }
349
350 /*
351  * down_read
352  *   To acquire read-lock of the rw_semahore
353  *
354  * Arguments:
355  *   rwsem:  pointer to the rw_semaphore_t structure
356  *
357  * Return Value:
358  *   N/A
359  *
360  * Notes: 
361  *   N/A
362  */
363
364 static inline void down_read(struct rw_semaphore *s)
365 {
366         ExAcquireResourceSharedLite(&s->rwsem, TRUE);
367 }
368
369
370 /*
371  * down_read_trylock
372  *   To acquire read-lock of the rw_semahore without blocking
373  *
374  * Arguments:
375  *   rwsem:  pointer to the rw_semaphore_t structure
376  *
377  * Return Value:
378  *   Zero: failed to acquire the read lock
379  *   Non-Zero: succeeded to acquire the read lock
380  *
381  * Notes: 
382  *   This routine will return immediately without waiting.
383  */
384
385 static inline int down_read_trylock(struct rw_semaphore *s)
386 {
387         return ExAcquireResourceSharedLite(&s->rwsem, FALSE);
388 }
389
390
391 /*
392  * down_write
393  *   To acquire write-lock of the rw_semahore
394  *
395  * Arguments:
396  *   rwsem:  pointer to the rw_semaphore_t structure
397  *
398  * Return Value:
399  *   N/A
400  *
401  * Notes: 
402  *   N/A
403  */
404
405 static inline void down_write(struct rw_semaphore *s)
406 {
407         ExAcquireResourceExclusiveLite(&(s->rwsem), TRUE);
408 }
409
410
411 /*
412  * down_write_trylock
413  *   To acquire write-lock of the rw_semahore without blocking
414  *
415  * Arguments:
416  *   rwsem:  pointer to the rw_semaphore_t structure
417  *
418  * Return Value:
419  *   Zero: failed to acquire the write lock
420  *   Non-Zero: succeeded to acquire the read lock
421  *
422  * Notes: 
423  *   This routine will return immediately without waiting.
424  */
425
426 static inline int down_write_trylock(struct rw_semaphore *s)
427 {
428     return ExAcquireResourceExclusiveLite(&(s->rwsem), FALSE);
429 }
430
431
432 /*
433  * up_read
434  *   To release read-lock of the rw_semahore
435  *
436  * Arguments:
437  *   rwsem:  pointer to the rw_semaphore_t structure
438  *
439  * Return Value:
440  *   N/A
441  *
442  * Notes: 
443  *   N/A
444  */
445
446 static inline void up_read(struct rw_semaphore *s)
447 {
448     ExReleaseResourceForThreadLite(
449             &(s->rwsem),
450             ExGetCurrentResourceThread());
451 }
452
453
454 /*
455  * up_write
456  *   To release write-lock of the rw_semahore
457  *
458  * Arguments:
459  *   rwsem:  pointer to the rw_semaphore_t structure
460  *
461  * Return Value:
462  *   N/A
463  *
464  * Notes: 
465  *   N/A
466  */
467
468 static inline void up_write(struct rw_semaphore *s)
469 {
470     ExReleaseResourceForThreadLite(
471                 &(s->rwsem),
472                 ExGetCurrentResourceThread());
473 }
474
475 /*
476  * rwlock_t (using sempahore)
477  *
478  * - rwlock_init(x)
479  * - read_lock(x)
480  * - read_unlock(x)
481  * - write_lock(x)
482  * - write_unlock(x)
483  */
484
485 typedef struct {
486     spinlock_t guard;
487     int        count;
488 } rwlock_t;
489
490 void rwlock_init(rwlock_t * rwlock);
491 void rwlock_fini(rwlock_t * rwlock);
492
493 void read_lock(rwlock_t * rwlock);
494 void read_unlock(rwlock_t * rwlock);
495 void write_lock(rwlock_t * rwlock);
496 void write_unlock(rwlock_t * rwlock);
497
498 #define write_lock_irqsave(l, f)        do {f = 0; write_lock(l);} while(0)
499 #define write_unlock_irqrestore(l, f)   do {write_unlock(l);} while(0)
500 #define read_lock_irqsave(l, f)         do {f=0; read_lock(l);} while(0)
501 #define read_unlock_irqrestore(l, f)    do {read_unlock(l);} while(0)
502
503
504 /*
505  * Semaphore
506  *
507  * - sema_init(x, v)
508  * - __down(x)
509  * - __up(x)
510  */
511
512 typedef struct semaphore {
513         KSEMAPHORE sem;
514 } mutex_t;
515
516 static inline void sema_init(struct semaphore *s, int val)
517 {
518         KeInitializeSemaphore(&s->sem, val, val);
519 }
520
521 static inline void __down(struct semaphore *s)
522 {
523    KeWaitForSingleObject( &(s->sem), Executive,
524                           KernelMode, FALSE, NULL );
525
526 }
527
528 static inline void __up(struct semaphore *s)
529 {
530         KeReleaseSemaphore(&s->sem, 0, 1, FALSE);
531 }
532
533 /*
534  * mutex_t:
535  *
536  * - init_mutex(x)
537  * - init_mutex_locked(x)
538  * - mutex_up(x)
539  * - mutex_down(x)
540  */
541
542
543 /*
544  * init_mutex
545  *   To initialize a mutex_t structure
546  *
547  * Arguments:
548  *   mutex:  pointer to the mutex_t structure
549  *
550  * Return Value:
551  *   N/A
552  *
553  * Notes: 
554  *   N/A
555  */
556
557 static inline void init_mutex(mutex_t *mutex)
558 {
559     sema_init(mutex, 1);
560 }
561
562
563 /*
564  * mutex_down
565  *   To acquire the mutex lock
566  *
567  * Arguments:
568  *   mutex:  pointer to the mutex_t structure
569  *
570  * Return Value:
571  *   N/A
572  *
573  * Notes: 
574  *   N/A
575  */
576
577 static inline void mutex_down(mutex_t *mutex)
578 {
579     __down(mutex);
580 }
581
582
583 /*
584  * mutex_up
585  *   To release the mutex lock (acquired already)
586  *
587  * Arguments:
588  *   mutex:  pointer to the mutex_t structure
589  *
590  * Return Value:
591  *   N/A
592  *
593  * Notes: 
594  *   N/A
595  */
596
597 static inline void mutex_up(mutex_t *mutex)
598 {
599     __up(mutex);
600 }
601
602
603 /*
604  * init_mutex_locked
605  *   To initialize the mutex as acquired state
606  *
607  * Arguments:
608  *   mutex:  pointer to the mutex_t structure
609  *
610  * Return Value:
611  *   N/A
612  *
613  * Notes: 
614  *   N/A
615  */
616
617 static inline init_mutex_locked(mutex_t *mutex)
618 {
619     init_mutex(mutex);
620     mutex_down(mutex);
621 }
622
623 /*
624  * completion
625  *
626  * - init_complition(c)
627  * - complete(c)
628  * - wait_for_completion(c)
629  */
630
631 struct completion {
632         event_t  event;
633 };
634
635
636 /*
637  * init_completion
638  *   To initialize the completion object
639  *
640  * Arguments:
641  *   c:  pointer to the completion structure
642  *
643  * Return Value:
644  *   N/A
645  *
646  * Notes: 
647  *   N/A
648  */
649
650 static inline void init_completion(struct completion *c)
651 {
652         cfs_init_event(&(c->event), 1, FALSE);
653 }
654
655
656 /*
657  * complete
658  *   To complete/signal the completion object
659  *
660  * Arguments:
661  *   c:  pointer to the completion structure
662  *
663  * Return Value:
664  *   N/A
665  *
666  * Notes: 
667  *   N/A
668  */
669
670 static inline void complete(struct completion *c)
671 {
672         cfs_wake_event(&(c->event));
673 }
674
675 /*
676  * wait_for_completion
677  *   To wait on the completion object. If the event is signaled,
678  *   this function will return to the call with the event un-singled.
679  *
680  * Arguments:
681  *   c:  pointer to the completion structure
682  *
683  * Return Value:
684  *   N/A
685  *
686  * Notes: 
687  *   N/A
688  */
689
690 static inline void wait_for_completion(struct completion *c)
691 {
692     cfs_wait_event(&(c->event), 0);
693 }
694
695 /* __KERNEL__ */
696 #else
697
698 #include "../user-lock.h"
699
700 /* __KERNEL__ */
701 #endif
702 #endif