|Xlib headers insist on this for some reason... Nuke it because
it'll override our member name
|The existing length of the string. Do not call during BulkWrite().
|XMLHttpRequest in workers
XHR in workers is implemented by proxying calls/events/etc between the
worker thread and an XMLHttpRequest on the main thread. The glue
object here is the Proxy, which lives on both threads. All other objects
live on either the main thread (the XMLHttpRequest) or the worker thread
(the worker and XHR private objects).
The main thread XHR is always operated in async mode, even for sync XHR
in workers. Calls made on the worker thread are proxied to the main thread
synchronously (meaning the worker thread is blocked until the call
returns). Each proxied call spins up a sync queue, which captures any
synchronously dispatched events and ensures that they run synchronously
on the worker as well. Asynchronously dispatched events are posted to the
worker thread to run asynchronously. Some of the XHR state is mirrored on
the worker thread to avoid needing a cross-thread call on every property
The XHR private is stored in the private slot of the XHR JSObject on the
worker thread. It is destroyed when that JSObject is GCd. The private
roots its JSObject while network activity is in progress. It also
adds itself as a feature to the worker to give itself a chance to clean up
if the worker goes away during an XHR call. It is important that the
rooting and feature registration (collectively called pinning) happens at
the proper times. If we pin for too long we can cause memory leaks or even
shutdown hangs. If we don't pin for long enough we introduce a GC hazard.
The XHR is pinned from the time Send is called to roughly the time loadend
is received. There are some complications involved with Abort and XHR
reuse. We maintain a counter on the main thread of how many times Send was
called on this XHR, and we decrement the counter every time we receive a
loadend event. When the counter reaches zero we dispatch a runnable to the
worker thread to unpin the XHR. We only decrement the counter if the
dispatch was successful, because the worker may no longer be accepting
regular runnables. In the event that we reach Proxy::Teardown and there
the outstanding Send count is still non-zero, we dispatch a control
runnable which is guaranteed to run.
NB: Some of this could probably be simplified now that we have the
inner/outer channel ids.