serializing token
Matthew Dillon
dillon at apollo.backplane.com
Sat Apr 24 11:06:16 PDT 2004
:Is it true that functions that can block can cause
:a release of a token? Is that actually a "must
:cause the release of a token"? If so then
:being able to print out source code and highlight
:critical sections seems like it might be more
:difficult for the new coder than say a mutex based
:locking system.
Well, I'd would say that a new coder would be more likely to create
a deadlock situation using mutexes. Also, keep in mind that you cannot
safely block holding a mutex in FreeBSD-5 (and its a bad idea to do so
in any system), which means that there is serious code pollution between
layers (an upper layer must know absolutely for sure whether a lower layer
might block in order to determine whether a mutex can be safely held
through the call to the lower layer). In Dragonfly an upper layer need
only allow for the fact that a lower layer might block in order to recheck
(if necessary) the atomicy of data being protected by a token, and there
is no code pollution whatsoever becaue the upper layer can simply assume
that a lower layer might block if the upper layer is not sure, or if you
want to program defensively.
So in fact being able to block while holding a token is a feature of
DragonFly, as long as the programmer is aware of the side effects.
:If the interrupt can get the token then it's even harder
:to draw a critical section in code where data is
:consistent. Also shouldn't some interrupts be treated with
:a higher priority than others?
:
:How can I write code with this API and know without a doubt
:that my data is how I left it.
:
:Dave
I'm sure what you mean by harder to draw a critical section. A
critical section will prevent an interrupt from occuring on the same
cpu, but critical sections are only required in certain circumstances
where a preemption might interfere with a piece of code. For example,
the slab allocator enters a critical section while manipulating the
per-cpu globaldata cache in order to avoid conflicting with itself if
it were called from a preemptive interrupt.
Writing code the API is fairly simple, but it does depend on what you
do 'inside' the area being protected by the token. The vast majority
of code that uses tokens, just as with mutexes, does not do anything fancy
within the protected area and doesn't really have to worry about any of
these issues. For the remaining code you either have to be aware of the
exact side effects (with mutexes), or you have to program defensively
if you are not sure what a lower layer will do (with tokens).
There is also a huge class of code where no rechecking is needed. Take
this for example:
if (someglobal) {
lwkt_gettoken(..)
while (someglobal) {
someglobal &= ~someotherprocedurethatmightbloc();
call procedure that might block()
}
lwkt_reltoken(..)
}
This code snippit above is using a token to protect a global variable.
It is able to optimize itself by not bothering to get the token unless
it thinks it has work to do, and then integrating the recheck case in
the while(). The token is protecting against preemptive modifications
to the global variable rather then protecting against changes made to
the global variable by the called procedures or as a side effect if
either procedure blocks.
The really complex cases are relatively few... cases involving structural
pointers such as unreferenced vnode pointers, vm_page's, and so forth.
There are plenty of ways to protect such structures. The vnode case is
probably the most complex (and it is just as complex or even more complex
when implemented with mutexes), most of the rest of the structures can be
prevented from moving around with a ref count.
-Matt
Matthew Dillon
<dillon at xxxxxxxxxxxxx>
More information about the Kernel
mailing list