diff options
author | Michel Lespinasse <walken@google.com> | 2013-05-07 09:45:58 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-05-07 10:20:16 -0400 |
commit | 8cf5322ce69afea1fab6a6270db24d057d664798 (patch) | |
tree | a7b49b135dc7703a4a709562178a847fb9bc4f77 /lib/rwsem.c | |
parent | 9b0fc9c09f1b262b7fe697eba6b05095d78850e5 (diff) |
rwsem: simplify __rwsem_do_wake
This is mostly for cleanup value:
- We don't need several gotos to handle the case where the first
waiter is a writer. Two simple tests will do (and generate very
similar code).
- In the remainder of the function, we know the first waiter is a reader,
so we don't have to double check that. We can use do..while loops
to iterate over the readers to wake (generates slightly better code).
Signed-off-by: Michel Lespinasse <walken@google.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/rwsem.c')
-rw-r--r-- | lib/rwsem.c | 26 |
1 files changed, 12 insertions, 14 deletions
diff --git a/lib/rwsem.c b/lib/rwsem.c index 0d50e46d5b0c..9a675fa9d78e 100644 --- a/lib/rwsem.c +++ b/lib/rwsem.c | |||
@@ -68,20 +68,17 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type) | |||
68 | signed long woken, loop, adjustment; | 68 | signed long woken, loop, adjustment; |
69 | 69 | ||
70 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); | 70 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); |
71 | if (waiter->type != RWSEM_WAITING_FOR_WRITE) | 71 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) { |
72 | goto readers_only; | 72 | if (wake_type != RWSEM_WAKE_READ_OWNED) |
73 | 73 | /* Wake writer at the front of the queue, but do not | |
74 | if (wake_type == RWSEM_WAKE_READ_OWNED) | 74 | * grant it the lock yet as we want other writers |
75 | /* Another active reader was observed, so wakeup is not | 75 | * to be able to steal it. Readers, on the other hand, |
76 | * likely to succeed. Save the atomic op. | 76 | * will block as they will notice the queued writer. |
77 | */ | 77 | */ |
78 | wake_up_process(waiter->task); | ||
78 | goto out; | 79 | goto out; |
80 | } | ||
79 | 81 | ||
80 | /* Wake up the writing waiter and let the task grab the sem: */ | ||
81 | wake_up_process(waiter->task); | ||
82 | goto out; | ||
83 | |||
84 | readers_only: | ||
85 | /* If we come here from up_xxxx(), another thread might have reached | 82 | /* If we come here from up_xxxx(), another thread might have reached |
86 | * rwsem_down_failed_common() before we acquired the spinlock and | 83 | * rwsem_down_failed_common() before we acquired the spinlock and |
87 | * woken up a waiter, making it now active. We prefer to check for | 84 | * woken up a waiter, making it now active. We prefer to check for |
@@ -125,7 +122,8 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type) | |||
125 | rwsem_atomic_add(adjustment, sem); | 122 | rwsem_atomic_add(adjustment, sem); |
126 | 123 | ||
127 | next = sem->wait_list.next; | 124 | next = sem->wait_list.next; |
128 | for (loop = woken; loop > 0; loop--) { | 125 | loop = woken; |
126 | do { | ||
129 | waiter = list_entry(next, struct rwsem_waiter, list); | 127 | waiter = list_entry(next, struct rwsem_waiter, list); |
130 | next = waiter->list.next; | 128 | next = waiter->list.next; |
131 | tsk = waiter->task; | 129 | tsk = waiter->task; |
@@ -133,7 +131,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wake_type) | |||
133 | waiter->task = NULL; | 131 | waiter->task = NULL; |
134 | wake_up_process(tsk); | 132 | wake_up_process(tsk); |
135 | put_task_struct(tsk); | 133 | put_task_struct(tsk); |
136 | } | 134 | } while (--loop); |
137 | 135 | ||
138 | sem->wait_list.next = next; | 136 | sem->wait_list.next = next; |
139 | next->prev = &sem->wait_list; | 137 | next->prev = &sem->wait_list; |