Re: Wait Queues
Re: Wait Queues
- Subject: Re: Wait Queues
- From: Jim Magee <email@hidden>
- Date: Wed, 5 Mar 2003 16:28:04 -0500
On Wednesday, March 5, 2003, at 03:38 PM, Vivek Balasubramanyam wrote:
while (1)
{
/* synchronize with other reads */
while(lkvi_use_lock_use_when_unused(&(device->rLock)) != 0) {};
bytesAvailable = device->bufWrIdx - device->bufRdIdx;
if (bytesAvailable < 0)
bytesAvailable += device->bufSize;
if ((device->buf != NULL) &&
((bytesAvailable > 0) || (device->flags &
SMD_OUTPUT_DEVICE_FLAG_TRAILING_EOF)))
break; /* keep the lock since we'll need it anyway */
lkvi_use_lock_unuse(&(device->rLock));
/* SMD_PRINT_DEBUG_INFO (("Going to sleep")); */
lkvi_wait_queue_sleep_interruptible (&device->readQueue);
/* SMD_PRINT_DEBUG_INFO (("Woken up")); */
}
Now that I look at your code, it is prime justification for the 2 stage
mach assert_wait(), thread_block() mechanism. You "unuse" your lock
before sleeping. This opens you up to a race condition on
preemptible/smp kernels like ours. What happens if the wakeup occurs
after the lock but before you get a chance to sleep? You'll miss it
and potentially sleep forever.
Using the Mach style, it would be more like:
while(lkvi_use_lock_use_when_unused(&(device->rLock)) != 0) {};
while(1) {
...
if (bytesAvailable > 0 || ...)
break;
wait_result =
lkvi_wait_queue_assert_wait_interruptible(&device->readQueue);
if (wait_result == THREAD_WAITING) {
lkvi_use_lock_unuse(&(device->rLock));
wait_result = thread_block();
while(lkvi_use_lock_use_when_unused(&(device->rLock)) != 0) {};
}
if (wait_result == THREAD_INTERRUPTED)
break;
}
NOTE that the assertion of your intent to wait on that particular event
occurred while you still held the lock (assuring you wouldn't miss the
wakeup - assuming that the wakeup code actually takes the lock as well).
ALSO NOTE: Both the assert_wait() functions and the thread_block()
function return wait results. The assert_wait code knows your
signal/abort state and your intentions with respect to letting this
wait be interrupted. If you are already aborted, it won't even bother
asserting your intention to wait (potentially giving the opportunity to
be woken up to some other thread that isn't aborted). You only need to
block (give up the CPU, if your assert_wait "took").
You also need to check for interruptible wait status. Otherwise,
you're going to loop forever in the case that you were interrupted.
--Jim
_______________________________________________
darwin-kernel mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/darwin-kernel
Do not post admin requests to the list. They will be ignored.