[whatwg] Combining the DedicatedWorker and SharedWorker interfaces
Alexey Proskuryakov
ap at webkit.org
Fri Nov 14 01:43:10 PST 2008
Nov 14, 2008, в 3:59 AM, Ian Hickson написал(а):
>> For the sake of completeness, a connect/startConversation method on a
>> worker really should automatically open the receiving port - this is
>> what examples posted so far implied, and it would cause a lot of
>> aggravation if it didn't. I know I'm often forgetting to open the
>> port
>> when writing my tests, and it's not a very easy mistake to spot.
>
> What do you mean by "open the port"? Do you mean calling start()? If
> so,
> that should happen automatically when you set onmessage the first
> time,
> per spec.
Oh, that's my mistake - I totally didn't expect that it could have
such side effect. It seems weird that addEventListener("message", ...)
does not have such effect, does it?
>> In an async processing model, there is simply no way for the
>> receiver to
>> have a list of all objects that were posted to it - it's exactly the
>> reason for the existence of the queue that events are delivered
>> asynchronously and cannot be peeked before being delivered. For
>> example,
>> in a multi-process implementation, these events may still be across
>> process boundary.
>
> It actually doesn't really matter if there is something that has been
> posted but not yet received, because that is indistinguishable (as
> far as
> I can tell) from the case of the worker having shut down a split
> second
> before that object was posted.
I'm not sure what state you mean by "shut down" here - the spec does
not define this, and shutting down a side of an async communication
channel is complicated (see e.g. a TCP/IP state diagram). Anyway, the
contents of "the worker's ports" is used for defining "active needed
worker" and "suspendable worker" further on, which are concepts that
are very important for worker lifetime definition. If the ports in
event queue are not important, then the spec should not say that they
are included in "the worker's ports". This would resolve the
concurrency problem, but I don't think that the resulting behavior
would be desirable.
>> It is not possible to have a symmetric relationship in an
>> asynchronous
>> messaging model - we need a multi-step entagling/unentangling
>> protocol,
>> so the relationship is necessarily asymmetric. One can't freeze
>> another
>> process (or really, even another thread) to change something in it
>> synchronously.
>
> The above is not a requirement, it's just a description of the
> concept. I
> don't think anything actually depends on it being symmetric; all the
> parts
> that actually entangle ports have (or, are intended to have, maybe I
> missed some) pretty well-defined synchronisation points.
OK, say there is a pair of entangled ports in different threads/
processes, portA and portB. We concurrently post both with
postMessage, which causes the ports to be cloned. From the point of
view of first thread, PortA is now unentangled, and portA' is
entangled with portB. From the point of view of second thread, PortB
is unentangled, and portB' is entangled with portA.
Next, threads send asynchronous notifications to each other, asking to
update entangling information. First thread's notification asks portB
to become entangled with portA'. So, portB will need to forward this
notification to portB' (and possibly further, because portB' may have
been posted and cloned again). This already is unduly complicated.
Now consider that all these ports need to have destroyed sooner or
later, but not too soon. This basically means that we now have a many-
to-many distributed GC system. It was bad enough when we had to
garbage protect ports between threads, because this required
modification of the JavaScript interpreter to support a certain case
of distributed GC. But this example basically shows that we need a
full-blown distributed GC system in order to implement port cloning.
> For example, any method that entangles two ports blocks until both
> threads are synchronised
> and entangled.
This will cause deadlocks - if portB' is sent to the first thread as
portB'' in the above scheme, the lock will not let synchronization
ever finish.
> (The spec is somewhat implicit about this, but the intent is that
> workers
> really be implemented either as two system threads, one doing
> communication and one running the JS, or by one system thread that
> runs
> the JS in an interruptible fashion. In particular, doing something
> that
> synchronises with a worker isn't expected to have to wait for that
> worker
> to finish running its current JS.)
The JS thread will need to be interrupted in any case - we certainly
don't want it to read a half-written pointer from memory or something.
Adding memory barriers around access to data that can be modified
externally is not sufficient, because MessagePort algorithms are not
designed in a lock-free fashion (lock-free algorithms that only rely
on read/write atomicity do exist, but these aren't such). Locking
around all MessagePort functions will cause deadlocks, as demonstrated
above, and is generally against best practices. A middle ground may
exist, but it may not, and it's definitely hard to find.
I don't think that pursuing a design that relies on locking is
particularly promising - for the same reason that workers do not
expose shared data to JS programmers, it is highly desirable to not
rely on shared data in implementations, too (except for a few well
understood constructs, such as an event queue). So, I think that the
specs (Web Workers and HTML5 channel messaging) should be cleaned up
from anything that mentions synchronous access to entangled port's
data structures to really be verified for correctness. This is not
straightforward, and may seriously affect the API - e.g., I doubt that
passing MessagePorts around is implementable with reasonable
complexity, and there is not a lot of use in MessagePorts if they
cannot be passed around.
- WBR, Alexey Proskuryakov
More information about the whatwg
mailing list