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 | darwin-kernel@lists.apple.com Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/darwin-kernel Do not post admin requests to the list. They will be ignored.
participants (1)
-
Jim Magee