lkml.org 
[lkml]   [2001]   [Apr]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: rw_semaphores
On Sun, 8 Apr 2001, Linus Torvalds wrote:

>
> The "down_writer_failed()" case was wrong:

Which is exactly the same problem in the original code. How about the
following patch against the original code? I hadn't sent it yet as the
test code isn't finished (hence, it's untested), but given that Andrew is
going full steam ahead, people might as well give this a try.

-ben

rwsem-2.4.4-pre1-A0.diff
diff -ur v2.4.4-pre1/arch/i386/kernel/semaphore.c work-2.4.4-pre1/arch/i386/kernel/semaphore.c
--- v2.4.4-pre1/arch/i386/kernel/semaphore.c Sat Nov 18 20:31:25 2000
+++ work-2.4.4-pre1/arch/i386/kernel/semaphore.c Mon Apr 9 09:47:02 2001
@@ -269,10 +269,9 @@
ret

2: call down_write_failed
- " LOCK "subl $" RW_LOCK_BIAS_STR ",(%eax)
- jz 1b
- jnc 2b
- jmp 3b
+ popl %ecx
+ popl %edx
+ ret
"
);

@@ -366,19 +365,56 @@
struct task_struct *tsk = current;
DECLARE_WAITQUEUE(wait, tsk);

- __up_write(sem); /* this takes care of granting the lock */
+ /* Originally we called __up_write here, but that
+ * doesn't work: the lock add operation could result
+ * in us failing to detect a bias grant. Instead,
+ * we'll use a compare and exchange to get the lock
+ * from a known state: either <= -BIAS while another
+ * waiter is still around, or > -BIAS if we were given
+ * the lock's bias.
+ */

+ do {
+ int old = atomic_read(&sem->count), new, res;
+ if (old > -RW_LOCK_BIAS)
+ return down_write_failed_biased(sem);
+ new = old + RW_LOCK_BIAS;
+ res = cmpxchg(&sem->count.counter, old, new);
+ } while (res != old);
+
+again:
+ /* We are now removed from the lock. Wait for all other
+ * waiting writers to go away.
+ */
add_wait_queue_exclusive(&sem->wait, &wait);

while (atomic_read(&sem->count) < 0) {
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sem->count) >= 0)
+ if (atomic_read(&sem->count) >= 0) {
break; /* we must attempt to acquire or bias the lock */
+ }
+
schedule();
}

remove_wait_queue(&sem->wait, &wait);
tsk->state = TASK_RUNNING;
+
+ /* Okay, try to grab the lock. */
+ for (;;) {
+ int old = atomic_read(&sem->count), new, res;
+ if (old < 0)
+ goto again;
+ new = old - RW_LOCK_BIAS;
+ res = cmpxchg(&sem->count.counter, old, new);
+ if (res != old)
+ continue;
+ if (old == RW_LOCK_BIAS)
+ break;
+ if (old >= 0)
+ return down_write_failed_biased(sem);
+ goto again;
+ }

return sem;
}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:24    [W:0.134 / U:1.684 seconds]
©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site