Whamcloud - gitweb
LU-812 compat: SPIN/RW_LOCK_UNLOCKED no longer exist
[fs/lustre-release.git] / libcfs / include / libcfs / winnt / winnt-lock.h
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  */
30 /*
31  * This file is part of Lustre, http://www.lustre.org/
32  * Lustre is a trademark of Sun Microsystems, Inc.
33  *
34  * libcfs/include/libcfs/winnt/winnt-lock.h
35  *
36  * Basic library routines.
37  */
38
39 #ifndef __LIBCFS_WINNT_CFS_LOCK_H__
40 #define __LIBCFS_WINNT_CFS_LOCK_H__
41
42 #ifndef __LIBCFS_LIBCFS_H__
43 #error Do not #include this file directly. #include <libcfs/libcfs.h> instead
44 #endif
45
46 #ifdef __KERNEL__
47
48
49 /*
50  * IMPORTANT !!!!!!!!
51  *
52  * All locks' declaration are not guaranteed to be initialized,
53  * Althought some of they are initialized in Linux. All locks
54  * declared by CFS_DECL_* should be initialized explicitly.
55  */
56
57 /*
58  *  spinlock & event definitions
59  */
60
61 typedef struct cfs_spin_lock cfs_spinlock_t;
62
63 /* atomic */
64
65 typedef struct { volatile int counter; } cfs_atomic_t;
66
67 #define CFS_ATOMIC_INIT(i)      { i }
68
69 #define cfs_atomic_read(v)      ((v)->counter)
70 #define cfs_atomic_set(v,i)     (((v)->counter) = (i))
71
72 void FASTCALL cfs_atomic_add(int i, cfs_atomic_t *v);
73 void FASTCALL cfs_atomic_sub(int i, cfs_atomic_t *v);
74
75 int FASTCALL cfs_atomic_sub_and_test(int i, cfs_atomic_t *v);
76
77 void FASTCALL cfs_atomic_inc(cfs_atomic_t *v);
78 void FASTCALL cfs_atomic_dec(cfs_atomic_t *v);
79
80 int FASTCALL cfs_atomic_dec_and_test(cfs_atomic_t *v);
81 int FASTCALL cfs_atomic_inc_and_test(cfs_atomic_t *v);
82
83 int FASTCALL cfs_atomic_add_return(int i, cfs_atomic_t *v);
84 int FASTCALL cfs_atomic_sub_return(int i, cfs_atomic_t *v);
85
86 #define cfs_atomic_inc_return(v)  cfs_atomic_add_return(1, v)
87 #define cfs_atomic_dec_return(v)  cfs_atomic_sub_return(1, v)
88
89 int FASTCALL cfs_atomic_dec_and_lock(cfs_atomic_t *v, cfs_spinlock_t *lock);
90
91 /* event */
92
93 typedef KEVENT          event_t;
94
95 /*
96  * cfs_init_event
97  *   To initialize the event object
98  *
99  * Arguments:
100  *   event:  pointer to the event object
101  *   type:   Non Zero: SynchronizationEvent
102  *           Zero: NotificationEvent
103  *   status: the initial stats of the event
104  *           Non Zero: signaled
105  *           Zero: un-signaled
106  *
107  * Return Value:
108  *   N/A
109  *
110  * Notes:
111  *   N/A
112  */
113 static inline void
114 cfs_init_event(event_t *event, int type, int status)
115 {
116     KeInitializeEvent(
117             event,
118             (type) ? SynchronizationEvent: NotificationEvent,
119             (status) ? TRUE : FALSE
120             );
121 }
122
123 /*
124  * cfs_wait_event_internal
125  *   To wait on an event to syncrhonize the process
126  *
127  * Arguments:
128  *   event:  pointer to the event object
129  *   timeout: the timeout for waitting or 0 means infinite time.
130  *
131  * Return Value:
132  *   Zero:   waiting timeouts
133  *   Non Zero: event signaled ...
134  *
135  * Notes:
136  *   N/A
137  */
138
139 static inline int64_t
140 cfs_wait_event_internal(event_t * event, int64_t timeout)
141 {
142     NTSTATUS        Status;
143     LARGE_INTEGER   TimeOut;
144
145     TimeOut.QuadPart = -1 * (10000000/CFS_HZ) * timeout;
146
147     Status = KeWaitForSingleObject(
148                 event,
149                 Executive,
150                 KernelMode,
151                 FALSE,
152                 (timeout != 0) ? (&TimeOut) : (NULL)
153                 );
154
155     if (Status == STATUS_TIMEOUT)  {
156         return 0;
157     }
158
159     return TRUE; // signaled case
160 }
161
162 /*
163  * cfs_wake_event
164  *   To signal the event object
165  *
166  * Arguments:
167  *   event:  pointer to the event object
168  *
169  * Return Value:
170  *   N/A
171  *
172  * Notes:
173  *   N/A
174  */
175
176 static inline int
177 cfs_wake_event(event_t * event)
178 {
179     return (KeSetEvent(event, 0, FALSE) != 0);
180 }
181
182 /*
183  * cfs_clear_event
184  *   To clear/reset the status of the event object
185  *
186  * Arguments:
187  *   event:  pointer to the event object
188  *
189  * Return Value:
190  *   N/A
191  *
192  * Notes:
193  *   N/A
194  */
195
196 static inline void
197 cfs_clear_event(event_t * event)
198 {
199     KeResetEvent(event);
200 }
201
202 /*
203  * spin lock defintions / routines
204  */
205
206 /*
207  * Warning:
208  *
209  * for spinlock operations, try to grab nesting acquisition of
210  * spinlock will cause dead-lock in MP system and current irql
211  * overwritten for UP system. (UP system could allow nesting spin
212  * acqisition, because it's not spin at all just raising the irql.)
213  *
214  */
215
216 struct cfs_spin_lock {
217     KSPIN_LOCK lock;
218     KIRQL      irql;
219 };
220
221 #define CFS_DECL_SPIN(name)  cfs_spinlock_t name;
222 #define CFS_DECL_SPIN_EXTERN(name)  extern cfs_spinlock_t name;
223
224 #define DEFINE_SPINLOCK {0}
225
226 static inline void cfs_spin_lock_init(cfs_spinlock_t *lock)
227 {
228     KeInitializeSpinLock(&(lock->lock));
229 }
230
231 static inline void cfs_spin_lock(cfs_spinlock_t *lock)
232 {
233     KeAcquireSpinLock(&(lock->lock), &(lock->irql));
234 }
235
236 static inline void cfs_spin_lock_nested(cfs_spinlock_t *lock, unsigned subclass)
237 {
238     KeAcquireSpinLock(&(lock->lock), &(lock->irql));
239 }
240
241 static inline void cfs_spin_unlock(cfs_spinlock_t *lock)
242 {
243     KIRQL       irql = lock->irql;
244     KeReleaseSpinLock(&(lock->lock), irql);
245 }
246
247
248 #define cfs_spin_lock_irqsave(lock, flags)  \
249 do {(flags) = 0; cfs_spin_lock(lock);} while(0)
250
251 #define cfs_spin_unlock_irqrestore(lock, flags) \
252 do {cfs_spin_unlock(lock);} while(0)
253
254
255 /* There's no  corresponding routine in windows kernel.
256    We must realize a light one of our own.  But there's
257    no way to identify the system is MP build or UP build
258    on the runtime. We just uses a workaround for it. */
259
260 extern int libcfs_mp_system;
261
262 static int cfs_spin_trylock(cfs_spinlock_t *lock)
263 {
264     KIRQL   Irql;
265     int     rc = 0;
266
267     ASSERT(lock != NULL);
268
269     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
270
271     if (libcfs_mp_system) {
272         if (0 == (ulong_ptr_t)lock->lock) {
273 #if _X86_
274             __asm {
275                 mov  edx, dword ptr [ebp + 8]
276                 lock bts dword ptr[edx], 0
277                 jb   lock_failed
278                 mov  rc, TRUE
279             lock_failed:
280             }
281 #else
282         KdBreakPoint();
283 #endif
284
285         }
286     } else {
287         rc = TRUE;
288     }
289
290     if (rc) {
291         lock->irql = Irql;
292     } else {
293         KeLowerIrql(Irql);
294     }
295
296     return rc;
297 }
298
299 static int cfs_spin_is_locked(cfs_spinlock_t *lock)
300 {
301 #if _WIN32_WINNT >= 0x502
302     /* KeTestSpinLock only avalilable on 2k3 server or later */
303     return (!KeTestSpinLock(&lock->lock));
304 #else
305     return (int) (lock->lock);
306 #endif
307 }
308
309 /* synchronization between cpus: it will disable all DPCs
310    kernel task scheduler on the CPU */
311 #define cfs_spin_lock_bh(x)                 cfs_spin_lock(x)
312 #define cfs_spin_unlock_bh(x)       cfs_spin_unlock(x)
313 #define cfs_spin_lock_bh_init(x)        cfs_spin_lock_init(x)
314
315 /*
316  * cfs_rw_semaphore (using ERESOURCE)
317  */
318
319
320 typedef struct cfs_rw_semaphore {
321     ERESOURCE   rwsem;
322 } cfs_rw_semaphore_t;
323
324
325 #define CFS_DECLARE_RWSEM(name) cfs_rw_semaphore_t name
326 #define CFS_DECLARE_RWSEM_EXTERN(name) extern cfs_rw_semaphore_t name
327
328 /*
329  * cfs_init_rwsem
330  *   To initialize the the cfs_rw_semaphore_t structure
331  *
332  * Arguments:
333  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
334  *
335  * Return Value:
336  *   N/A
337  *
338  * Notes:
339  *   N/A
340  */
341
342 static inline void cfs_init_rwsem(cfs_rw_semaphore_t *s)
343 {
344         ExInitializeResourceLite(&s->rwsem);
345 }
346 #define rwsem_init cfs_init_rwsem
347
348 /*
349  * cfs_fini_rwsem
350  *   To finilize/destroy the the cfs_rw_semaphore_t structure
351  *
352  * Arguments:
353  *   rwsem:  pointer to the cfs_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 cfs_fini_rwsem(cfs_rw_semaphore_t *s)
364 {
365     ExDeleteResourceLite(&s->rwsem);
366 }
367
368 /*
369  * cfs_down_read
370  *   To acquire read-lock of the cfs_rw_semaphore
371  *
372  * Arguments:
373  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
374  *
375  * Return Value:
376  *   N/A
377  *
378  * Notes:
379  *   N/A
380  */
381
382 static inline void cfs_down_read(cfs_rw_semaphore_t *s)
383 {
384         ExAcquireResourceSharedLite(&s->rwsem, TRUE);
385 }
386 #define cfs_down_read_nested cfs_down_read
387
388
389 /*
390  * cfs_down_read_trylock
391  *   To acquire read-lock of the cfs_rw_semaphore without blocking
392  *
393  * Arguments:
394  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
395  *
396  * Return Value:
397  *   Zero: failed to acquire the read lock
398  *   Non-Zero: succeeded to acquire the read lock
399  *
400  * Notes:
401  *   This routine will return immediately without waiting.
402  */
403
404 static inline int cfs_down_read_trylock(cfs_rw_semaphore_t *s)
405 {
406         return ExAcquireResourceSharedLite(&s->rwsem, FALSE);
407 }
408
409
410 /*
411  * cfs_down_write
412  *   To acquire write-lock of the cfs_rw_semaphore
413  *
414  * Arguments:
415  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
416  *
417  * Return Value:
418  *   N/A
419  *
420  * Notes:
421  *   N/A
422  */
423
424 static inline void cfs_down_write(cfs_rw_semaphore_t *s)
425 {
426         ExAcquireResourceExclusiveLite(&(s->rwsem), TRUE);
427 }
428 #define cfs_down_write_nested cfs_down_write
429
430 /*
431  * down_write_trylock
432  *   To acquire write-lock of the cfs_rw_semaphore without blocking
433  *
434  * Arguments:
435  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
436  *
437  * Return Value:
438  *   Zero: failed to acquire the write lock
439  *   Non-Zero: succeeded to acquire the read lock
440  *
441  * Notes:
442  *   This routine will return immediately without waiting.
443  */
444
445 static inline int cfs_down_write_trylock(cfs_rw_semaphore_t *s)
446 {
447     return ExAcquireResourceExclusiveLite(&(s->rwsem), FALSE);
448 }
449
450
451 /*
452  * cfs_up_read
453  *   To release read-lock of the cfs_rw_semaphore
454  *
455  * Arguments:
456  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
457  *
458  * Return Value:
459  *   N/A
460  *
461  * Notes:
462  *   N/A
463  */
464
465 static inline void cfs_up_read(cfs_rw_semaphore_t *s)
466 {
467     ExReleaseResourceForThreadLite(
468             &(s->rwsem),
469             ExGetCurrentResourceThread());
470 }
471
472
473 /*
474  * cfs_up_write
475  *   To release write-lock of the cfs_rw_semaphore
476  *
477  * Arguments:
478  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
479  *
480  * Return Value:
481  *   N/A
482  *
483  * Notes:
484  *   N/A
485  */
486
487 static inline void cfs_up_write(cfs_rw_semaphore_t *s)
488 {
489     ExReleaseResourceForThreadLite(
490                 &(s->rwsem),
491                 ExGetCurrentResourceThread());
492 }
493
494 /*
495  * rwlock_t (using sempahore)
496  *
497  * - rwlock_init(x)
498  * - read_lock(x)
499  * - read_unlock(x)
500  * - write_lock(x)
501  * - write_unlock(x)
502  */
503
504 typedef struct {
505     cfs_spinlock_t guard;
506     int            count;
507 } cfs_rwlock_t;
508
509 void cfs_rwlock_init(cfs_rwlock_t * rwlock);
510 void cfs_rwlock_fini(cfs_rwlock_t * rwlock);
511
512 void cfs_read_lock(cfs_rwlock_t * rwlock);
513 void cfs_read_unlock(cfs_rwlock_t * rwlock);
514 void cfs_write_lock(cfs_rwlock_t * rwlock);
515 void cfs_write_unlock(cfs_rwlock_t * rwlock);
516
517 #define cfs_write_lock_irqsave(l, f)     do {f = 0; cfs_write_lock(l);} while(0)
518 #define cfs_write_unlock_irqrestore(l, f)   do {cfs_write_unlock(l);} while(0)
519 #define cfs_read_lock_irqsave(l, f          do {f=0; cfs_read_lock(l);} while(0)
520 #define cfs_read_unlock_irqrestore(l, f)    do {cfs_read_unlock(l);} while(0)
521
522 #define cfs_write_lock_bh   cfs_write_lock
523 #define cfs_write_unlock_bh cfs_write_unlock
524
525 typedef struct cfs_lock_class_key {
526         int foo;
527 } cfs_lock_class_key_t;
528
529 #define cfs_lockdep_set_class(lock, class) do {} while(0)
530
531 static inline void cfs_lockdep_off(void)
532 {
533 }
534
535 static inline void cfs_lockdep_on(void)
536 {
537 }
538
539 /*
540  * Semaphore
541  *
542  * - sema_init(x, v)
543  * - __down(x)
544  * - __up(x)
545  */
546
547 typedef struct cfs_semaphore {
548         KSEMAPHORE sem;
549 } cfs_semaphore_t;
550
551 static inline void cfs_sema_init(cfs_semaphore_t *s, int val)
552 {
553         KeInitializeSemaphore(&s->sem, val, val);
554 }
555
556 static inline void __down(cfs_semaphore_t *s)
557 {
558    KeWaitForSingleObject( &(s->sem), Executive,
559                           KernelMode, FALSE, NULL );
560
561 }
562 static inline void __up(cfs_semaphore_t *s)
563 {
564         KeReleaseSemaphore(&s->sem, 0, 1, FALSE);
565 }
566
567 static inline int down_trylock(cfs_semaphore_t *s)
568 {
569     LARGE_INTEGER  timeout = {0};
570     NTSTATUS status =
571         KeWaitForSingleObject( &(s->sem), Executive,
572                                KernelMode, FALSE, &timeout);
573
574     if (status == STATUS_SUCCESS) {
575         return 0;
576     }
577
578     return 1;
579 }
580
581 /*
582  * mutex_t:
583  *
584  * - init_mutex(x)
585  * - init_mutex_locked(x)
586  * - mutex_up(x)
587  * - mutex_down(x)
588  */
589
590 typedef struct cfs_semaphore cfs_mutex_t;
591
592 #define CFS_DECLARE_MUTEX(x) cfs_mutex_t x
593
594 /*
595  * init_mutex
596  *   To initialize a mutex_t structure
597  *
598  * Arguments:
599  *   mutex:  pointer to the mutex_t structure
600  *
601  * Return Value:
602  *   N/A
603  *
604  * Notes:
605  *   N/A
606  */
607 #define cfs_mutex_init cfs_init_mutex
608 static inline void cfs_init_mutex(cfs_mutex_t *mutex)
609 {
610     cfs_sema_init(mutex, 1);
611 }
612
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 cfs_mutex_down(cfs_mutex_t *mutex)
628 {
629     __down(mutex);
630 }
631
632 static inline int cfs_mutex_down_interruptible(cfs_mutex_t *mutex)
633 {
634     __down(mutex);
635     return 0;
636 }
637
638 #define cfs_mutex_lock(m)         cfs_mutex_down(m)
639 #define cfs_mutex_trylock(s)      down_trylock(s)
640 #define cfs_mutex_lock_nested(m)  cfs_mutex_down(m)
641 #define cfs_down(m)               cfs_mutex_down(m)
642 #define cfs_down_interruptible(m) cfs_mutex_down_interruptible(m)
643
644 /*
645  * mutex_up
646  *   To release the mutex lock (acquired already)
647  *
648  * Arguments:
649  *   mutex:  pointer to the mutex_t structure
650  *
651  * Return Value:
652  *   N/A
653  *
654  * Notes:
655  *   N/A
656  */
657
658 static inline void cfs_mutex_up(cfs_mutex_t *mutex)
659 {
660     __up(mutex);
661 }
662
663 #define cfs_mutex_unlock(m) cfs_mutex_up(m)
664 #define cfs_up(m)           cfs_mutex_up(m)
665
666 /*
667  * init_mutex_locked
668  *   To initialize the mutex as acquired state
669  *
670  * Arguments:
671  *   mutex:  pointer to the mutex_t structure
672  *
673  * Return Value:
674  *   N/A
675  *
676  * Notes:
677  *   N/A
678  */
679
680 static inline void cfs_init_mutex_locked(cfs_mutex_t *mutex)
681 {
682     cfs_init_mutex(mutex);
683     cfs_mutex_down(mutex);
684 }
685
686 static inline void cfs_mutex_destroy(cfs_mutex_t *mutex)
687 {
688 }
689
690 /*
691  * completion
692  *
693  * - init_complition(c)
694  * - complete(c)
695  * - wait_for_completion(c)
696  */
697
698 typedef struct {
699         event_t  event;
700 } cfs_completion_t;
701
702
703 /*
704  * init_completion
705  *   To initialize the completion object
706  *
707  * Arguments:
708  *   c:  pointer to the completion structure
709  *
710  * Return Value:
711  *   N/A
712  *
713  * Notes:
714  *   N/A
715  */
716
717 static inline void cfs_init_completion(cfs_completion_t *c)
718 {
719         cfs_init_event(&(c->event), 1, FALSE);
720 }
721
722
723 /*
724  * complete
725  *   To complete/signal the completion object
726  *
727  * Arguments:
728  *   c:  pointer to the completion structure
729  *
730  * Return Value:
731  *   N/A
732  *
733  * Notes:
734  *   N/A
735  */
736
737 static inline void cfs_complete(cfs_completion_t *c)
738 {
739         cfs_wake_event(&(c->event));
740 }
741
742 /*
743  * wait_for_completion
744  *   To wait on the completion object. If the event is signaled,
745  *   this function will return to the call with the event un-singled.
746  *
747  * Arguments:
748  *   c:  pointer to the completion structure
749  *
750  * Return Value:
751  *   N/A
752  *
753  * Notes:
754  *   N/A
755  */
756
757 static inline void cfs_wait_for_completion(cfs_completion_t *c)
758 {
759     cfs_wait_event_internal(&(c->event), 0);
760 }
761
762 static inline int cfs_wait_for_completion_interruptible(cfs_completion_t *c)
763 {
764     cfs_wait_event_internal(&(c->event), 0);
765     return 0;
766 }
767
768 #else  /* !__KERNEL__ */
769 #endif /* !__KERNEL__ */
770 #endif