Whamcloud - gitweb
b=17167 libcfs: ensure all libcfs exported symbols to have cfs_ prefix
[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 cfs_spin_lock cfs_spinlock_t;
64
65 /* atomic */
66
67 typedef struct { volatile int counter; } cfs_atomic_t;
68
69 #define CFS_ATOMIC_INIT(i)      { i }
70
71 #define cfs_atomic_read(v)      ((v)->counter)
72 #define cfs_atomic_set(v,i)     (((v)->counter) = (i))
73
74 void FASTCALL cfs_atomic_add(int i, cfs_atomic_t *v);
75 void FASTCALL cfs_atomic_sub(int i, cfs_atomic_t *v);
76
77 int FASTCALL cfs_atomic_sub_and_test(int i, cfs_atomic_t *v);
78
79 void FASTCALL cfs_atomic_inc(cfs_atomic_t *v);
80 void FASTCALL cfs_atomic_dec(cfs_atomic_t *v);
81
82 int FASTCALL cfs_atomic_dec_and_test(cfs_atomic_t *v);
83 int FASTCALL cfs_atomic_inc_and_test(cfs_atomic_t *v);
84
85 int FASTCALL cfs_atomic_add_return(int i, cfs_atomic_t *v);
86 int FASTCALL cfs_atomic_sub_return(int i, cfs_atomic_t *v);
87
88 #define cfs_atomic_inc_return(v)  cfs_atomic_add_return(1, v)
89 #define cfs_atomic_dec_return(v)  cfs_atomic_sub_return(1, v)
90
91 int FASTCALL cfs_atomic_dec_and_lock(cfs_atomic_t *v, cfs_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/CFS_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 cfs_spin_lock {
219     KSPIN_LOCK lock;
220     KIRQL      irql;
221 };
222
223 #define CFS_DECL_SPIN(name)  cfs_spinlock_t name;
224 #define CFS_DECL_SPIN_EXTERN(name)  extern cfs_spinlock_t name;
225
226 #define CFS_SPIN_LOCK_UNLOCKED {0}
227
228 static inline void cfs_spin_lock_init(cfs_spinlock_t *lock)
229 {
230     KeInitializeSpinLock(&(lock->lock));
231 }
232
233 static inline void cfs_spin_lock(cfs_spinlock_t *lock)
234 {
235     KeAcquireSpinLock(&(lock->lock), &(lock->irql));
236 }
237
238 static inline void cfs_spin_lock_nested(cfs_spinlock_t *lock, unsigned subclass)
239 {
240     KeAcquireSpinLock(&(lock->lock), &(lock->irql));
241 }
242
243 static inline void cfs_spin_unlock(cfs_spinlock_t *lock)
244 {
245     KIRQL       irql = lock->irql;
246     KeReleaseSpinLock(&(lock->lock), irql);
247 }
248
249
250 #define cfs_spin_lock_irqsave(lock, flags)  \
251 do {(flags) = 0; cfs_spin_lock(lock);} while(0)
252
253 #define cfs_spin_unlock_irqrestore(lock, flags) \
254 do {cfs_spin_unlock(lock);} while(0)
255
256
257 /* There's no  corresponding routine in windows kernel.
258    We must realize a light one of our own.  But there's
259    no way to identify the system is MP build or UP build
260    on the runtime. We just uses a workaround for it. */
261
262 extern int libcfs_mp_system;
263
264 static int cfs_spin_trylock(cfs_spinlock_t *lock)
265 {
266     KIRQL   Irql;
267     int     rc = 0;
268
269     ASSERT(lock != NULL);
270
271     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
272
273     if (libcfs_mp_system) {
274         if (0 == (ulong_ptr_t)lock->lock) {
275 #if _X86_
276             __asm {
277                 mov  edx, dword ptr [ebp + 8]
278                 lock bts dword ptr[edx], 0
279                 jb   lock_failed
280                 mov  rc, TRUE
281             lock_failed:
282             }
283 #else
284         KdBreakPoint();
285 #endif
286
287         }
288     } else {
289         rc = TRUE;
290     }
291
292     if (rc) {
293         lock->irql = Irql;
294     } else {
295         KeLowerIrql(Irql);
296     }
297
298     return rc;
299 }
300
301 static int cfs_spin_is_locked(cfs_spinlock_t *lock)
302 {
303 #if _WIN32_WINNT >= 0x502
304     /* KeTestSpinLock only avalilable on 2k3 server or later */
305     return (!KeTestSpinLock(&lock->lock));
306 #else
307     return (int) (lock->lock);
308 #endif
309 }
310
311 /* synchronization between cpus: it will disable all DPCs
312    kernel task scheduler on the CPU */
313 #define cfs_spin_lock_bh(x)                 cfs_spin_lock(x)
314 #define cfs_spin_unlock_bh(x)       cfs_spin_unlock(x)
315 #define cfs_spin_lock_bh_init(x)        cfs_spin_lock_init(x)
316
317 /*
318  * cfs_rw_semaphore (using ERESOURCE)
319  */
320
321
322 typedef struct cfs_rw_semaphore {
323     ERESOURCE   rwsem;
324 } cfs_rw_semaphore_t;
325
326
327 #define CFS_DECLARE_RWSEM(name) cfs_rw_semaphore_t name
328 #define CFS_DECLARE_RWSEM_EXTERN(name) extern cfs_rw_semaphore_t name
329
330 /*
331  * cfs_init_rwsem
332  *   To initialize the the cfs_rw_semaphore_t structure
333  *
334  * Arguments:
335  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
336  *
337  * Return Value:
338  *   N/A
339  *
340  * Notes:
341  *   N/A
342  */
343
344 static inline void cfs_init_rwsem(cfs_rw_semaphore_t *s)
345 {
346         ExInitializeResourceLite(&s->rwsem);
347 }
348 #define rwsem_init cfs_init_rwsem
349
350 /*
351  * cfs_fini_rwsem
352  *   To finilize/destroy the the cfs_rw_semaphore_t structure
353  *
354  * Arguments:
355  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
356  *
357  * Return Value:
358  *   N/A
359  *
360  * Notes:
361  *   For winnt system, we need this routine to delete the ERESOURCE.
362  *   Just define it NULL for other systems.
363  */
364
365 static inline void cfs_fini_rwsem(cfs_rw_semaphore_t *s)
366 {
367     ExDeleteResourceLite(&s->rwsem);
368 }
369
370 /*
371  * cfs_down_read
372  *   To acquire read-lock of the cfs_rw_semaphore
373  *
374  * Arguments:
375  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
376  *
377  * Return Value:
378  *   N/A
379  *
380  * Notes:
381  *   N/A
382  */
383
384 static inline void cfs_down_read(cfs_rw_semaphore_t *s)
385 {
386         ExAcquireResourceSharedLite(&s->rwsem, TRUE);
387 }
388 #define cfs_down_read_nested cfs_down_read
389
390
391 /*
392  * cfs_down_read_trylock
393  *   To acquire read-lock of the cfs_rw_semaphore without blocking
394  *
395  * Arguments:
396  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
397  *
398  * Return Value:
399  *   Zero: failed to acquire the read lock
400  *   Non-Zero: succeeded to acquire the read lock
401  *
402  * Notes:
403  *   This routine will return immediately without waiting.
404  */
405
406 static inline int cfs_down_read_trylock(cfs_rw_semaphore_t *s)
407 {
408         return ExAcquireResourceSharedLite(&s->rwsem, FALSE);
409 }
410
411
412 /*
413  * cfs_down_write
414  *   To acquire write-lock of the cfs_rw_semaphore
415  *
416  * Arguments:
417  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
418  *
419  * Return Value:
420  *   N/A
421  *
422  * Notes:
423  *   N/A
424  */
425
426 static inline void cfs_down_write(cfs_rw_semaphore_t *s)
427 {
428         ExAcquireResourceExclusiveLite(&(s->rwsem), TRUE);
429 }
430 #define cfs_down_write_nested cfs_down_write
431
432 /*
433  * down_write_trylock
434  *   To acquire write-lock of the cfs_rw_semaphore without blocking
435  *
436  * Arguments:
437  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
438  *
439  * Return Value:
440  *   Zero: failed to acquire the write lock
441  *   Non-Zero: succeeded to acquire the read lock
442  *
443  * Notes:
444  *   This routine will return immediately without waiting.
445  */
446
447 static inline int cfs_down_write_trylock(cfs_rw_semaphore_t *s)
448 {
449     return ExAcquireResourceExclusiveLite(&(s->rwsem), FALSE);
450 }
451
452
453 /*
454  * cfs_up_read
455  *   To release read-lock of the cfs_rw_semaphore
456  *
457  * Arguments:
458  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
459  *
460  * Return Value:
461  *   N/A
462  *
463  * Notes:
464  *   N/A
465  */
466
467 static inline void cfs_up_read(cfs_rw_semaphore_t *s)
468 {
469     ExReleaseResourceForThreadLite(
470             &(s->rwsem),
471             ExGetCurrentResourceThread());
472 }
473
474
475 /*
476  * cfs_up_write
477  *   To release write-lock of the cfs_rw_semaphore
478  *
479  * Arguments:
480  *   rwsem:  pointer to the cfs_rw_semaphore_t structure
481  *
482  * Return Value:
483  *   N/A
484  *
485  * Notes:
486  *   N/A
487  */
488
489 static inline void cfs_up_write(cfs_rw_semaphore_t *s)
490 {
491     ExReleaseResourceForThreadLite(
492                 &(s->rwsem),
493                 ExGetCurrentResourceThread());
494 }
495
496 /*
497  * rwlock_t (using sempahore)
498  *
499  * - rwlock_init(x)
500  * - read_lock(x)
501  * - read_unlock(x)
502  * - write_lock(x)
503  * - write_unlock(x)
504  */
505
506 typedef struct {
507     cfs_spinlock_t guard;
508     int            count;
509 } cfs_rwlock_t;
510
511 void cfs_rwlock_init(cfs_rwlock_t * rwlock);
512 void cfs_rwlock_fini(cfs_rwlock_t * rwlock);
513
514 void cfs_read_lock(cfs_rwlock_t * rwlock);
515 void cfs_read_unlock(cfs_rwlock_t * rwlock);
516 void cfs_write_lock(cfs_rwlock_t * rwlock);
517 void cfs_write_unlock(cfs_rwlock_t * rwlock);
518
519 #define cfs_write_lock_irqsave(l, f)     do {f = 0; cfs_write_lock(l);} while(0)
520 #define cfs_write_unlock_irqrestore(l, f)   do {cfs_write_unlock(l);} while(0)
521 #define cfs_read_lock_irqsave(l, f          do {f=0; cfs_read_lock(l);} while(0)
522 #define cfs_read_unlock_irqrestore(l, f)    do {cfs_read_unlock(l);} while(0)
523
524 #define cfs_write_lock_bh   cfs_write_lock
525 #define cfs_write_unlock_bh cfs_write_unlock
526
527 typedef struct cfs_lock_class_key {
528         int foo;
529 } cfs_lock_class_key_t;
530
531 #define cfs_lockdep_set_class(lock, class) do {} while(0)
532
533 static inline void cfs_lockdep_off(void)
534 {
535 }
536
537 static inline void cfs_lockdep_on(void)
538 {
539 }
540
541 /*
542  * Semaphore
543  *
544  * - sema_init(x, v)
545  * - __down(x)
546  * - __up(x)
547  */
548
549 typedef struct cfs_semaphore {
550         KSEMAPHORE sem;
551 } cfs_semaphore_t;
552
553 static inline void cfs_sema_init(cfs_semaphore_t *s, int val)
554 {
555         KeInitializeSemaphore(&s->sem, val, val);
556 }
557
558 static inline void __down(cfs_semaphore_t *s)
559 {
560    KeWaitForSingleObject( &(s->sem), Executive,
561                           KernelMode, FALSE, NULL );
562
563 }
564 static inline void __up(cfs_semaphore_t *s)
565 {
566         KeReleaseSemaphore(&s->sem, 0, 1, FALSE);
567 }
568
569 static inline int down_trylock(cfs_semaphore_t *s)
570 {
571     LARGE_INTEGER  timeout = {0};
572     NTSTATUS status =
573         KeWaitForSingleObject( &(s->sem), Executive,
574                                KernelMode, FALSE, &timeout);
575
576     if (status == STATUS_SUCCESS) {
577         return 0;
578     }
579
580     return 1;
581 }
582
583 /*
584  * mutex_t:
585  *
586  * - init_mutex(x)
587  * - init_mutex_locked(x)
588  * - mutex_up(x)
589  * - mutex_down(x)
590  */
591
592 typedef struct cfs_semaphore cfs_mutex_t;
593
594 #define CFS_DECLARE_MUTEX(x) cfs_mutex_t x
595
596 /*
597  * init_mutex
598  *   To initialize a mutex_t structure
599  *
600  * Arguments:
601  *   mutex:  pointer to the mutex_t structure
602  *
603  * Return Value:
604  *   N/A
605  *
606  * Notes:
607  *   N/A
608  */
609 #define cfs_mutex_init cfs_init_mutex
610 static inline void cfs_init_mutex(cfs_mutex_t *mutex)
611 {
612     cfs_sema_init(mutex, 1);
613 }
614
615 /*
616  * mutex_down
617  *   To acquire the mutex lock
618  *
619  * Arguments:
620  *   mutex:  pointer to the mutex_t structure
621  *
622  * Return Value:
623  *   N/A
624  *
625  * Notes:
626  *   N/A
627  */
628
629 static inline void cfs_mutex_down(cfs_mutex_t *mutex)
630 {
631     __down(mutex);
632 }
633
634 #define cfs_mutex_lock(m) cfs_mutex_down(m)
635 #define cfs_mutex_trylock(s) down_trylock(s)
636 #define cfs_mutex_lock_nested(m) cfs_mutex_down(m)
637 #define cfs_down(m)       cfs_mutex_down(m)
638
639 /*
640  * mutex_up
641  *   To release the mutex lock (acquired already)
642  *
643  * Arguments:
644  *   mutex:  pointer to the mutex_t structure
645  *
646  * Return Value:
647  *   N/A
648  *
649  * Notes:
650  *   N/A
651  */
652
653 static inline void cfs_mutex_up(cfs_mutex_t *mutex)
654 {
655     __up(mutex);
656 }
657
658 #define cfs_mutex_unlock(m) cfs_mutex_up(m)
659 #define cfs_up(m)           cfs_mutex_up(m)
660
661 /*
662  * init_mutex_locked
663  *   To initialize the mutex as acquired state
664  *
665  * Arguments:
666  *   mutex:  pointer to the mutex_t structure
667  *
668  * Return Value:
669  *   N/A
670  *
671  * Notes:
672  *   N/A
673  */
674
675 static inline void cfs_init_mutex_locked(cfs_mutex_t *mutex)
676 {
677     cfs_init_mutex(mutex);
678     cfs_mutex_down(mutex);
679 }
680
681 static inline void cfs_mutex_destroy(cfs_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 typedef struct {
694         event_t  event;
695 } cfs_completion_t;
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 cfs_init_completion(cfs_completion_t *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 cfs_complete(cfs_completion_t *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 cfs_wait_for_completion(cfs_completion_t *c)
753 {
754     cfs_wait_event_internal(&(c->event), 0);
755 }
756
757 static inline int cfs_wait_for_completion_interruptible(cfs_completion_t *c)
758 {
759     cfs_wait_event_internal(&(c->event), 0);
760     return 0;
761 }
762
763 #else  /* !__KERNEL__ */
764 #endif /* !__KERNEL__ */
765 #endif