Re: Synchronizing tsleep() and wakeup()
Eric Long writes:
Hi,
I've been trying to use tsleep() and wakeup() in a kernel extension, but it
isn't obvious to me how to enforce synchronization of these calls. (Likely,
this isn't the right mechanism for what I want. But, since I'm not sure
what I need to use, I'm bringing it up here.)
My goal is to put a thread Y to sleep until a condition is met or a time out
occurs. Thread Z is manipulating the condition, then calling wakeup on
Thread Y when it changes. But if thread Z's timing is just right (or should
I say wrong) thread Y may call tsleep after thread Z has decided whether or
not to wake it up.
Traditional UNIX tsleep/wakeup mechanism requires some external synchronization that guarantees that thing you are describing is impossible. For example, code in BSD portion of XNU that uses tsleep/wakeup is usually executed under (or should I say `within'?) a funnel, so that checking condition and entering tsleep occurs atomically with respect to the wakeup calls (funnel is automatically released by low-level scheduler code when thread actually blocks). If you don't want to use funnels, you can resort to MACH synchronization primitives, but I, personally, wouldn't recommend this, because they seem to be designed for programming model different than one normally employed by UNIX kernel code. For example, MACH semaphore remembers thread that created it, and can only be destroyed by this thread. This makes it impossible to embed such a semaphore into dynamically allocated memory object (like inode). Moreover, all semaphores created by a thread are automatically destroyed when thread exits. This seems to target applications like MACH servers. The simplest route is to create your own condition variable implementation directly on top of MACH wait_queue_* API and usimple locks (do _not_ use simple lock: this API is preprocessed to nothing). If you don't need bells-and-whistles like time-outs, condition variables (cond_init, cond_wait, cond_signal, and cond_broadcast) would require only few dozen lines of C code. This, by the way, reminds me of some problem: osfmk/kern/kern_types.h doesn't export real struct wait_queue. Instead is defines a placeholder of the same size. This means, that initializer also cannot be provided. That is, one cannot write something like static struct wait_queue wq = WAIT_QUEUE_INIT(&wq); This is cumbersome, and it would be really nice if Apple people added initializer macros for internal kernel data-structures. Nikita.
Searching for a condition lock, I came to this page:
<http://developer.apple.com/documentation/Darwin/Conceptual/KernelProgrammin
g/synchronization/chapter_15_section_3.html#//apple_ref/doc/uid/TP30000905-C
H218-TPXREF109>
Which says:
The BSD portion of Mac OS X provides tsleep, wakeup, and wakeup_one, which are
equivalent to condition variables with the addition of an optional time-out.
Since they are more commonly used for waiting a predetermined period of time,
these calls are discussed in more detail in the section 3Using tsleep2 as part
of the 3Miscellaneous Kernel Services2 chapter.
In my case, I'm not waiting for a predetermined amount of time. In fact, I
may not need to wait at all, if the other thread has changed the value, and
ultimately I only want to sleep until the value has changed or we time-out
and give up waiting for the change.
What's the best way to do this in the kernel?
Thanks,
Eri
_______________________________________________ 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)
-
Nikita Danilov