[WinCairo] Move unrelated features of WorkQueueWin into IPC::Connection
authorBasuke.Suzuki@sony.com <Basuke.Suzuki@sony.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jun 2018 19:36:00 +0000 (19:36 +0000)
committerBasuke.Suzuki@sony.com <Basuke.Suzuki@sony.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Jun 2018 19:36:00 +0000 (19:36 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186582

Source/WebKit:

Add EventListener private class to handle signaled tasks for I/O.
Originally they were in WTF::WorkQueueWin, but those features were not related
to WorkQueue and only used in IPC::ConnectionWin. Moved logic is more specialized
than old generalized logic. That was unneeded generalization.

Reviewed by Brent Fulgham.

* Platform/IPC/Connection.h:
(IPC::Connection::EventListener::state):
* Platform/IPC/win/ConnectionWin.cpp:
(IPC::Connection::platformInitialize):
(IPC::Connection::platformInvalidate):
(IPC::Connection::readEventHandler):
(IPC::Connection::writeEventHandler):
(IPC::Connection::invokeReadEventHandler):
(IPC::Connection::invokeWriteEventHandler):
(IPC::Connection::open):
(IPC::Connection::sendOutgoingMessage):
(IPC::Connection::EventListener::open):
(IPC::Connection::EventListener::callback):
(IPC::Connection::EventListener::close):

Source/WTF:

Remove unrelated feature from WorkQueueWin.

Reviewed by Brent Fulgham.

* wtf/PlatformWin.cmake: Remove WorkItemContext.*
* wtf/WorkQueue.cpp:
* wtf/WorkQueue.h:
* wtf/win/Win32Handle.h:
* wtf/win/WorkItemContext.cpp: Removed.
* wtf/win/WorkItemContext.h: Removed.
* wtf/win/WorkQueueWin.cpp:
(WTF::WorkQueue::handleCallback): Deleted.
(WTF::WorkQueue::registerHandle): Deleted.
(WTF::WorkQueue::unregisterAndCloseHandle): Deleted.
(WTF::WorkQueue::unregisterWaitAndDestroyItemSoon): Deleted.
(WTF::WorkQueue::unregisterWaitAndDestroyItemCallback): Deleted.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@232888 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WTF/ChangeLog
Source/WTF/wtf/PlatformWin.cmake
Source/WTF/wtf/WorkQueue.cpp
Source/WTF/wtf/WorkQueue.h
Source/WTF/wtf/win/Win32Handle.h
Source/WTF/wtf/win/WorkItemContext.cpp [deleted file]
Source/WTF/wtf/win/WorkItemContext.h [deleted file]
Source/WTF/wtf/win/WorkQueueWin.cpp
Source/WebKit/ChangeLog
Source/WebKit/Platform/IPC/Connection.h
Source/WebKit/Platform/IPC/win/ConnectionWin.cpp

index 4f1c316..f6a0ee9 100644 (file)
@@ -1,3 +1,25 @@
+2018-06-15  Basuke Suzuki  <Basuke.Suzuki@sony.com>
+
+        [WinCairo] Move unrelated features of WorkQueueWin into IPC::Connection
+        https://bugs.webkit.org/show_bug.cgi?id=186582
+
+        Remove unrelated feature from WorkQueueWin.
+
+        Reviewed by Brent Fulgham.
+
+        * wtf/PlatformWin.cmake: Remove WorkItemContext.*
+        * wtf/WorkQueue.cpp:
+        * wtf/WorkQueue.h:
+        * wtf/win/Win32Handle.h:
+        * wtf/win/WorkItemContext.cpp: Removed.
+        * wtf/win/WorkItemContext.h: Removed.
+        * wtf/win/WorkQueueWin.cpp:
+        (WTF::WorkQueue::handleCallback): Deleted.
+        (WTF::WorkQueue::registerHandle): Deleted.
+        (WTF::WorkQueue::unregisterAndCloseHandle): Deleted.
+        (WTF::WorkQueue::unregisterWaitAndDestroyItemSoon): Deleted.
+        (WTF::WorkQueue::unregisterWaitAndDestroyItemCallback): Deleted.
+
 2018-06-13  Keith Miller  <keith_miller@apple.com>
 
         AutomaticThread should have a way to provide a thread name
index 014d739..4685196 100644 (file)
@@ -4,7 +4,6 @@ list(APPEND WTF_PUBLIC_HEADERS
     win/GDIObject.h
     win/SoftLinking.h
     win/Win32Handle.h
-    win/WorkItemContext.h
 )
 
 list(APPEND WTF_SOURCES
@@ -16,7 +15,6 @@ list(APPEND WTF_SOURCES
     win/MemoryFootprintWin.cpp
     win/MemoryPressureHandlerWin.cpp
     win/RunLoopWin.cpp
-    win/WorkItemContext.cpp
     win/WorkQueueWin.cpp
 )
 
index 063d72c..248db08 100644 (file)
 #include <wtf/Threading.h>
 #include <wtf/text/WTFString.h>
 
-#if USE(WINDOWS_EVENT_LOOP)
-#include <wtf/win/WorkItemContext.h>
-#endif
-
 namespace WTF {
 
 Ref<WorkQueue> WorkQueue::create(const char* name, Type type, QOS qos)
index 85eca62..4ecd2b5 100644 (file)
 
 namespace WTF {
 
-#if USE(WINDOWS_EVENT_LOOP)
-class WorkItemContext;
-#endif
-
 class WorkQueue final : public FunctionDispatcher {
 
 public:
@@ -81,9 +77,6 @@ public:
     dispatch_queue_t dispatchQueue() const { return m_dispatchQueue; }
 #elif USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
     RunLoop& runLoop() const { return *m_runLoop; }
-#elif USE(WINDOWS_EVENT_LOOP)
-    WTF_EXPORT_PRIVATE void registerHandle(HANDLE, Function<void()>&&);
-    WTF_EXPORT_PRIVATE void unregisterAndCloseHandle(HANDLE);
 #endif
 
 private:
@@ -93,16 +86,12 @@ private:
     void platformInvalidate();
 
 #if USE(WINDOWS_EVENT_LOOP)
-    static void CALLBACK handleCallback(void* context, BOOLEAN timerOrWaitFired);
     static void CALLBACK timerCallback(void* context, BOOLEAN timerOrWaitFired);
     static DWORD WINAPI workThreadCallback(void* context);
 
     bool tryRegisterAsWorkThread();
     void unregisterAsWorkThread();
     void performWorkOnRegisteredWorkThread();
-
-    static void unregisterWaitAndDestroyItemSoon(Ref<WorkItemContext>&&);
-    static DWORD WINAPI unregisterWaitAndDestroyItemCallback(void* context);
 #endif
 
 #if USE(COCOA_EVENT_LOOP)
@@ -112,9 +101,7 @@ private:
     volatile LONG m_isWorkThreadRegistered;
 
     Lock m_functionQueueLock;
-    Lock m_itemsMapLock;
     Vector<Function<void()>> m_functionQueue;
-    HashMap<HANDLE, Ref<WorkItemContext>> m_itemsMap;
 
     HANDLE m_timerQueue;
 #elif USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
index a6f1df3..aa7f490 100644 (file)
@@ -33,8 +33,6 @@ namespace WTF {
 class Win32Handle {
     WTF_MAKE_NONCOPYABLE(Win32Handle);
 
-    friend class WorkQueue;
-
 public:
     Win32Handle() : m_handle(INVALID_HANDLE_VALUE) { }
     explicit Win32Handle(HANDLE handle) : m_handle(handle) { }
diff --git a/Source/WTF/wtf/win/WorkItemContext.cpp b/Source/WTF/wtf/win/WorkItemContext.cpp
deleted file mode 100755 (executable)
index 9ec11a9..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
- * Copyright (C) 2017 Sony Interactive Entertainment Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "WorkItemContext.h"
-
-#include <Windows.h>
-#include <wtf/Threading.h>
-#include <wtf/WorkQueue.h>
-
-namespace WTF {
-
-WorkItemContext::WorkItemContext(HANDLE handle, HANDLE waitHandle, Function<void()>&& function, WorkQueue* queue)
-    : m_handle(handle)
-    , m_waitHandle(waitHandle)
-    , m_function(WTFMove(function))
-    , m_queue(queue)
-{
-}
-
-Ref<WorkItemContext> WorkItemContext::create(HANDLE handle, HANDLE waitHandle, Function<void()>&& function, WorkQueue* queue)
-{
-    return adoptRef(*new WorkItemContext(handle, waitHandle, WTFMove(function), queue));
-}
-
-WorkItemContext::~WorkItemContext()
-{
-}
-
-} // namespace WTF
diff --git a/Source/WTF/wtf/win/WorkItemContext.h b/Source/WTF/wtf/win/WorkItemContext.h
deleted file mode 100644 (file)
index 0aa15c7..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
- * Portions Copyright (c) 2010 Motorola Mobility, Inc.  All rights reserved.
- * Copyright (C) 2017 Sony Interactive Entertainment Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <Windows.h>
-#include <functional>
-#include <wtf/FunctionDispatcher.h>
-#include <wtf/RefPtr.h>
-#include <wtf/ThreadSafeRefCounted.h>
-#include <wtf/win/Win32Handle.h>
-
-namespace WTF {
-
-class WorkQueue;
-
-class WorkItemContext : public ThreadSafeRefCounted<WorkItemContext> {
-
-public:
-    static Ref<WorkItemContext> create(HANDLE, HANDLE, Function<void()>&&, WorkQueue*);
-    virtual ~WorkItemContext();
-
-    Win32Handle& handle() { return m_handle; }
-    Win32Handle& waitHandle() { return m_waitHandle; }
-    Function<void()>& function() { return m_function; }
-    WorkQueue* queue() const { return m_queue.get(); }
-
-private:
-    WorkItemContext(HANDLE, HANDLE, Function<void()>&&, WorkQueue*);
-
-    Win32Handle m_handle;
-    Win32Handle m_waitHandle;
-    Function<void()> m_function;
-    RefPtr<WorkQueue> m_queue;
-};
-
-}
index 41bfde0..78230c0 100644 (file)
 
 #include <wtf/MathExtras.h>
 #include <wtf/Threading.h>
-#include <wtf/win/WorkItemContext.h>
 
 namespace WTF {
 
-void WorkQueue::handleCallback(void* data, BOOLEAN timerOrWaitFired)
-{
-    ASSERT_ARG(data, data);
-    ASSERT_ARG(timerOrWaitFired, !timerOrWaitFired);
-
-    WorkItemContext* context = static_cast<WorkItemContext*>(data);
-    WorkQueue* queue = context->queue();
-
-    RefPtr<WorkItemContext> protector(context);
-    queue->dispatch([protector] {
-        protector->function()();
-    });
-}
-
-void WorkQueue::registerHandle(HANDLE handle, Function<void()>&& function)
-{
-    Ref<WorkItemContext> context = WorkItemContext::create(handle, nullptr, WTFMove(function), this);
-
-    if (!::RegisterWaitForSingleObject(&context->waitHandle().m_handle, handle, handleCallback, context.ptr(), INFINITE, WT_EXECUTEDEFAULT))
-        ASSERT_WITH_MESSAGE(m_timerQueue, "::RegisterWaitForSingleObject %lu", ::GetLastError());
-
-    auto locker = holdLock(m_itemsMapLock);
-    ASSERT_ARG(handle, !m_itemsMap.contains(handle));
-    m_itemsMap.set(handle, WTFMove(context));
-}
-
-void WorkQueue::unregisterAndCloseHandle(HANDLE handle)
-{
-    auto locker = holdLock(m_itemsMapLock);
-    ASSERT_ARG(handle, m_itemsMap.contains(handle));
-
-    unregisterWaitAndDestroyItemSoon(m_itemsMap.take(handle).value());
-}
-
 DWORD WorkQueue::workThreadCallback(void* context)
 {
     ASSERT_ARG(context, context);
@@ -222,26 +187,4 @@ void WorkQueue::dispatchAfter(Seconds duration, Function<void()>&& function)
     context.leakRef();
 }
 
-void WorkQueue::unregisterWaitAndDestroyItemSoon(Ref<WorkItemContext>&& workItem)
-{
-    // We're going to make a blocking call to ::UnregisterWaitEx before closing the handle. (The
-    // blocking version of ::UnregisterWaitEx is much simpler than the non-blocking version.) If we
-    // do this on the current thread, we'll deadlock if we're currently in a callback function for
-    // the wait we're unregistering. So instead we do it asynchronously on some other worker thread.
-    ::QueueUserWorkItem(unregisterWaitAndDestroyItemCallback, workItem.ptr(), WT_EXECUTEDEFAULT);
-}
-
-DWORD WINAPI WorkQueue::unregisterWaitAndDestroyItemCallback(void* data)
-{
-    ASSERT_ARG(data, data);
-    WorkItemContext* context = static_cast<WorkItemContext*>(data);
-
-    // Now that we know we're not in a callback function for the wait we're unregistering, we can
-    // make a blocking call to ::UnregisterWaitEx.
-    if (!::UnregisterWaitEx(context->waitHandle().get(), INVALID_HANDLE_VALUE))
-        ASSERT_WITH_MESSAGE(false, "::UnregisterWaitEx failed with '%s'", ::GetLastError());
-
-    return 0;
-}
-
 } // namespace WTF
index 34c846f..406d457 100644 (file)
@@ -1,3 +1,30 @@
+2018-06-15  Basuke Suzuki  <Basuke.Suzuki@sony.com>
+
+        [WinCairo] Move unrelated features of WorkQueueWin into IPC::Connection
+        https://bugs.webkit.org/show_bug.cgi?id=186582
+
+        Add EventListener private class to handle signaled tasks for I/O.
+        Originally they were in WTF::WorkQueueWin, but those features were not related
+        to WorkQueue and only used in IPC::ConnectionWin. Moved logic is more specialized
+        than old generalized logic. That was unneeded generalization.
+
+        Reviewed by Brent Fulgham.
+
+        * Platform/IPC/Connection.h:
+        (IPC::Connection::EventListener::state):
+        * Platform/IPC/win/ConnectionWin.cpp:
+        (IPC::Connection::platformInitialize):
+        (IPC::Connection::platformInvalidate):
+        (IPC::Connection::readEventHandler):
+        (IPC::Connection::writeEventHandler):
+        (IPC::Connection::invokeReadEventHandler):
+        (IPC::Connection::invokeWriteEventHandler):
+        (IPC::Connection::open):
+        (IPC::Connection::sendOutgoingMessage):
+        (IPC::Connection::EventListener::open):
+        (IPC::Connection::EventListener::callback):
+        (IPC::Connection::EventListener::close):
+
 2018-06-15  Brady Eidson  <beidson@apple.com>
 
         Crash in both StorageProcess and UIProcess when using custom WKWebsiteDataStores for data management.
index 8c380b3..f2598f6 100644 (file)
@@ -343,12 +343,29 @@ private:
     // Called on the connection queue.
     void readEventHandler();
     void writeEventHandler();
+    void invokeReadEventHandler();
+    void invokeWriteEventHandler();
+
+    class EventListener {
+    public:
+        void open(Function<void()>&&);
+        void close();
+
+        OVERLAPPED& state() { return m_state; }
+
+    private:
+        static void callback(void*, BOOLEAN);
+
+        OVERLAPPED m_state;
+        HANDLE m_waitHandle { INVALID_HANDLE_VALUE };
+        Function<void()> m_handler;
+    };
 
     Vector<uint8_t> m_readBuffer;
-    OVERLAPPED m_readState;
+    EventListener m_readListener;
     std::unique_ptr<Encoder> m_pendingWriteEncoder;
-    OVERLAPPED m_writeState;
-    HANDLE m_connectionPipe;
+    EventListener m_writeListener;
+    HANDLE m_connectionPipe { INVALID_HANDLE_VALUE };
 #endif
 };
 
index 01faa91..3c0e850 100644 (file)
@@ -72,12 +72,6 @@ bool Connection::createServerAndClientIdentifiers(HANDLE& serverIdentifier, HAND
 
 void Connection::platformInitialize(Identifier identifier)
 {
-    memset(&m_readState, 0, sizeof(m_readState));
-    m_readState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0);
-
-    memset(&m_writeState, 0, sizeof(m_writeState));
-    m_writeState.hEvent = ::CreateEventW(0, FALSE, FALSE, 0);
-
     m_connectionPipe = identifier;
 }
 
@@ -88,11 +82,8 @@ void Connection::platformInvalidate()
 
     m_isConnected = false;
 
-    m_connectionQueue->unregisterAndCloseHandle(m_readState.hEvent);
-    m_readState.hEvent = 0;
-
-    m_connectionQueue->unregisterAndCloseHandle(m_writeState.hEvent);
-    m_writeState.hEvent = 0;
+    m_readListener.close();
+    m_writeListener.close();
 
     ::CloseHandle(m_connectionPipe);
     m_connectionPipe = INVALID_HANDLE_VALUE;
@@ -106,7 +97,7 @@ void Connection::readEventHandler()
     while (true) {
         // Check if we got some data.
         DWORD numberOfBytesRead = 0;
-        if (!::GetOverlappedResult(m_connectionPipe, &m_readState, &numberOfBytesRead, FALSE)) {
+        if (!::GetOverlappedResult(m_connectionPipe, &m_readListener.state(), &numberOfBytesRead, FALSE)) {
             DWORD error = ::GetLastError();
             switch (error) {
             case ERROR_BROKEN_PIPE:
@@ -133,7 +124,7 @@ void Connection::readEventHandler()
                     break;
 
                 m_readBuffer.grow(m_readBuffer.size() + bytesToRead);
-                if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readState)) {
+                if (!::ReadFile(m_connectionPipe, m_readBuffer.data() + numberOfBytesRead, bytesToRead, 0, &m_readListener.state())) {
                     DWORD error = ::GetLastError();
                     ASSERT_NOT_REACHED();
                     return;
@@ -182,7 +173,7 @@ void Connection::readEventHandler()
 
         // Either read the next available message (which should occur synchronously), or start an
         // asynchronous read of the next message that becomes available.
-        BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readState);
+        BOOL result = ::ReadFile(m_connectionPipe, m_readBuffer.data(), m_readBuffer.size(), 0, &m_readListener.state());
         if (result) {
             // There was already a message waiting in the pipe, and we read it synchronously.
             // Process it.
@@ -218,7 +209,7 @@ void Connection::writeEventHandler()
         return;
 
     DWORD numberOfBytesWritten = 0;
-    if (!::GetOverlappedResult(m_connectionPipe, &m_writeState, &numberOfBytesWritten, FALSE)) {
+    if (!::GetOverlappedResult(m_connectionPipe, &m_writeListener.state(), &numberOfBytesWritten, FALSE)) {
         DWORD error = ::GetLastError();
 
         if (error == ERROR_IO_INCOMPLETE) {
@@ -240,26 +231,36 @@ void Connection::writeEventHandler()
     sendOutgoingMessages();
 }
 
+void Connection::invokeReadEventHandler()
+{
+    m_connectionQueue->dispatch([this, protectedThis = makeRef(*this)] {
+        readEventHandler();
+    });
+}
+
+void Connection::invokeWriteEventHandler()
+{
+    m_connectionQueue->dispatch([this, protectedThis = makeRef(*this)] {
+        writeEventHandler();
+    });
+}
+
 bool Connection::open()
 {
     // We connected the two ends of the pipe in createServerAndClientIdentifiers.
     m_isConnected = true;
 
-    RefPtr<Connection> protectedThis(this);
-
     // Start listening for read and write state events.
-    m_connectionQueue->registerHandle(m_readState.hEvent, [protectedThis] {
-        protectedThis->readEventHandler();
+    m_readListener.open([this] {
+        invokeReadEventHandler();
     });
 
-    m_connectionQueue->registerHandle(m_writeState.hEvent, [protectedThis] {
-        protectedThis->writeEventHandler();
+    m_writeListener.open([this] {
+        invokeWriteEventHandler();
     });
 
     // Schedule a read.
-    m_connectionQueue->dispatch([protectedThis] {
-        protectedThis->readEventHandler();
-    });
+    invokeReadEventHandler();
     return true;
 }
 
@@ -284,7 +285,7 @@ bool Connection::sendOutgoingMessage(std::unique_ptr<Encoder> encoder)
 
     // Write the outgoing message.
 
-    if (::WriteFile(m_connectionPipe, encoder->buffer(), encoder->bufferSize(), 0, &m_writeState)) {
+    if (::WriteFile(m_connectionPipe, encoder->buffer(), encoder->bufferSize(), 0, &m_writeListener.state())) {
         // We successfully sent this message.
         return true;
     }
@@ -318,4 +319,45 @@ void Connection::didReceiveSyncReply(OptionSet<SendSyncOption>)
 {
 }
 
+void Connection::EventListener::open(Function<void()>&& handler)
+{
+    m_handler = WTFMove(handler);
+
+    memset(&m_state, 0, sizeof(m_state));
+    m_state.hEvent = ::CreateEventW(0, FALSE, FALSE, 0);
+
+    BOOL result;
+    result = ::RegisterWaitForSingleObject(&m_waitHandle, m_state.hEvent, callback, this, INFINITE, WT_EXECUTEDEFAULT);
+    ASSERT(result);
+}
+
+void Connection::EventListener::callback(void* data, BOOLEAN timerOrWaitFired)
+{
+    ASSERT_ARG(data, data);
+    ASSERT_ARG(timerOrWaitFired, !timerOrWaitFired);
+
+    auto* listener = static_cast<Connection::EventListener*>(data);
+    listener->m_handler();
+}
+
+void Connection::EventListener::close()
+{
+    // We call ::UnregisterWaitEx directly here. Since ::UnregisterWaitEx drains all the remaining tasks here,
+    // it would cause deadlock if this function itself is executed in Windows callback functions. But this call
+    // is safe since our callbacks immediately dispatch a task to WorkQueue. And no Windows callbacks call this
+    // Connection::EventListener::close().
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms685061(v=vs.85).aspx
+    //
+    // And do not ::CloseHandle(m_waitHandle).
+    // > Note that a wait handle cannot be used in functions that require an object handle, such as CloseHandle.
+    // https://msdn.microsoft.com/en-us/library/windows/desktop/ms685061(v=vs.85).aspx
+    ::UnregisterWaitEx(m_waitHandle, INVALID_HANDLE_VALUE);
+    m_waitHandle = INVALID_HANDLE_VALUE;
+
+    ::CloseHandle(m_state.hEvent);
+    m_state.hEvent = 0;
+
+    m_handler = Function<void()>();
+}
+
 } // namespace IPC