Re: Simultaneous destructors
Chris Jones <[email protected]>
| Newsgroups | gmane.comp.mozilla.devel.dom |
|---|---|
| Message-ID | <[email protected]> |
Benjamin Smedberg wrote:
>> The substantial modification from the original protocol is the addition
>> of the SENTDATA state and the "moar()" message. This captures the
>> decision a child makes between wanting more data vs. cancelling. It
>> prevents two dataavailable() messages from being sent in a row. This
>> might seem strange, but we'll need this feature when the child and
>> parent are transferring network data through two shmem buffers. The
>> |moar()| message is where the child would send back to the parent a
>> handle to the "free" shmem buffer (i.e., the one it's not currently
>> using). (The parent would then fill that buffer and transfer it back to
>> the child using |datavailable()|).
>
> Oh, I misread the protocol. Although it might be good/necessary to use a
> single shmem buffer like this, it's not strictly necessary to prevent
> racing, right?
I was imaging a double-buffering scheme in which, roughly speaking, the
parent fills a buffer at the same time the child is draining another
buffer. Then when the parent fills its buffer, it sends it to the child
with OnDataAvailable() (transferring "ownership"). Upon receiving that
buffer, the child sends back its drained buffer to the parent with
Moar(), and starts draining the buffer it had just received while the
parent starts filling buffer it received in Moar().
But in this case, regardless of the data transfer scheme, the Moar()
message /is/ necessary to prevent racing. See below.
> Or to put it another way, is the following protocol is also
> race-free and allows multiple dataavailable() calls in a row?
>
> protocol Channel {
> child:
> dataavailable();
> datadone();
> oncanceled()
> parent:
> cancel();
> delete();
>
> state NORMAL:
> send dataavailable goto NORMAL;
> send datadone goto DONE;
> recv cancel goto CANCELED;
>
> state DONE:
> recv cancel goto DONE;
> recv delete goto __deleted__;
>
> state CANCELED:
> send dataavailable goto CANCELED;
> send datadone goto CANCELED;
> send oncanceled goto DONE;
> };
>
No, this is a racy protocol. BTW, I should have mentioned in the last
message that you can run these protocols through IPDL to check whether
they pass the race detector. (I have a script called "ipdlc" that
basically does |exec python $srcdir/ipdl.py $*|).
The reason this protocol is racy is exactly because it specifies that
the parent can send an indefinite number of dataavailable() messages in
a row. The child can send cancel() at any time during that indefinitely
long sequence of datavailable() messages, and if it does,
dataavailable() will arrive at the child in a state where it's not allowed.
>> I agree that two-phase deletion is complicated, but (i) it's the price
>> to be paid for race-free deletion; (ii) two-phase deletion is a kind of
>> "IPDL pattern", like "empty subprotocols", that can be documented and
>> copied by other protocols.
>
> Ok, let's try it. Hopefully we can develop some mixins/C++ helpers which
> make two-phase cancellation less confusing for developers: e.g. something
> which would automatically throw away dataavailable in the CANCELED state.
>
IMHO specifying a protocol that successfully implements two-phase
deletion is the most complicated task. The C++ code is actually pretty
simple, see my upcoming response to jduell's post.
Cheers,
Chris