984a5448d6238b22ba0c9a09ccacb6c9c5b667aa
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / websockets / WorkerThreadableWebSocketChannel.cpp
1 /*
2  * Copyright (C) 2011, 2012 Google Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "modules/websockets/WorkerThreadableWebSocketChannel.h"
34
35 #include "bindings/v8/ScriptCallStackFactory.h"
36 #include "core/dom/CrossThreadTask.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/ExecutionContext.h"
39 #include "core/fileapi/Blob.h"
40 #include "core/inspector/ScriptCallFrame.h"
41 #include "core/inspector/ScriptCallStack.h"
42 #include "core/workers/WorkerLoaderProxy.h"
43 #include "core/workers/WorkerRunLoop.h"
44 #include "core/workers/WorkerThread.h"
45 #include "modules/websockets/MainThreadWebSocketChannel.h"
46 #include "modules/websockets/NewWebSocketChannelImpl.h"
47 #include "modules/websockets/ThreadableWebSocketChannelClientWrapper.h"
48 #include "platform/RuntimeEnabledFeatures.h"
49 #include "public/platform/Platform.h"
50 #include "public/platform/WebWaitableEvent.h"
51 #include "wtf/ArrayBuffer.h"
52 #include "wtf/Assertions.h"
53 #include "wtf/Functional.h"
54 #include "wtf/MainThread.h"
55
56 namespace WebCore {
57
58 // Created and destroyed on the worker thread. All setters of this class are
59 // called on the main thread, while all getters are called on the worker
60 // thread. signalWorkerThread() must be called before any getters are called.
61 class ThreadableWebSocketChannelSyncHelper {
62 public:
63     static PassOwnPtr<ThreadableWebSocketChannelSyncHelper> create(PassOwnPtr<blink::WebWaitableEvent> event)
64     {
65         return adoptPtr(new ThreadableWebSocketChannelSyncHelper(event));
66     }
67
68     // All setters are called on the main thread.
69     void setConnectRequestResult(bool connectRequestResult)
70     {
71         m_connectRequestResult = connectRequestResult;
72     }
73     void setSendRequestResult(WebSocketChannel::SendResult sendRequestResult)
74     {
75         m_sendRequestResult = sendRequestResult;
76     }
77
78     // All getter are called on the worker thread.
79     bool connectRequestResult() const
80     {
81         return m_connectRequestResult;
82     }
83     WebSocketChannel::SendResult sendRequestResult() const
84     {
85         return m_sendRequestResult;
86     }
87
88     // This should be called after all setters are called and before any
89     // getters are called.
90     void signalWorkerThread()
91     {
92         m_event->signal();
93     }
94
95     blink::WebWaitableEvent* event() const
96     {
97         return m_event.get();
98     }
99
100 private:
101     ThreadableWebSocketChannelSyncHelper(PassOwnPtr<blink::WebWaitableEvent> event)
102         : m_event(event)
103         , m_connectRequestResult(false)
104         , m_sendRequestResult(WebSocketChannel::SendFail)
105     {
106     }
107
108     OwnPtr<blink::WebWaitableEvent> m_event;
109     bool m_connectRequestResult;
110     WebSocketChannel::SendResult m_sendRequestResult;
111 };
112
113 WorkerThreadableWebSocketChannel::WorkerThreadableWebSocketChannel(WorkerGlobalScope& workerGlobalScope, WebSocketChannelClient* client, const String& sourceURL, unsigned lineNumber)
114     : m_workerClientWrapper(ThreadableWebSocketChannelClientWrapper::create(client))
115     , m_bridge(Bridge::create(m_workerClientWrapper, workerGlobalScope))
116     , m_sourceURLAtConnection(sourceURL)
117     , m_lineNumberAtConnection(lineNumber)
118 {
119     ASSERT(m_workerClientWrapper.get());
120     m_bridge->initialize(sourceURL, lineNumber);
121 }
122
123 WorkerThreadableWebSocketChannel::~WorkerThreadableWebSocketChannel()
124 {
125     if (m_bridge)
126         m_bridge->disconnect();
127 }
128
129 bool WorkerThreadableWebSocketChannel::connect(const KURL& url, const String& protocol)
130 {
131     if (m_bridge)
132         return m_bridge->connect(url, protocol);
133     return false;
134 }
135
136 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::send(const String& message)
137 {
138     if (!m_bridge)
139         return WebSocketChannel::SendFail;
140     return m_bridge->send(message);
141 }
142
143 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::send(const ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
144 {
145     if (!m_bridge)
146         return WebSocketChannel::SendFail;
147     return m_bridge->send(binaryData, byteOffset, byteLength);
148 }
149
150 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::send(PassRefPtr<BlobDataHandle> blobData)
151 {
152     if (!m_bridge)
153         return WebSocketChannel::SendFail;
154     return m_bridge->send(blobData);
155 }
156
157 void WorkerThreadableWebSocketChannel::close(int code, const String& reason)
158 {
159     if (m_bridge)
160         m_bridge->close(code, reason);
161 }
162
163 void WorkerThreadableWebSocketChannel::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
164 {
165     if (!m_bridge)
166         return;
167
168     RefPtrWillBeRawPtr<ScriptCallStack> callStack = createScriptCallStack(1, true);
169     if (callStack && callStack->size())  {
170         // In order to emulate the ConsoleMessage behavior,
171         // we should ignore the specified url and line number if
172         // we can get the JavaScript context.
173         m_bridge->fail(reason, level, callStack->at(0).sourceURL(), callStack->at(0).lineNumber());
174     } else if (sourceURL.isEmpty() && !lineNumber) {
175         // No information is specified by the caller - use the url
176         // and the line number at the connection.
177         m_bridge->fail(reason, level, m_sourceURLAtConnection, m_lineNumberAtConnection);
178     } else {
179         // Use the specified information.
180         m_bridge->fail(reason, level, sourceURL, lineNumber);
181     }
182 }
183
184 void WorkerThreadableWebSocketChannel::disconnect()
185 {
186     m_bridge->disconnect();
187     m_bridge.clear();
188 }
189
190 void WorkerThreadableWebSocketChannel::trace(Visitor* visitor)
191 {
192     visitor->trace(m_workerClientWrapper);
193     WebSocketChannel::trace(visitor);
194 }
195
196 WorkerThreadableWebSocketChannel::Peer::Peer(PassRefPtr<WeakReference<Peer> > reference, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper, WorkerLoaderProxy& loaderProxy, ExecutionContext* context, const String& sourceURL, unsigned lineNumber, PassOwnPtr<ThreadableWebSocketChannelSyncHelper> syncHelper)
197     : m_workerClientWrapper(clientWrapper)
198     , m_loaderProxy(loaderProxy)
199     , m_mainWebSocketChannel(nullptr)
200     , m_syncHelper(syncHelper)
201     , m_weakFactory(reference, this)
202 {
203     ASSERT(isMainThread());
204     ASSERT(m_workerClientWrapper.get());
205
206     Document* document = toDocument(context);
207     if (RuntimeEnabledFeatures::experimentalWebSocketEnabled()) {
208         m_mainWebSocketChannel = NewWebSocketChannelImpl::create(document, this, sourceURL, lineNumber);
209     } else {
210         m_mainWebSocketChannel = MainThreadWebSocketChannel::create(document, this, sourceURL, lineNumber);
211     }
212
213     m_syncHelper->signalWorkerThread();
214 }
215
216 WorkerThreadableWebSocketChannel::Peer::~Peer()
217 {
218     ASSERT(isMainThread());
219     if (m_mainWebSocketChannel)
220         m_mainWebSocketChannel->disconnect();
221 }
222
223 void WorkerThreadableWebSocketChannel::Peer::initialize(ExecutionContext* context, PassRefPtr<WeakReference<Peer> > reference, WorkerLoaderProxy* loaderProxy, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper, const String& sourceURLAtConnection, unsigned lineNumberAtConnection, PassOwnPtr<ThreadableWebSocketChannelSyncHelper> syncHelper)
224 {
225     // The caller must call destroy() to free the peer.
226     new Peer(reference, clientWrapper, *loaderProxy, context, sourceURLAtConnection, lineNumberAtConnection, syncHelper);
227 }
228
229 void WorkerThreadableWebSocketChannel::Peer::destroy()
230 {
231     ASSERT(isMainThread());
232     delete this;
233 }
234
235 void WorkerThreadableWebSocketChannel::Peer::connect(const KURL& url, const String& protocol)
236 {
237     ASSERT(isMainThread());
238     if (!m_mainWebSocketChannel) {
239         m_syncHelper->setConnectRequestResult(false);
240     } else {
241         bool connectRequestResult = m_mainWebSocketChannel->connect(url, protocol);
242         m_syncHelper->setConnectRequestResult(connectRequestResult);
243     }
244     m_syncHelper->signalWorkerThread();
245 }
246
247 void WorkerThreadableWebSocketChannel::Peer::send(const String& message)
248 {
249     ASSERT(isMainThread());
250     if (!m_mainWebSocketChannel) {
251         m_syncHelper->setSendRequestResult(WebSocketChannel::SendFail);
252     } else {
253         WebSocketChannel::SendResult sendRequestResult = m_mainWebSocketChannel->send(message);
254         m_syncHelper->setSendRequestResult(sendRequestResult);
255     }
256     m_syncHelper->signalWorkerThread();
257 }
258
259 void WorkerThreadableWebSocketChannel::Peer::sendArrayBuffer(PassOwnPtr<Vector<char> > data)
260 {
261     ASSERT(isMainThread());
262     if (!m_mainWebSocketChannel) {
263         m_syncHelper->setSendRequestResult(WebSocketChannel::SendFail);
264     } else {
265         WebSocketChannel::SendResult sendRequestResult = m_mainWebSocketChannel->send(data);
266         m_syncHelper->setSendRequestResult(sendRequestResult);
267     }
268     m_syncHelper->signalWorkerThread();
269 }
270
271 void WorkerThreadableWebSocketChannel::Peer::sendBlob(PassRefPtr<BlobDataHandle> blobData)
272 {
273     ASSERT(isMainThread());
274     if (!m_mainWebSocketChannel) {
275         m_syncHelper->setSendRequestResult(WebSocketChannel::SendFail);
276     } else {
277         WebSocketChannel::SendResult sendRequestResult = m_mainWebSocketChannel->send(blobData);
278         m_syncHelper->setSendRequestResult(sendRequestResult);
279     }
280     m_syncHelper->signalWorkerThread();
281 }
282
283 void WorkerThreadableWebSocketChannel::Peer::close(int code, const String& reason)
284 {
285     ASSERT(isMainThread());
286     if (!m_mainWebSocketChannel)
287         return;
288     m_mainWebSocketChannel->close(code, reason);
289 }
290
291 void WorkerThreadableWebSocketChannel::Peer::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
292 {
293     ASSERT(isMainThread());
294     if (!m_mainWebSocketChannel)
295         return;
296     m_mainWebSocketChannel->fail(reason, level, sourceURL, lineNumber);
297 }
298
299 void WorkerThreadableWebSocketChannel::Peer::disconnect()
300 {
301     ASSERT(isMainThread());
302     if (!m_mainWebSocketChannel)
303         return;
304     m_mainWebSocketChannel->disconnect();
305     m_mainWebSocketChannel = nullptr;
306 }
307
308 static void workerGlobalScopeDidConnect(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, const String& subprotocol, const String& extensions)
309 {
310     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
311     workerClientWrapper->didConnect(subprotocol, extensions);
312 }
313
314 void WorkerThreadableWebSocketChannel::Peer::didConnect(const String& subprotocol, const String& extensions)
315 {
316     ASSERT(isMainThread());
317     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidConnect, m_workerClientWrapper.get(), subprotocol, extensions));
318 }
319
320 static void workerGlobalScopeDidReceiveMessage(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, const String& message)
321 {
322     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
323     workerClientWrapper->didReceiveMessage(message);
324 }
325
326 void WorkerThreadableWebSocketChannel::Peer::didReceiveMessage(const String& message)
327 {
328     ASSERT(isMainThread());
329     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveMessage, m_workerClientWrapper.get(), message));
330 }
331
332 static void workerGlobalScopeDidReceiveBinaryData(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, PassOwnPtr<Vector<char> > binaryData)
333 {
334     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
335     workerClientWrapper->didReceiveBinaryData(binaryData);
336 }
337
338 void WorkerThreadableWebSocketChannel::Peer::didReceiveBinaryData(PassOwnPtr<Vector<char> > binaryData)
339 {
340     ASSERT(isMainThread());
341     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveBinaryData, m_workerClientWrapper.get(), binaryData));
342 }
343
344 static void workerGlobalScopeDidConsumeBufferedAmount(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, unsigned long consumed)
345 {
346     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
347     workerClientWrapper->didConsumeBufferedAmount(consumed);
348 }
349
350 void WorkerThreadableWebSocketChannel::Peer::didConsumeBufferedAmount(unsigned long consumed)
351 {
352     ASSERT(isMainThread());
353     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidConsumeBufferedAmount, m_workerClientWrapper.get(), consumed));
354 }
355
356 static void workerGlobalScopeDidStartClosingHandshake(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
357 {
358     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
359     workerClientWrapper->didStartClosingHandshake();
360 }
361
362 void WorkerThreadableWebSocketChannel::Peer::didStartClosingHandshake()
363 {
364     ASSERT(isMainThread());
365     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidStartClosingHandshake, m_workerClientWrapper.get()));
366 }
367
368 static void workerGlobalScopeDidClose(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, WebSocketChannelClient::ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason)
369 {
370     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
371     workerClientWrapper->didClose(closingHandshakeCompletion, code, reason);
372 }
373
374 void WorkerThreadableWebSocketChannel::Peer::didClose(ClosingHandshakeCompletionStatus closingHandshakeCompletion, unsigned short code, const String& reason)
375 {
376     ASSERT(isMainThread());
377     m_mainWebSocketChannel = nullptr;
378     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidClose, m_workerClientWrapper.get(), closingHandshakeCompletion, code, reason));
379 }
380
381 static void workerGlobalScopeDidReceiveMessageError(ExecutionContext* context, PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper)
382 {
383     ASSERT_UNUSED(context, context->isWorkerGlobalScope());
384     workerClientWrapper->didReceiveMessageError();
385 }
386
387 void WorkerThreadableWebSocketChannel::Peer::didReceiveMessageError()
388 {
389     ASSERT(isMainThread());
390     m_loaderProxy.postTaskToWorkerGlobalScope(createCallbackTask(&workerGlobalScopeDidReceiveMessageError, m_workerClientWrapper.get()));
391 }
392
393 WorkerThreadableWebSocketChannel::Bridge::Bridge(PassRefPtrWillBeRawPtr<ThreadableWebSocketChannelClientWrapper> workerClientWrapper, WorkerGlobalScope& workerGlobalScope)
394     : m_workerClientWrapper(workerClientWrapper)
395     , m_workerGlobalScope(workerGlobalScope)
396     , m_loaderProxy(m_workerGlobalScope->thread()->workerLoaderProxy())
397     , m_syncHelper(0)
398 {
399     ASSERT(m_workerClientWrapper.get());
400 }
401
402 WorkerThreadableWebSocketChannel::Bridge::~Bridge()
403 {
404     disconnect();
405 }
406
407 void WorkerThreadableWebSocketChannel::Bridge::initialize(const String& sourceURL, unsigned lineNumber)
408 {
409     RefPtr<WeakReference<Peer> > reference = WeakReference<Peer>::createUnbound();
410     m_peer = WeakPtr<Peer>(reference);
411
412     OwnPtr<ThreadableWebSocketChannelSyncHelper> syncHelper = ThreadableWebSocketChannelSyncHelper::create(adoptPtr(blink::Platform::current()->createWaitableEvent()));
413     // This pointer is guaranteed to be valid until we call terminatePeer.
414     m_syncHelper = syncHelper.get();
415
416     RefPtr<Bridge> protect(this);
417     if (!waitForMethodCompletion(createCallbackTask(&Peer::initialize, reference.release(), AllowCrossThreadAccess(&m_loaderProxy), m_workerClientWrapper.get(), sourceURL, lineNumber, syncHelper.release()))) {
418         // The worker thread has been signalled to shutdown before method completion.
419         terminatePeer();
420     }
421 }
422
423 bool WorkerThreadableWebSocketChannel::Bridge::connect(const KURL& url, const String& protocol)
424 {
425     if (hasTerminatedPeer())
426         return false;
427
428     RefPtr<Bridge> protect(this);
429     if (!waitForMethodCompletion(CallClosureTask::create(bind(&Peer::connect, m_peer, url.copy(), protocol.isolatedCopy()))))
430         return false;
431
432     return m_syncHelper->connectRequestResult();
433 }
434
435 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(const String& message)
436 {
437     if (hasTerminatedPeer())
438         return WebSocketChannel::SendFail;
439
440     RefPtr<Bridge> protect(this);
441     if (!waitForMethodCompletion(CallClosureTask::create(bind(&Peer::send, m_peer, message.isolatedCopy()))))
442         return WebSocketChannel::SendFail;
443
444     return m_syncHelper->sendRequestResult();
445 }
446
447 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(const ArrayBuffer& binaryData, unsigned byteOffset, unsigned byteLength)
448 {
449     if (hasTerminatedPeer())
450         return WebSocketChannel::SendFail;
451
452     // ArrayBuffer isn't thread-safe, hence the content of ArrayBuffer is copied into Vector<char>.
453     OwnPtr<Vector<char> > data = adoptPtr(new Vector<char>(byteLength));
454     if (binaryData.byteLength())
455         memcpy(data->data(), static_cast<const char*>(binaryData.data()) + byteOffset, byteLength);
456
457     RefPtr<Bridge> protect(this);
458     if (!waitForMethodCompletion(CallClosureTask::create(bind(&Peer::sendArrayBuffer, m_peer, data.release()))))
459         return WebSocketChannel::SendFail;
460
461     return m_syncHelper->sendRequestResult();
462 }
463
464 WebSocketChannel::SendResult WorkerThreadableWebSocketChannel::Bridge::send(PassRefPtr<BlobDataHandle> data)
465 {
466     if (hasTerminatedPeer())
467         return WebSocketChannel::SendFail;
468
469     RefPtr<Bridge> protect(this);
470     if (!waitForMethodCompletion(CallClosureTask::create(bind(&Peer::sendBlob, m_peer, data))))
471         return WebSocketChannel::SendFail;
472
473     return m_syncHelper->sendRequestResult();
474 }
475
476 void WorkerThreadableWebSocketChannel::Bridge::close(int code, const String& reason)
477 {
478     if (hasTerminatedPeer())
479         return;
480
481     m_loaderProxy.postTaskToLoader(CallClosureTask::create(bind(&Peer::close, m_peer, code, reason.isolatedCopy())));
482 }
483
484 void WorkerThreadableWebSocketChannel::Bridge::fail(const String& reason, MessageLevel level, const String& sourceURL, unsigned lineNumber)
485 {
486     if (hasTerminatedPeer())
487         return;
488
489     m_loaderProxy.postTaskToLoader(CallClosureTask::create(bind(&Peer::fail, m_peer, reason.isolatedCopy(), level, sourceURL.isolatedCopy(), lineNumber)));
490 }
491
492 void WorkerThreadableWebSocketChannel::Bridge::disconnect()
493 {
494     clearClientWrapper();
495     terminatePeer();
496 }
497
498 void WorkerThreadableWebSocketChannel::Bridge::clearClientWrapper()
499 {
500     m_workerClientWrapper->clearClient();
501 }
502
503 // Caller of this function should hold a reference to the bridge, because this function may call WebSocket::didClose() in the end,
504 // which causes the bridge to get disconnected from the WebSocket and deleted if there is no other reference.
505 bool WorkerThreadableWebSocketChannel::Bridge::waitForMethodCompletion(PassOwnPtr<ExecutionContextTask> task)
506 {
507     ASSERT(m_workerGlobalScope);
508     ASSERT(m_syncHelper);
509
510     m_loaderProxy.postTaskToLoader(task);
511
512     // We wait for the syncHelper event even if a shutdown event is fired.
513     // See https://codereview.chromium.org/267323004/#msg43 for why we need to wait this.
514     Vector<blink::WebWaitableEvent*> events;
515     events.append(m_syncHelper->event());
516     ThreadState::SafePointScope scope(ThreadState::HeapPointersOnStack);
517     blink::Platform::current()->waitMultipleEvents(events);
518     // This is checking whether a shutdown event is fired or not.
519     return !m_workerGlobalScope->thread()->runLoop().terminated();
520 }
521
522 void WorkerThreadableWebSocketChannel::Bridge::terminatePeer()
523 {
524     m_loaderProxy.postTaskToLoader(CallClosureTask::create(bind(&Peer::destroy, m_peer)));
525     // Peer::destroy() deletes m_peer and then m_syncHelper will be released.
526     // We must not touch m_syncHelper any more.
527     m_syncHelper = 0;
528
529     // We won't use this any more.
530     m_workerGlobalScope = nullptr;
531 }
532
533 } // namespace WebCore