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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.