diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rwsem-spinlock.c | 23 | ||||
-rw-r--r-- | lib/rwsem.c | 26 |
2 files changed, 19 insertions, 30 deletions
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c index 5f117f37ac0a..9be8a9144978 100644 --- a/lib/rwsem-spinlock.c +++ b/lib/rwsem-spinlock.c | |||
@@ -70,26 +70,17 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) | |||
70 | 70 | ||
71 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); | 71 | waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); |
72 | 72 | ||
73 | if (!wakewrite) { | ||
74 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) | ||
75 | goto out; | ||
76 | goto dont_wake_writers; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * as we support write lock stealing, we can't set sem->activity | ||
81 | * to -1 here to indicate we get the lock. Instead, we wake it up | ||
82 | * to let it go get it again. | ||
83 | */ | ||
84 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) { | 73 | if (waiter->type == RWSEM_WAITING_FOR_WRITE) { |
85 | wake_up_process(waiter->task); | 74 | if (wakewrite) |
75 | /* Wake up a writer. Note that we do not grant it the | ||
76 | * lock - it will have to acquire it when it runs. */ | ||
77 | wake_up_process(waiter->task); | ||
86 | goto out; | 78 | goto out; |
87 | } | 79 | } |
88 | 80 | ||
89 | /* grant an infinite number of read locks to the front of the queue */ | 81 | /* grant an infinite number of read locks to the front of the queue */ |
90 | dont_wake_writers: | ||
91 | woken = 0; | 82 | woken = 0; |
92 | while (waiter->type == RWSEM_WAITING_FOR_READ) { | 83 | do { |
93 | struct list_head *next = waiter->list.next; | 84 | struct list_head *next = waiter->list.next; |
94 | 85 | ||
95 | list_del(&waiter->list); | 86 | list_del(&waiter->list); |
@@ -99,10 +90,10 @@ __rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) | |||
99 | wake_up_process(tsk); | 90 | wake_up_process(tsk); |
100 | put_task_struct(tsk); | 91 | put_task_struct(tsk); |
101 | woken++; | 92 | woken++; |
102 | if (list_empty(&sem->wait_list)) | 93 | if (next == &sem->wait_list) |
103 | break; | 94 | break; |
104 | waiter = list_entry(next, struct rwsem_waiter, list); | 95 | waiter = list_entry(next, struct rwsem_waiter, list); |
105 | } | 96 | } while (waiter->type != RWSEM_WAITING_FOR_WRITE); |
106 | 97 | ||
107 | sem->activity += woken; | 98 | sem->activity += woken; |
108 | 99 | ||
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; |