Rev 5347 | Rev 6934 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 5347 | Rev 6102 | ||
---|---|---|---|
1 | /* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for i486+ |
1 | /* rwsem.h: R/W semaphores implemented using XADD/CMPXCHG for i486+ |
2 | * |
2 | * |
3 | * Written by David Howells (dhowells@redhat.com). |
3 | * Written by David Howells (dhowells@redhat.com). |
4 | * |
4 | * |
5 | * Derived from asm-x86/semaphore.h |
5 | * Derived from asm-x86/semaphore.h |
6 | * |
6 | * |
7 | * |
7 | * |
8 | * The MSW of the count is the negated number of active writers and waiting |
8 | * The MSW of the count is the negated number of active writers and waiting |
9 | * lockers, and the LSW is the total number of active locks |
9 | * lockers, and the LSW is the total number of active locks |
10 | * |
10 | * |
11 | * The lock count is initialized to 0 (no active and no waiting lockers). |
11 | * The lock count is initialized to 0 (no active and no waiting lockers). |
12 | * |
12 | * |
13 | * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an |
13 | * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an |
14 | * uncontended lock. This can be determined because XADD returns the old value. |
14 | * uncontended lock. This can be determined because XADD returns the old value. |
15 | * Readers increment by 1 and see a positive value when uncontended, negative |
15 | * Readers increment by 1 and see a positive value when uncontended, negative |
16 | * if there are writers (and maybe) readers waiting (in which case it goes to |
16 | * if there are writers (and maybe) readers waiting (in which case it goes to |
17 | * sleep). |
17 | * sleep). |
18 | * |
18 | * |
19 | * The value of WAITING_BIAS supports up to 32766 waiting processes. This can |
19 | * The value of WAITING_BIAS supports up to 32766 waiting processes. This can |
20 | * be extended to 65534 by manually checking the whole MSW rather than relying |
20 | * be extended to 65534 by manually checking the whole MSW rather than relying |
21 | * on the S flag. |
21 | * on the S flag. |
22 | * |
22 | * |
23 | * The value of ACTIVE_BIAS supports up to 65535 active processes. |
23 | * The value of ACTIVE_BIAS supports up to 65535 active processes. |
24 | * |
24 | * |
25 | * This should be totally fair - if anything is waiting, a process that wants a |
25 | * This should be totally fair - if anything is waiting, a process that wants a |
26 | * lock will go to the back of the queue. When the currently active lock is |
26 | * lock will go to the back of the queue. When the currently active lock is |
27 | * released, if there's a writer at the front of the queue, then that and only |
27 | * released, if there's a writer at the front of the queue, then that and only |
28 | * that will be woken up; if there's a bunch of consequtive readers at the |
28 | * that will be woken up; if there's a bunch of consequtive readers at the |
29 | * front, then they'll all be woken up, but no other readers will be. |
29 | * front, then they'll all be woken up, but no other readers will be. |
30 | */ |
30 | */ |
31 | 31 | ||
32 | #ifndef _ASM_X86_RWSEM_H |
32 | #ifndef _ASM_X86_RWSEM_H |
33 | #define _ASM_X86_RWSEM_H |
33 | #define _ASM_X86_RWSEM_H |
34 | 34 | ||
35 | #ifndef _LINUX_RWSEM_H |
35 | #ifndef _LINUX_RWSEM_H |
36 | #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" |
36 | #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" |
37 | #endif |
37 | #endif |
38 | 38 | ||
39 | #ifdef __KERNEL__ |
39 | #ifdef __KERNEL__ |
40 | #include |
40 | #include |
41 | 41 | ||
42 | #define FASTCALL __attribute__ ((fastcall)) __attribute__ ((dllimport)) |
42 | #define FASTCALL __attribute__ ((fastcall)) __attribute__ ((dllimport)) |
43 | 43 | ||
44 | void FASTCALL InitRwsem(struct rw_semaphore *sem)__asm__("InitRwsem"); |
44 | void FASTCALL InitRwsem(struct rw_semaphore *sem)__asm__("InitRwsem"); |
45 | void FASTCALL DownRead(struct rw_semaphore *sem)__asm__("DownRead"); |
45 | void FASTCALL DownRead(struct rw_semaphore *sem)__asm__("DownRead"); |
46 | void FASTCALL DownWrite(struct rw_semaphore *sem)__asm__("DownWrite"); |
46 | void FASTCALL DownWrite(struct rw_semaphore *sem)__asm__("DownWrite"); |
47 | void FASTCALL UpRead(struct rw_semaphore *sem)__asm__("UpRead"); |
47 | void FASTCALL UpRead(struct rw_semaphore *sem)__asm__("UpRead"); |
48 | void FASTCALL UpWrite(struct rw_semaphore *sem)__asm__("UpWrite"); |
48 | void FASTCALL UpWrite(struct rw_semaphore *sem)__asm__("UpWrite"); |
49 | 49 | ||
50 | static inline void __init_rwsem(struct rw_semaphore *sem, const char *name, |
50 | static inline void __init_rwsem(struct rw_semaphore *sem, const char *name, |
51 | struct lock_class_key *key) |
51 | struct lock_class_key *key) |
52 | { |
52 | { |
53 | InitRwsem(sem); |
53 | InitRwsem(sem); |
54 | } |
54 | } |
55 | 55 | ||
56 | /* |
56 | /* |
57 | * lock for reading |
57 | * lock for reading |
58 | */ |
58 | */ |
59 | static inline void down_read(struct rw_semaphore *sem) |
59 | static inline void down_read(struct rw_semaphore *sem) |
60 | { |
60 | { |
61 | DownRead(sem); |
61 | DownRead(sem); |
62 | } |
62 | } |
63 | 63 | ||
64 | static inline void down_write(struct rw_semaphore *sem) |
64 | static inline void down_write(struct rw_semaphore *sem) |
65 | { |
65 | { |
66 | DownWrite(sem); |
66 | DownWrite(sem); |
67 | } |
67 | } |
68 | 68 | ||
69 | /* |
69 | /* |
70 | * unlock after reading |
70 | * unlock after reading |
71 | */ |
71 | */ |
72 | static inline void up_read(struct rw_semaphore *sem) |
72 | static inline void up_read(struct rw_semaphore *sem) |
73 | { |
73 | { |
74 | UpRead(sem); |
74 | UpRead(sem); |
75 | } |
75 | } |
76 | 76 | ||
77 | /* |
77 | /* |
78 | * unlock after writing |
78 | * unlock after writing |
79 | */ |
79 | */ |
80 | static inline void up_write(struct rw_semaphore *sem) |
80 | static inline void up_write(struct rw_semaphore *sem) |
81 | { |
81 | { |
82 | UpWrite(sem); |
82 | UpWrite(sem); |
83 | } |
83 | } |
- | 84 | ||
- | 85 | #define RWSEM_UNLOCKED_VALUE 0x00000000L |
|
- | 86 | #define RWSEM_ACTIVE_BIAS 0x00000001L |
|
- | 87 | #define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1) |
|
- | 88 | #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS |
|
- | 89 | #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) |
|
- | 90 | ||
- | 91 | static inline int down_read_trylock(struct rw_semaphore *sem) |
|
- | 92 | { |
|
- | 93 | long result, tmp; |
|
- | 94 | asm volatile("# beginning __down_read_trylock\n\t" |
|
- | 95 | " mov %0,%1\n\t" |
|
- | 96 | "1:\n\t" |
|
- | 97 | " mov %1,%2\n\t" |
|
- | 98 | " add %3,%2\n\t" |
|
- | 99 | " jle 2f\n\t" |
|
- | 100 | LOCK_PREFIX " cmpxchg %2,%0\n\t" |
|
- | 101 | " jnz 1b\n\t" |
|
- | 102 | "2:\n\t" |
|
- | 103 | "# ending __down_read_trylock\n\t" |
|
- | 104 | : "+m" (sem->count), "=&a" (result), "=&r" (tmp) |
|
- | 105 | : "i" (RWSEM_ACTIVE_READ_BIAS) |
|
- | 106 | : "memory", "cc"); |
|
- | 107 | return result >= 0 ? 1 : 0; |
|
- | 108 | } |
|
- | 109 | ||
84 | 110 | ||
85 | #endif /* __KERNEL__ */ |
111 | #endif /* __KERNEL__ */ |
86 | #endif /* _ASM_X86_RWSEM_H */ |
112 | #endif /* _ASM_X86_RWSEM_H */ |