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