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