diff options
| author | Michel Lespinasse <walken@google.com> | 2013-05-07 09:45:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 10:20:15 -0400 |
| commit | e2d57f782c8a906f80d5b5f54da803c1638929d7 (patch) | |
| tree | 96a3d2f26b8257d39db40ec4cd3cd52b3ef14588 /lib | |
| parent | c1be5a5b1b355d40e6cf79cc979eb66dafa24ad1 (diff) | |
rwsem: make the waiter type an enumeration rather than a bitmask
We are not planning to add some new waiter flags, so we can convert the
waiter type into an enumeration.
Background: David Howells suggested I do this back when I tried adding
a new waiter type for unfair readers. However, I believe the cleanup
applies regardless of that use case.
Signed-off-by: Michel Lespinasse <walken@google.com>
Reviewed-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Peter Hurley <peter@hurleysoftware.com>
Acked-by: Davidlohr Bueso <davidlohr.bueso@hp.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/rwsem-spinlock.c | 19 | ||||
| -rw-r--r-- | lib/rwsem.c | 23 |
2 files changed, 24 insertions, 18 deletions
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index 7542afbb22b3..5f117f37ac0a 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c | |||
| @@ -9,12 +9,15 @@ | |||
| 9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
| 10 | #include <linux/export.h> | 10 | #include <linux/export.h> |
| 11 | 11 | ||
| 12 | enum rwsem_waiter_type { | ||
| 13 | RWSEM_WAITING_FOR_WRITE, | ||
| 14 | RWSEM_WAITING_FOR_READ | ||
| 15 | }; | ||
| 16 | |||
| 12 | struct rwsem_waiter { | 17 | struct rwsem_waiter { |
| 13 | struct list_head list; | 18 | struct list_head list; |
| 14 | struct task_struct *task; | 19 | struct task_struct *task; |
| 15 | unsigned int flags; | 20 | enum rwsem_waiter_type type; |
| 16 | #define RWSEM_WAITING_FOR_READ 0x00000001 | ||
| 17 | #define RWSEM_WAITING_FOR_WRITE 0x00000002 | ||
| 18 | }; | 21 | }; |
| 19 | 22 | ||
| 20 | int rwsem_is_locked(struct rw_semaphore *sem) | 23 | int rwsem_is_locked(struct rw_semaphore *sem) |
| @@ -68,7 +71,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) | |||
| 68 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); | 71 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); |
| 69 | 72 | ||
| 70 | if (!wakewrite) { | 73 | if (!wakewrite) { |
| 71 | if (waiter->flags & RWSEM_WAITING_FOR_WRITE) | 74 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) |
| 72 | goto out; | 75 | goto out; |
| 73 | goto dont_wake_writers; | 76 | goto dont_wake_writers; |
| 74 | } | 77 | } |
| @@ -78,7 +81,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) | |||
| 78 | * to -1 here to indicate we get the lock. Instead, we wake it up | 81 | * to -1 here to indicate we get the lock. Instead, we wake it up |
| 79 | * to let it go get it again. | 82 | * to let it go get it again. |
| 80 | */ | 83 | */ |
| 81 | if (waiter->flags & RWSEM_WAITING_FOR_WRITE) { | 84 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) { |
| 82 | wake_up_process(waiter->task); | 85 | wake_up_process(waiter->task); |
| 83 | goto out; | 86 | goto out; |
| 84 | } | 87 | } |
| @@ -86,7 +89,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) | |||
| 86 | /* grant an infinite number of read locks to the front of the queue */ | 89 | /* grant an infinite number of read locks to the front of the queue */ |
| 87 | dont_wake_writers: | 90 | dont_wake_writers: |
| 88 | woken = 0; | 91 | woken = 0; |
| 89 | while (waiter->flags & RWSEM_WAITING_FOR_READ) { | 92 | while (waiter->type == RWSEM_WAITING_FOR_READ) { |
| 90 | struct list_head *next = waiter->list.next; | 93 | struct list_head *next = waiter->list.next; |
| 91 | 94 | ||
| 92 | list_del(&waiter->list); | 95 | list_del(&waiter->list); |
| @@ -144,7 +147,7 @@ void __sched __down_read(struct rw_semaphore *sem) | |||
| 144 | 147 | ||
| 145 | /* set up my own style of waitqueue */ | 148 | /* set up my own style of waitqueue */ |
| 146 | waiter.task = tsk; | 149 | waiter.task = tsk; |
| 147 | waiter.flags = RWSEM_WAITING_FOR_READ; | 150 | waiter.type = RWSEM_WAITING_FOR_READ; |
| 148 | get_task_struct(tsk); | 151 | get_task_struct(tsk); |
| 149 | 152 | ||
| 150 | list_add_tail(&waiter.list, &sem->wait_list); | 153 | list_add_tail(&waiter.list, &sem->wait_list); |
| @@ -201,7 +204,7 @@ void __sched __down_write_nested(struct rw_semaphore *sem, int subclass) | |||
| 201 | /* set up my own style of waitqueue */ | 204 | /* set up my own style of waitqueue */ |
| 202 | tsk = current; | 205 | tsk = current; |
| 203 | waiter.task = tsk; | 206 | waiter.task = tsk; |
| 204 | waiter.flags = RWSEM_WAITING_FOR_WRITE; | 207 | waiter.type = RWSEM_WAITING_FOR_WRITE; |
| 205 | list_add_tail(&waiter.list, &sem->wait_list); | 208 | list_add_tail(&waiter.list, &sem->wait_list); |
| 206 | 209 | ||
| 207 | /* wait for someone to release the lock */ | 210 | /* wait for someone to release the lock */ |
diff --git a/lib/rwsem.c b/lib/rwsem.c index ad5e0df16ab4..672eb33218ac 100644 --- a/lib/rwsem.c +++ b/lib/rwsem.c | |||
| @@ -30,12 +30,15 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name, | |||
| 30 | 30 | ||
| 31 | EXPORT_SYMBOL(__init_rwsem); | 31 | EXPORT_SYMBOL(__init_rwsem); |
| 32 | 32 | ||
| 33 | enum rwsem_waiter_type { | ||
| 34 | RWSEM_WAITING_FOR_WRITE, | ||
| 35 | RWSEM_WAITING_FOR_READ | ||
| 36 | }; | ||
| 37 | |||
| 33 | struct rwsem_waiter { | 38 | struct rwsem_waiter { |
| 34 | struct list_head list; | 39 | struct list_head list; |
| 35 | struct task_struct *task; | 40 | struct task_struct *task; |
| 36 | unsigned int flags; | 41 | enum rwsem_waiter_type type; |
| 37 | #define RWSEM_WAITING_FOR_READ 0x00000001 | ||
| 38 | #define RWSEM_WAITING_FOR_WRITE 0x00000002 | ||
| 39 | }; | 42 | }; |
| 40 | 43 | ||
| 41 | /* Wake types for __rwsem_do_wake(). Note that RWSEM_WAKE_NO_ACTIVE and | 44 | /* Wake types for __rwsem_do_wake(). Note that RWSEM_WAKE_NO_ACTIVE and |
| @@ -65,7 +68,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type) | |||
| 65 | signed long woken, loop, adjustment; | 68 | signed long woken, loop, adjustment; |
| 66 | 69 | ||
| 67 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); | 70 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); |
| 68 | if (!(waiter->flags & RWSEM_WAITING_FOR_WRITE)) | 71 | if (waiter->type != RWSEM_WAITING_FOR_WRITE) |
| 69 | goto readers_only; | 72 | goto readers_only; |
| 70 | 73 | ||
| 71 | if (wake_type == RWSEM_WAKE_READ_OWNED) | 74 | if (wake_type == RWSEM_WAKE_READ_OWNED) |
| @@ -112,10 +115,10 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type) | |||
| 112 | waiter = list_entry(waiter->list.next, | 115 | waiter = list_entry(waiter->list.next, |
| 113 | struct rwsem_waiter, list); | 116 | struct rwsem_waiter, list); |
| 114 | 117 | ||
| 115 | } while (waiter->flags & RWSEM_WAITING_FOR_READ); | 118 | } while (waiter->type != RWSEM_WAITING_FOR_WRITE); |
| 116 | 119 | ||
| 117 | adjustment = woken * RWSEM_ACTIVE_READ_BIAS; | 120 | adjustment = woken * RWSEM_ACTIVE_READ_BIAS; |
| 118 | if (waiter->flags & RWSEM_WAITING_FOR_READ) | 121 | if (waiter->type != RWSEM_WAITING_FOR_WRITE) |
| 119 | /* hit end of list above */ | 122 | /* hit end of list above */ |
| 120 | adjustment -= RWSEM_WAITING_BIAS; | 123 | adjustment -= RWSEM_WAITING_BIAS; |
| 121 | 124 | ||
| @@ -148,7 +151,7 @@ static int try_get_writer_sem(struct rw_semaphore *sem, | |||
| 148 | 151 | ||
| 149 | /* only steal when first waiter is writing */ | 152 | /* only steal when first waiter is writing */ |
| 150 | fwaiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); | 153 | fwaiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); |
| 151 | if (!(fwaiter->flags & RWSEM_WAITING_FOR_WRITE)) | 154 | if (fwaiter->type != RWSEM_WAITING_FOR_WRITE) |
| 152 | return 0; | 155 | return 0; |
| 153 | 156 | ||
| 154 | adjustment = RWSEM_ACTIVE_WRITE_BIAS; | 157 | adjustment = RWSEM_ACTIVE_WRITE_BIAS; |
| @@ -179,7 +182,7 @@ try_again_write: | |||
| 179 | */ | 182 | */ |
| 180 | static struct rw_semaphore __sched * | 183 | static struct rw_semaphore __sched * |
| 181 | rwsem_down_failed_common(struct rw_semaphore *sem, | 184 | rwsem_down_failed_common(struct rw_semaphore *sem, |
| 182 | unsigned int flags, signed long adjustment) | 185 | enum rwsem_waiter_type type, signed long adjustment) |
| 183 | { | 186 | { |
| 184 | struct rwsem_waiter waiter; | 187 | struct rwsem_waiter waiter; |
| 185 | struct task_struct *tsk = current; | 188 | struct task_struct *tsk = current; |
| @@ -190,7 +193,7 @@ rwsem_down_failed_common(struct rw_semaphore *sem, | |||
| 190 | /* set up my own style of waitqueue */ | 193 | /* set up my own style of waitqueue */ |
| 191 | raw_spin_lock_irq(&sem->wait_lock); | 194 | raw_spin_lock_irq(&sem->wait_lock); |
| 192 | waiter.task = tsk; | 195 | waiter.task = tsk; |
| 193 | waiter.flags = flags; | 196 | waiter.type = type; |
| 194 | get_task_struct(tsk); | 197 | get_task_struct(tsk); |
| 195 | 198 | ||
| 196 | if (list_empty(&sem->wait_list)) | 199 | if (list_empty(&sem->wait_list)) |
| @@ -221,7 +224,7 @@ rwsem_down_failed_common(struct rw_semaphore *sem, | |||
| 221 | 224 | ||
| 222 | raw_spin_lock_irq(&sem->wait_lock); | 225 | raw_spin_lock_irq(&sem->wait_lock); |
| 223 | /* Try to get the writer sem, may steal from the head writer: */ | 226 | /* Try to get the writer sem, may steal from the head writer: */ |
| 224 | if (flags == RWSEM_WAITING_FOR_WRITE) | 227 | if (type == RWSEM_WAITING_FOR_WRITE) |
| 225 | if (try_get_writer_sem(sem, &waiter)) { | 228 | if (try_get_writer_sem(sem, &waiter)) { |
| 226 | raw_spin_unlock_irq(&sem->wait_lock); | 229 | raw_spin_unlock_irq(&sem->wait_lock); |
| 227 | return sem; | 230 | return sem; |
