2011-01-24 Kimmo Kinnunen <kimmo.t.kinnunen@nokia.com>
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Jan 2011 12:58:32 +0000 (12:58 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 24 Jan 2011 12:58:32 +0000 (12:58 +0000)
        Reviewed by Kenneth Rohde Christiansen.

        [Qt] Remove CleanupHandler by passing file descriptors.

        Deleting files in signal handler of UI process is not a good idea,
        because the memory where filenames are stored might not be valid
        after a crash.

        To avoid the need of using signal handlers for cleanup,
        change following:
          1) Avoid passing filenames between processes, pass fds
          2) When mmap'ing files, delete them immediately after
             opening and mmap'ing them.
          3) Pass sockets with fds during fork+exec instead of
             passing them via the filesystem.
          4) Use mmap'ed files for implementation of SharedMemory.
             QSharedMemory does not support cleanup correctly.

        Consquences:
          - Move MappedMemory to SharedMemory, make UpdateChunk use this.
          - Implement CoreIPC::Attachment using mmaped files.
          - Send messages using datagram socket. This solution works
            similiarly to Mach ports on Mac.
          - Send big messages out-of-line and thus avoid increasing
            the receive buffer.
          - Remove MemoryMappedPool and rely on libc/kernel caching
            of mmapped areas.
          - Unmap memory areas after use.
          - When UI process crashes, kill the web process using SIGKILL.
            This is possible again because cleanup handler is not needed.

        [WK2][Qt] Multiple problems with MemoryMappedPool
        https://bugs.webkit.org/show_bug.cgi?id=51984

        * Platform/CoreIPC/Attachment.cpp:
        (CoreIPC::Attachment::Attachment):
        * Platform/CoreIPC/Attachment.h:
        (CoreIPC::Attachment::size):
        (CoreIPC::Attachment::releaseFileDescriptor):
        (CoreIPC::Attachment::fileDescriptor):
        * Platform/CoreIPC/Connection.h:
        * Platform/CoreIPC/qt/ConnectionQt.cpp:
        (CoreIPC::MessageInfo::MessageInfo):
        (CoreIPC::MessageInfo::setMessageBodyOOL):
        (CoreIPC::MessageInfo::isMessageBodyOOL):
        (CoreIPC::MessageInfo::bodySize):
        (CoreIPC::MessageInfo::messageID):
        (CoreIPC::MessageInfo::attachmentCount):
        (CoreIPC::Connection::platformInitialize):
        (CoreIPC::Connection::platformInvalidate):
        (CoreIPC::SocketNotifierDisableGuard::SocketNotifierDisableGuard):
        (CoreIPC::SocketNotifierDisableGuard::~SocketNotifierDisableGuard):
        (CoreIPC::Connection::readyReadHandler):
        (CoreIPC::Connection::open):
        (CoreIPC::Connection::platformCanSendOutgoingMessages):
        (CoreIPC::Connection::sendOutgoingMessage):
        * Platform/SharedMemory.h:
        * Platform/WorkQueue.h:
        * Platform/qt/MappedMemoryPool.cpp: Removed.
        * Platform/qt/MappedMemoryPool.h: Removed.
        * Platform/qt/SharedMemoryQt.cpp:
        (WebKit::SharedMemory::Handle::Handle):
        (WebKit::SharedMemory::Handle::~Handle):
        (WebKit::SharedMemory::Handle::isNull):
        (WebKit::SharedMemory::Handle::encode):
        (WebKit::SharedMemory::Handle::decode):
        (WebKit::SharedMemory::Handle::releaseToAttachment):
        (WebKit::SharedMemory::Handle::adoptFromAttachment):
        (WebKit::SharedMemory::create):
        (WebKit::accessModeMMap):
        (WebKit::SharedMemory::~SharedMemory):
        (WebKit::accessModeFile):
        (WebKit::SharedMemory::createHandle):
        * Platform/qt/WorkQueueQt.cpp:
        (WorkQueue::registerSocketEventHandler):
        * Shared/qt/UpdateChunk.cpp:
        (WebKit::UpdateChunk::UpdateChunk):
        (WebKit::UpdateChunk::~UpdateChunk):
        (WebKit::UpdateChunk::encode):
        (WebKit::UpdateChunk::decode):
        (WebKit::UpdateChunk::createImage):
        * Shared/qt/UpdateChunk.h:
        * UIProcess/Launcher/ProcessLauncher.h:
        * UIProcess/Launcher/qt/ProcessLauncherQt.cpp:
        (WebKit::QtWebProcess::QtWebProcess):
        (WebKit::QtWebProcess::setupChildProcess):
        (WebKit::ProcessLauncher::launchProcess):
        (WebKit::ProcessLauncher::platformInvalidate):
        * UIProcess/Launcher/qt/ThreadLauncherQt.cpp:
        (WebKit::webThreadBody):
        (WebKit::ThreadLauncher::createWebThread):
        * WebKit2.pro:
        * WebProcess/qt/WebProcessMainQt.cpp:
        (WebKit::WebProcessMainQt):

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

22 files changed:
Source/WebKit2/ChangeLog
Source/WebKit2/Platform/CoreIPC/ArgumentDecoder.cpp
Source/WebKit2/Platform/CoreIPC/ArgumentEncoder.cpp
Source/WebKit2/Platform/CoreIPC/Attachment.h
Source/WebKit2/Platform/CoreIPC/Connection.h
Source/WebKit2/Platform/CoreIPC/qt/AttachmentQt.cpp [new file with mode: 0644]
Source/WebKit2/Platform/CoreIPC/qt/ConnectionQt.cpp
Source/WebKit2/Platform/SharedMemory.h
Source/WebKit2/Platform/WorkQueue.h
Source/WebKit2/Platform/qt/MappedMemoryPool.cpp [deleted file]
Source/WebKit2/Platform/qt/MappedMemoryPool.h [deleted file]
Source/WebKit2/Platform/qt/SharedMemoryQt.cpp
Source/WebKit2/Platform/qt/WorkQueueQt.cpp
Source/WebKit2/Shared/qt/UpdateChunk.cpp
Source/WebKit2/Shared/qt/UpdateChunk.h
Source/WebKit2/UIProcess/Launcher/ProcessLauncher.h
Source/WebKit2/UIProcess/Launcher/qt/ProcessLauncherQt.cpp
Source/WebKit2/UIProcess/Launcher/qt/ThreadLauncherQt.cpp
Source/WebKit2/UIProcess/WebProcessProxy.cpp
Source/WebKit2/UIProcess/qt/WebContextQt.cpp
Source/WebKit2/WebKit2.pro
Source/WebKit2/WebProcess/qt/WebProcessMainQt.cpp

index 331f0ab..a3a682c 100644 (file)
@@ -1,3 +1,100 @@
+2011-01-24  Kimmo Kinnunen  <kimmo.t.kinnunen@nokia.com>
+
+        Reviewed by Kenneth Rohde Christiansen.
+
+        [Qt] Remove CleanupHandler by passing file descriptors.
+
+        Deleting files in signal handler of UI process is not a good idea,
+        because the memory where filenames are stored might not be valid
+        after a crash.
+
+        To avoid the need of using signal handlers for cleanup,
+        change following:
+          1) Avoid passing filenames between processes, pass fds
+          2) When mmap'ing files, delete them immediately after
+             opening and mmap'ing them.
+          3) Pass sockets with fds during fork+exec instead of
+             passing them via the filesystem.
+          4) Use mmap'ed files for implementation of SharedMemory.
+             QSharedMemory does not support cleanup correctly.
+
+        Consquences:
+          - Move MappedMemory to SharedMemory, make UpdateChunk use this.
+          - Implement CoreIPC::Attachment using mmaped files.
+          - Send messages using datagram socket. This solution works
+            similiarly to Mach ports on Mac.
+          - Send big messages out-of-line and thus avoid increasing
+            the receive buffer.
+          - Remove MemoryMappedPool and rely on libc/kernel caching
+            of mmapped areas.
+          - Unmap memory areas after use.
+          - When UI process crashes, kill the web process using SIGKILL.
+            This is possible again because cleanup handler is not needed.
+
+        [WK2][Qt] Multiple problems with MemoryMappedPool
+        https://bugs.webkit.org/show_bug.cgi?id=51984
+
+        * Platform/CoreIPC/Attachment.cpp:
+        (CoreIPC::Attachment::Attachment):
+        * Platform/CoreIPC/Attachment.h:
+        (CoreIPC::Attachment::size):
+        (CoreIPC::Attachment::releaseFileDescriptor):
+        (CoreIPC::Attachment::fileDescriptor):
+        * Platform/CoreIPC/Connection.h:
+        * Platform/CoreIPC/qt/ConnectionQt.cpp:
+        (CoreIPC::MessageInfo::MessageInfo):
+        (CoreIPC::MessageInfo::setMessageBodyOOL):
+        (CoreIPC::MessageInfo::isMessageBodyOOL):
+        (CoreIPC::MessageInfo::bodySize):
+        (CoreIPC::MessageInfo::messageID):
+        (CoreIPC::MessageInfo::attachmentCount):
+        (CoreIPC::Connection::platformInitialize):
+        (CoreIPC::Connection::platformInvalidate):
+        (CoreIPC::SocketNotifierDisableGuard::SocketNotifierDisableGuard):
+        (CoreIPC::SocketNotifierDisableGuard::~SocketNotifierDisableGuard):
+        (CoreIPC::Connection::readyReadHandler):
+        (CoreIPC::Connection::open):
+        (CoreIPC::Connection::platformCanSendOutgoingMessages):
+        (CoreIPC::Connection::sendOutgoingMessage):
+        * Platform/SharedMemory.h:
+        * Platform/WorkQueue.h:
+        * Platform/qt/MappedMemoryPool.cpp: Removed.
+        * Platform/qt/MappedMemoryPool.h: Removed.
+        * Platform/qt/SharedMemoryQt.cpp:
+        (WebKit::SharedMemory::Handle::Handle):
+        (WebKit::SharedMemory::Handle::~Handle):
+        (WebKit::SharedMemory::Handle::isNull):
+        (WebKit::SharedMemory::Handle::encode):
+        (WebKit::SharedMemory::Handle::decode):
+        (WebKit::SharedMemory::Handle::releaseToAttachment):
+        (WebKit::SharedMemory::Handle::adoptFromAttachment):
+        (WebKit::SharedMemory::create):
+        (WebKit::accessModeMMap):
+        (WebKit::SharedMemory::~SharedMemory):
+        (WebKit::accessModeFile):
+        (WebKit::SharedMemory::createHandle):
+        * Platform/qt/WorkQueueQt.cpp:
+        (WorkQueue::registerSocketEventHandler):
+        * Shared/qt/UpdateChunk.cpp:
+        (WebKit::UpdateChunk::UpdateChunk):
+        (WebKit::UpdateChunk::~UpdateChunk):
+        (WebKit::UpdateChunk::encode):
+        (WebKit::UpdateChunk::decode):
+        (WebKit::UpdateChunk::createImage):
+        * Shared/qt/UpdateChunk.h:
+        * UIProcess/Launcher/ProcessLauncher.h:
+        * UIProcess/Launcher/qt/ProcessLauncherQt.cpp:
+        (WebKit::QtWebProcess::QtWebProcess):
+        (WebKit::QtWebProcess::setupChildProcess):
+        (WebKit::ProcessLauncher::launchProcess):
+        (WebKit::ProcessLauncher::platformInvalidate):
+        * UIProcess/Launcher/qt/ThreadLauncherQt.cpp:
+        (WebKit::webThreadBody):
+        (WebKit::ThreadLauncher::createWebThread):
+        * WebKit2.pro:
+        * WebProcess/qt/WebProcessMainQt.cpp:
+        (WebKit::WebProcessMainQt):
+
 2011-01-24  Andras Becsi  <abecsi@webkit.org>
 
         Reviewed by Csaba Osztrogon√°c.
index 336f72f..b7055f8 100644 (file)
@@ -46,7 +46,13 @@ ArgumentDecoder::~ArgumentDecoder()
 {
     ASSERT(m_buffer);
     fastFree(m_buffer);
+#if !PLATFORM(QT)
     // FIXME: We need to dispose of the mach ports in cases of failure.
+#else
+    Deque<Attachment>::iterator end = m_attachments.end();
+    for (Deque<Attachment>::iterator it = m_attachments.begin(); it != end; ++it)
+        it->dispose();
+#endif
 }
 
 void ArgumentDecoder::initialize(const uint8_t* buffer, size_t bufferSize)
index 1340c0a..85a7ca4 100644 (file)
@@ -49,7 +49,12 @@ ArgumentEncoder::~ArgumentEncoder()
 {
     if (m_buffer)
         fastFree(m_buffer);
+#if !PLATFORM(QT)
     // FIXME: We need to dispose of the attachments in cases of failure.
+#else
+    for (int i = 0; i < m_attachments.size(); ++i)
+        m_attachments[i].dispose();
+#endif
 }
 
 static inline size_t roundUpToAlignment(size_t value, unsigned alignment)
index 55a09c9..c057714 100644 (file)
@@ -40,12 +40,16 @@ public:
 #if PLATFORM(MAC)
         MachPortType,
         MachOOLMemoryType
+#elif PLATFORM(QT)
+        MappedMemory
 #endif
     };
 
 #if PLATFORM(MAC)
     Attachment(mach_port_name_t port, mach_msg_type_name_t disposition);
     Attachment(void* address, mach_msg_size_t size, mach_msg_copy_options_t copyOptions, bool deallocate);
+#elif PLATFORM(QT)
+    Attachment(int fileDescriptor, size_t);
 #endif
 
     Type type() const { return m_type; }
@@ -62,6 +66,13 @@ public:
     mach_msg_size_t size() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.size; }
     mach_msg_copy_options_t copyOptions() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.copyOptions; }
     bool deallocate() const { ASSERT(m_type == MachOOLMemoryType); return m_oolMemory.deallocate; }
+#elif PLATFORM(QT)
+    size_t size() const { return m_size; }
+
+    int releaseFileDescriptor() { int temp = m_fileDescriptor; m_fileDescriptor = -1; return temp; }
+    int fileDescriptor() const { return m_fileDescriptor; }
+
+    void dispose();
 #endif
 
     void encode(ArgumentEncoder*) const;
@@ -83,6 +94,9 @@ private:
             bool deallocate;
         } m_oolMemory;
     };
+#elif PLATFORM(QT)
+    int m_fileDescriptor;
+    size_t m_size;
 #endif
 };
 
index 1b009cf..58cb89c 100644 (file)
@@ -44,9 +44,8 @@
 #elif PLATFORM(WIN)
 #include <string>
 #elif PLATFORM(QT)
-#include <QString>
-class QLocalServer;
-class QLocalSocket;
+class QSocketNotifier;
+#include "PlatformProcessIdentifier.h"
 #endif
 
 class RunLoop;
@@ -98,7 +97,7 @@ public:
     typedef HANDLE Identifier;
     static bool createServerAndClientIdentifiers(Identifier& serverIdentifier, Identifier& clientIdentifier);
 #elif PLATFORM(QT)
-    typedef const QString Identifier;
+    typedef int Identifier;
 #elif PLATFORM(GTK)
     typedef int Identifier;
 #endif
@@ -109,6 +108,8 @@ public:
 
 #if PLATFORM(MAC)
     void setShouldCloseConnectionOnMachExceptions();
+#elif PLATFORM(QT)
+    void setShouldCloseConnectionOnProcessTermination(WebKit::PlatformProcessIdentifier);
 #endif
 
     bool open();
@@ -285,8 +286,8 @@ private:
 
     Vector<uint8_t> m_readBuffer;
     size_t m_currentMessageSize;
-    QLocalSocket* m_socket;
-    QString m_serverName;
+    QSocketNotifier* m_socketNotifier;
+    int m_socketDescriptor;
 #elif PLATFORM(GTK)
     void readEventHandler();
     void processCompletedMessage();
diff --git a/Source/WebKit2/Platform/CoreIPC/qt/AttachmentQt.cpp b/Source/WebKit2/Platform/CoreIPC/qt/AttachmentQt.cpp
new file mode 100644 (file)
index 0000000..66aa7d9
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "Attachment.h"
+#if PLATFORM(QT)
+#include <unistd.h>
+#include <errno.h>
+#endif
+
+
+namespace CoreIPC {
+
+Attachment::Attachment(int fileDescriptor, size_t size)
+    : m_type(MappedMemory)
+    , m_fileDescriptor(fileDescriptor)
+    , m_size(size)
+{
+    ASSERT(m_fileDescriptor);
+    ASSERT(m_size);
+}
+
+void Attachment::dispose()
+{
+    if (m_fileDescriptor != -1)
+        while (close(m_fileDescriptor) == -1 && (errno == EINTR)) { }
+}
+
+} // namespace CoreIPC
index c0736b8..5a90568 100644 (file)
 #include "ArgumentEncoder.h"
 #include "ProcessLauncher.h"
 #include "WorkItem.h"
+#include "SharedMemory.h"
+#include "WebProcessProxy.h"
 #include <QApplication>
-#include <QLocalServer>
-#include <QLocalSocket>
+#include <QSocketNotifier>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <wtf/Assertions.h>
 
 using namespace std;
 
 namespace CoreIPC {
 
-// This is what other ports use...
 static const size_t messageMaxSize = 4096;
+static const size_t attachmentMaxAmount = 255;
+
+enum {
+    MessageBodyIsOOL = 1 << 31
+};
+
+class MessageInfo {
+public:
+    MessageInfo() { }
+
+    MessageInfo(MessageID messageID, size_t bodySize, size_t initialAttachmentCount)
+        : m_messageID(messageID.toInt())
+        , m_bodySize(bodySize)
+        , m_attachmentCount(initialAttachmentCount)
+    {
+        ASSERT(!(m_messageID & MessageBodyIsOOL));
+    }
+
+    void setMessageBodyOOL()
+    {
+        ASSERT(!isMessageBodyOOL());
+
+        m_messageID |= MessageBodyIsOOL;
+        m_attachmentCount++;
+    }
+
+    bool isMessageBodyOOL() const { return m_messageID & MessageBodyIsOOL; }
+
+    size_t bodySize() const { return m_bodySize; }
+
+    MessageID messageID() const { return MessageID::fromInt(m_messageID & ~MessageBodyIsOOL); }
+
+    size_t attachmentCount() const { return m_attachmentCount; }
+
+private:
+    uint32_t m_messageID;
+    size_t m_bodySize;
+    size_t m_attachmentCount;
+};
 
 void Connection::platformInitialize(Identifier identifier)
 {
-    m_serverName = identifier;
-    m_socket = 0;
+    m_socketDescriptor = identifier;
+    m_socketNotifier = 0;
     m_readBuffer.resize(messageMaxSize);
     m_currentMessageSize = 0;
 }
 
 void Connection::platformInvalidate()
 {
-    m_socket->disconnect();
-    if (!m_isServer)
-        m_socket->deleteLater();
-    m_socket = 0;
+    if (m_socketDescriptor != -1)
+        while (close(m_socketDescriptor) == -1 && errno == EINTR) { }
+
+    if (!m_isConnected)
+        return;
+
+    delete m_socketNotifier;
+    m_socketNotifier = 0;
+    m_socketDescriptor = -1;
+    m_isConnected = false;
 }
 
+class SocketNotifierResourceGuard {
+public:
+    SocketNotifierResourceGuard(QSocketNotifier* socketNotifier)
+        : m_socketNotifier(socketNotifier)
+    {
+        m_socketNotifier->setEnabled(false);
+    }
+
+    ~SocketNotifierResourceGuard()
+    {
+        m_socketNotifier->setEnabled(true);
+    }
+
+private:
+    QSocketNotifier* const m_socketNotifier;
+};
+
+template<class T, class iterator>
+class AttachmentResourceGuard {
+public:
+    AttachmentResourceGuard(T& attachments)
+        : m_attachments(attachments)
+    {
+    }
+    ~AttachmentResourceGuard()
+    {
+        iterator end = m_attachments.end();
+        for (iterator i = m_attachments.begin(); i != end; ++i)
+            i->dispose();
+    }
+private:
+    T& m_attachments;
+};
+
 void Connection::readyReadHandler()
 {
-    while (m_socket->bytesAvailable()) {
-        if (!m_currentMessageSize) {
-            size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), sizeof(size_t));
-            ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead);
-            m_currentMessageSize = *reinterpret_cast<size_t*>(m_readBuffer.data());
-        }
+    Deque<Attachment> attachments;
+    SocketNotifierResourceGuard socketNotifierEnabler(m_socketNotifier);
+    AttachmentResourceGuard<Deque<Attachment>, Deque<Attachment>::iterator> attachementDisposer(attachments);
+
+    char attachmentDescriptorBuffer[CMSG_SPACE(sizeof(int) * (attachmentMaxAmount))];
+    struct msghdr message;
+    memset(&message, 0, sizeof(message));
+
+    struct iovec iov[1];
+    memset(&iov, 0, sizeof(iov));
+
+    message.msg_control = attachmentDescriptorBuffer;
+    message.msg_controllen = CMSG_SPACE(sizeof(int) * (attachmentMaxAmount));
+
+    iov[0].iov_base = m_readBuffer.data();
+    iov[0].iov_len = m_readBuffer.size();
+
+    message.msg_iov = iov;
+    message.msg_iovlen = 1;
+
 
-        if (m_socket->bytesAvailable() < m_currentMessageSize)
+    int messageLength = 0;
+    while ((messageLength = recvmsg(m_socketDescriptor, &message, MSG_CMSG_CLOEXEC)) == -1) {
+        if (errno != EINTR)
             return;
+    }
+
+    struct cmsghdr* controlMessage = CMSG_FIRSTHDR(&message);
+
+    MessageInfo messageInfo;
+    unsigned char* messageData = m_readBuffer.data();
+
+    memcpy(&messageInfo, messageData, sizeof(messageInfo));
+    ASSERT(messageLength == sizeof(messageInfo) + messageInfo.attachmentCount() * sizeof(size_t) + (messageInfo.isMessageBodyOOL() ? 0 : messageInfo.bodySize()));
+
+    messageData += sizeof(messageInfo);
+
+    RefPtr<WebKit::SharedMemory> oolMessageBody;
+
+    if (messageInfo.attachmentCount()) {
+        if (controlMessage && controlMessage->cmsg_level == SOL_SOCKET && controlMessage->cmsg_type == SCM_RIGHTS) {
+            size_t attachmentSizes[messageInfo.attachmentCount()];
+            memcpy(attachmentSizes, messageData, sizeof(attachmentSizes));
+
+            messageData += sizeof(attachmentSizes);
+
+            int fileDescriptors[messageInfo.attachmentCount()];
+            memcpy(fileDescriptors, CMSG_DATA(controlMessage), sizeof(fileDescriptors));
 
-        if (m_readBuffer.size() < m_currentMessageSize)
-            m_readBuffer.grow(m_currentMessageSize);
+            int attachmentCount = messageInfo.attachmentCount();
 
-        size_t numberOfBytesRead = m_socket->read(reinterpret_cast<char*>(m_readBuffer.data()), m_currentMessageSize);
-        ASSERT_UNUSED(numberOfBytesRead, numberOfBytesRead);
+            if (messageInfo.isMessageBodyOOL())
+                attachmentCount--;
 
-        // The messageID is encoded at the end of the buffer.
-        size_t realBufferSize = m_currentMessageSize - sizeof(uint32_t);
-        uint32_t messageID = *reinterpret_cast<uint32_t*>(m_readBuffer.data() + realBufferSize);
+            for (int i = 0; i < attachmentCount; ++i)
+                attachments.append(Attachment(fileDescriptors[i], attachmentSizes[i]));
 
-        processIncomingMessage(MessageID::fromInt(messageID), adoptPtr(new ArgumentDecoder(m_readBuffer.data(), realBufferSize)));
+            if (messageInfo.isMessageBodyOOL()) {
+                ASSERT(messageInfo.bodySize());
 
-        m_currentMessageSize = 0;
+                WebKit::SharedMemory::Handle handle;
+                handle.adoptFromAttachment(fileDescriptors[attachmentCount], attachmentSizes[attachmentCount]);
+                if (handle.isNull()) {
+                    ASSERT_NOT_REACHED();
+                    return;
+                }
+
+                oolMessageBody = WebKit::SharedMemory::create(handle, WebKit::SharedMemory::ReadOnly);
+                if (!oolMessageBody) {
+                    ASSERT_NOT_REACHED();
+                    return;
+                }
+            }
+
+            controlMessage = CMSG_NXTHDR(&message, controlMessage);
+        } else {
+            ASSERT_NOT_REACHED();
+            return;
+        }
     }
+
+    ASSERT(attachments.size() == messageInfo.isMessageBodyOOL() ? messageInfo.attachmentCount() - 1 : messageInfo.attachmentCount());
+
+    unsigned char* messageBody = messageData;
+
+    if (messageInfo.isMessageBodyOOL())
+        messageBody = reinterpret_cast<unsigned char*>(oolMessageBody->data());
+
+    ArgumentDecoder* argumentDecoder;
+    if (attachments.isEmpty())
+        argumentDecoder = new ArgumentDecoder(messageBody, messageInfo.bodySize());
+    else
+        argumentDecoder = new ArgumentDecoder(messageBody, messageInfo.bodySize(), attachments);
+
+    processIncomingMessage(messageInfo.messageID(), adoptPtr(argumentDecoder));
+
+    ASSERT(!controlMessage);
 }
 
 bool Connection::open()
 {
-    ASSERT(!m_socket);
-
-    if (m_isServer) {
-        m_socket = WebKit::ProcessLauncher::takePendingConnection();
-        m_isConnected = m_socket;
-        if (m_isConnected) {
-            m_connectionQueue.moveSocketToWorkThread(m_socket);
-            m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler));
+    ASSERT(!m_socketNotifier);
+    int flags = fcntl(m_socketDescriptor, F_GETFL, 0);
+    while (fcntl(m_socketDescriptor, F_SETFL, flags | O_NONBLOCK) == -1) {
+        if (errno != EINTR) {
+            ASSERT_NOT_REACHED();
+            return false;
         }
-    } else {
-        m_socket = new QLocalSocket();
-        m_socket->connectToServer(m_serverName);
-        m_connectionQueue.moveSocketToWorkThread(m_socket);
-        m_connectionQueue.connectSignal(m_socket, SIGNAL(readyRead()), WorkItem::create(this, &Connection::readyReadHandler));
-        m_connectionQueue.connectSignal(m_socket, SIGNAL(disconnected()), WorkItem::create(this, &Connection::connectionDidClose));
-        m_isConnected = m_socket->waitForConnected();
     }
-    return m_isConnected;
+
+    m_isConnected = true;
+    m_socketNotifier = m_connectionQueue.registerSocketEventHandler(m_socketDescriptor, QSocketNotifier::Read, WorkItem::create(this, &Connection::readyReadHandler));
+
+    // Schedule a call to readyReadHandler. Data may have arrived before installation of the signal
+    // handler.
+    m_connectionQueue.scheduleWork(WorkItem::create(this, &Connection::readyReadHandler));
+
+    return true;
 }
 
 bool Connection::platformCanSendOutgoingMessages() const
 {
-    return m_socket;
+    return m_socketNotifier;
 }
 
 bool Connection::sendOutgoingMessage(MessageID messageID, PassOwnPtr<ArgumentEncoder> arguments)
 {
-    ASSERT(m_socket);
-
-    // We put the message ID last.
-    arguments->encodeUInt32(messageID.toInt());
+    ASSERT(m_socketNotifier);
+    COMPILE_ASSERT(sizeof(MessageInfo) + attachmentMaxAmount * sizeof(size_t) <= messageMaxSize, AttachmentsFitToMessageInline);
 
-    size_t bufferSize = arguments->bufferSize();
+    Vector<Attachment> attachments = arguments->releaseAttachments();
+    AttachmentResourceGuard<Vector<Attachment>, Vector<Attachment>::iterator> attachementDisposer(attachments);
 
-    // Write message size first
-    // FIXME: Should  just do a single write.
-    qint64 bytesWrittenForSize = m_socket->write(reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize));
-    if (bytesWrittenForSize != sizeof(bufferSize)) {
-        connectionDidClose();
+    if (attachments.size() > (attachmentMaxAmount - 1)) {
+        ASSERT_NOT_REACHED();
         return false;
     }
 
-    qint64 bytesWrittenForBuffer = m_socket->write(reinterpret_cast<char*>(arguments->buffer()), arguments->bufferSize());
-    if (bytesWrittenForBuffer != arguments->bufferSize()) {
-        connectionDidClose();
-        return false;
+    MessageInfo messageInfo(messageID, arguments->bufferSize(), attachments.size());
+    size_t messageSizeWithBodyInline = sizeof(messageInfo) + (attachments.size() * sizeof(size_t)) + arguments->bufferSize();
+    if (messageSizeWithBodyInline > messageMaxSize && arguments->bufferSize()) {
+        RefPtr<WebKit::SharedMemory> oolMessageBody = WebKit::SharedMemory::create(arguments->bufferSize());
+        if (!oolMessageBody)
+            return false;
+
+        WebKit::SharedMemory::Handle handle;
+        if (!oolMessageBody->createHandle(handle, WebKit::SharedMemory::ReadOnly))
+            return false;
+
+        messageInfo.setMessageBodyOOL();
+
+        memcpy(oolMessageBody->data(), arguments->buffer(), arguments->bufferSize());
+
+        attachments.append(handle.releaseToAttachment());
     }
 
-    m_socket->flush();
+    struct msghdr message;
+    memset(&message, 0, sizeof(message));
+
+    struct iovec iov[3];
+    memset(&iov, 0, sizeof(iov));
+
+    message.msg_iov = iov;
+    int iovLength = 1;
+
+    iov[0].iov_base = reinterpret_cast<void*>(&messageInfo);
+    iov[0].iov_len = sizeof(messageInfo);
+
+    char attachmentFDBuffer[CMSG_SPACE(sizeof(int) * (attachments.size()))];
+    size_t attachmentSizes[attachments.size()];
+
+    if (!attachments.isEmpty()) {
+        message.msg_control = attachmentFDBuffer;
+        message.msg_controllen = sizeof(attachmentFDBuffer);
+
+        struct cmsghdr* cmsg = CMSG_FIRSTHDR(&message);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof(int) * attachments.size());
+
+        int* fdptr = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+        for (int i = 0; i < attachments.size(); ++i) {
+            attachmentSizes[i] = attachments[i].size();
+            fdptr[i] = attachments[i].fileDescriptor();
+        }
+
+        message.msg_controllen = cmsg->cmsg_len;
 
+        iov[iovLength].iov_base = attachmentSizes;
+        iov[iovLength].iov_len = sizeof(attachmentSizes);
+        ++iovLength;
+    }
+
+    if (!messageInfo.isMessageBodyOOL() && arguments->bufferSize()) {
+        iov[iovLength].iov_base = reinterpret_cast<void*>(arguments->buffer());
+        iov[iovLength].iov_len = arguments->bufferSize();
+        ++iovLength;
+    }
+
+    message.msg_iovlen = iovLength;
+
+    int bytesSent = 0;
+    while ((bytesSent = sendmsg(m_socketDescriptor, &message, 0)) == -1) {
+        if (errno != EINTR)
+            return false;
+    }
     return true;
 }
 
+void Connection::setShouldCloseConnectionOnProcessTermination(WebKit::PlatformProcessIdentifier process)
+{
+    m_connectionQueue.scheduleWorkOnTermination(process, WorkItem::create(this, &Connection::connectionDidClose));
+}
+
 } // namespace CoreIPC
index 9854132..fd1d60c 100644 (file)
 #include <wtf/RefCounted.h>
 
 #if PLATFORM(QT)
-#include <QtGlobal>
-QT_BEGIN_NAMESPACE
-class QSharedMemory;
-QT_END_NAMESPACE
+#include "Attachment.h"
 #include <wtf/text/WTFString.h>
 #endif
 
@@ -63,6 +60,10 @@ public:
         void encode(CoreIPC::ArgumentEncoder*) const;
         static bool decode(CoreIPC::ArgumentDecoder*, Handle&);
 
+#if PLATFORM(QT)
+        CoreIPC::Attachment releaseToAttachment() const;
+        void adoptFromAttachment(int fileDescriptor, size_t);
+#endif
     private:
         friend class SharedMemory;
 #if PLATFORM(MAC)
@@ -70,7 +71,7 @@ public:
 #elif PLATFORM(WIN)
         mutable HANDLE m_handle;
 #elif PLATFORM(QT)
-        mutable String m_key;
+        mutable int m_fileDescriptor;
 #endif
         size_t m_size;
     };
@@ -97,7 +98,7 @@ private:
 #if PLATFORM(WIN)
     HANDLE m_handle;
 #elif PLATFORM(QT)
-    QSharedMemory* m_impl;
+    int m_fileDescriptor;
 #endif
 };
 
index 78fa8b7..bcaae0e 100644 (file)
@@ -41,7 +41,8 @@
 #include <wtf/Vector.h>
 
 #if PLATFORM(QT)
-class QLocalSocket;
+#include <QSocketNotifier>
+#include "PlatformProcessIdentifier.h"
 class QObject;
 class QThread;
 #elif PLATFORM(GTK)
@@ -79,10 +80,8 @@ public:
     void registerHandle(HANDLE, PassOwnPtr<WorkItem>);
     void unregisterAndCloseHandle(HANDLE);
 #elif PLATFORM(QT)
-    void connectSignal(QObject*, const char* signal, PassOwnPtr<WorkItem>);
-    void disconnectSignal(QObject*, const char* signal);
-
-    void moveSocketToWorkThread(QLocalSocket*);
+    QSocketNotifier* registerSocketEventHandler(int, QSocketNotifier::Type, PassOwnPtr<WorkItem>);
+    void scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier, PassOwnPtr<WorkItem>);
 #elif PLATFORM(GTK)
     void registerEventSourceHandler(int, int, PassOwnPtr<WorkItem>);
     void unregisterEventSourceHandler(int);
diff --git a/Source/WebKit2/Platform/qt/MappedMemoryPool.cpp b/Source/WebKit2/Platform/qt/MappedMemoryPool.cpp
deleted file mode 100644 (file)
index d36d82b..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010 University of Szeged
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
- * All rights reserved.
- *
- * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
- * 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 "MappedMemoryPool.h"
-
-#include "CleanupHandler.h"
-#include "StdLibExtras.h"
-#include <QDir>
-#include <QIODevice>
-#include <QTemporaryFile>
-
-namespace WebKit {
-
-MappedMemoryPool* MappedMemoryPool::theInstance = 0;
-
-MappedMemoryPool* MappedMemoryPool::instance()
-{
-    if (!theInstance) {
-        theInstance = new MappedMemoryPool;
-
-        // Do not leave mapping files on the disk.
-        CleanupHandler::instance()->markForCleanup(theInstance);
-    }
-
-    return theInstance;
-}
-
-MappedMemoryPool::~MappedMemoryPool()
-{
-    CleanupHandler::instance()->unmark(theInstance);
-
-    for (unsigned n = 0; n < m_pool.size(); ++n) {
-        MappedMemory& current = m_pool.at(n);
-        if (!current.file)
-            continue;
-        current.file->remove();
-        delete current.file;
-    }
-    m_pool.clear();
-}
-
-MappedMemory* MappedMemoryPool::mapMemory(size_t size)
-{
-    for (unsigned n = 0; n < m_pool.size(); ++n) {
-        MappedMemory& current = m_pool.at(n);
-        if (current.dataSize >= size && current.isFree()) {
-            current.markUsed();
-            return &current;
-        }
-    }
-
-    MappedMemory newMap;
-    newMap.dataSize = size;
-    newMap.file = new QTemporaryFile(QDir::tempPath() + "/WebKit2UpdateChunk");
-    newMap.file->open(QIODevice::ReadWrite);
-    newMap.fileName = newMap.file->fileName();
-    newMap.file->resize(newMap.mapSize());
-    newMap.mappedBytes = newMap.file->map(0, newMap.mapSize());
-    newMap.file->close();
-    newMap.markUsed();
-    m_pool.append(newMap);
-    return &m_pool.last();
-}
-
-MappedMemory* MappedMemoryPool::mapFile(QString fileName, size_t size)
-{
-    for (unsigned n = 0; n < m_pool.size(); ++n) {
-        MappedMemory& current = m_pool.at(n);
-        if (current.fileName == fileName) {
-            ASSERT(!current.isFree());
-            return &current;
-        }
-    }
-
-    MappedMemory newMap;
-    newMap.file = new QFile(fileName);
-    newMap.fileName = fileName;
-    newMap.dataSize = size;
-    ASSERT(newMap.file->exists());
-    ASSERT(newMap.file->size() >= newMap.mapSize());
-    newMap.file->open(QIODevice::ReadWrite);
-    newMap.mappedBytes = newMap.file->map(0, newMap.mapSize());
-    ASSERT(newMap.mappedBytes);
-    ASSERT(!newMap.isFree());
-    newMap.file->close();
-    m_pool.append(newMap);
-    return &m_pool.last();
-}
-
-} // namespace WebKit
diff --git a/Source/WebKit2/Platform/qt/MappedMemoryPool.h b/Source/WebKit2/Platform/qt/MappedMemoryPool.h
deleted file mode 100644 (file)
index 8d6af8c..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
- * Copyright (C) 2010 University of Szeged
- *
- * 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.
- */
-
-#ifndef MappedMemoryPool_h
-#define MappedMemoryPool_h
-
-#include <QFile>
-#include <QObject>
-#include <wtf/StdLibExtras.h>
-#include <wtf/Vector.h>
-
-namespace WebKit {
-
-class MappedMemoryPool;
-
-struct MappedMemory {
-
-    QString mappedFileName() const
-    {
-        ASSERT(file);
-        ASSERT(mappedBytes);
-        return fileName;
-    }
-
-    void markFree()
-    {
-        ASSERT(mappedBytes);
-        dataPtr->isFree = true;
-    }
-
-    uchar* data() const
-    {
-        ASSERT(mappedBytes);
-        return dataPtr->bytes;
-    }
-
-private:
-    friend class MappedMemoryPool;
-
-    MappedMemory()
-        : file(0)
-        , mappedBytes(0)
-        , dataSize(0)
-    {
-    }
-
-    void markUsed() { dataPtr->isFree = false; }
-
-    size_t mapSize() const { return dataSize + sizeof(Data); }
-    bool isFree() const { return dataPtr->isFree; }
-
-    struct Data {
-        uint32_t isFree; // keep bytes aligned
-        uchar bytes[];
-    };
-
-    QFile* file;
-    QString fileName;
-    union {
-        uchar* mappedBytes;
-        Data* dataPtr;
-    };
-    size_t dataSize;
-};
-
-class MappedMemoryPool : QObject {
-    Q_OBJECT
-public:
-    static MappedMemoryPool* instance();
-
-    MappedMemory* mapMemory(size_t size);
-    MappedMemory* mapFile(QString fileName, size_t size);
-
-private:
-    MappedMemoryPool() { }
-    ~MappedMemoryPool();
-
-    static MappedMemoryPool* theInstance;
-
-    Vector<MappedMemory> m_pool;
-};
-
-} // namespace WebKit
-
-#endif // MappedMemoryPool_h
index f5fecfc..2e6141d 100644 (file)
 
 #include "ArgumentDecoder.h"
 #include "ArgumentEncoder.h"
-#include "CleanupHandler.h"
 #include "WebCoreArgumentCoders.h"
+#include <QDir>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
-#include <QCoreApplication>
-#include <QLatin1String>
-#include <QSharedMemory>
-#include <QString>
-#include <QUuid>
 #include <wtf/Assertions.h>
 #include <wtf/CurrentTime.h>
 
 namespace WebKit {
 
 SharedMemory::Handle::Handle()
-    : m_key()
+    : m_fileDescriptor(-1)
     , m_size(0)
 {
 }
 
 SharedMemory::Handle::~Handle()
 {
+    if (!isNull())
+        while (close(m_fileDescriptor) == -1 && errno == EINTR) { }
 }
 
 bool SharedMemory::Handle::isNull() const
 {
-    return m_key.isNull();
+    return m_fileDescriptor == -1;
 }
 
 void SharedMemory::Handle::encode(CoreIPC::ArgumentEncoder* encoder) const
 {
-    encoder->encodeUInt64(m_size);
-    encoder->encode(m_key);
-    m_key = String();
+    ASSERT(!isNull());
+
+    encoder->encode(releaseToAttachment());
 }
 
 bool SharedMemory::Handle::decode(CoreIPC::ArgumentDecoder* decoder, Handle& handle)
 {
     ASSERT_ARG(handle, !handle.m_size);
-    ASSERT_ARG(handle, handle.m_key.isNull());
+    ASSERT_ARG(handle, handle.isNull());
 
-    uint64_t size;
-    if (!decoder->decodeUInt64(size))
+    CoreIPC::Attachment attachment;
+    if (!decoder->decode(attachment))
         return false;
 
-    String key;
-    if (!decoder->decode(key))
-       return false;
+    handle.adoptFromAttachment(attachment.releaseFileDescriptor(), attachment.size());
+    return true;
+}
 
-    handle.m_size = size;
-    handle.m_key = key;
+CoreIPC::Attachment SharedMemory::Handle::releaseToAttachment() const
+{
+    ASSERT(!isNull());
 
-    return true;
+    int temp = m_fileDescriptor;
+    m_fileDescriptor = -1;
+    return CoreIPC::Attachment(temp, m_size);
 }
 
-static QString createUniqueKey()
+void SharedMemory::Handle::adoptFromAttachment(int fileDescriptor, size_t size)
 {
-    return QLatin1String("QWKSharedMemoryKey") + QUuid::createUuid().toString();
+    ASSERT(!m_size);
+    ASSERT(isNull());
+
+    m_fileDescriptor = fileDescriptor;
+    m_size = size;
 }
 
 PassRefPtr<SharedMemory> SharedMemory::create(size_t size)
 {
-    RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory));
-    QSharedMemory* impl = new QSharedMemory(createUniqueKey());
-    bool created = impl->create(size);
-    ASSERT_UNUSED(created, created);
+    QString tempName = QDir::temp().filePath("qwkshm.XXXXXX");
+    QByteArray tempNameCSTR = tempName.toLocal8Bit();
+    char* tempNameC = tempNameCSTR.data();
+
+    int fileDescriptor;
+    while ((fileDescriptor = mkostemp(tempNameC, O_CREAT | O_CLOEXEC | O_RDWR)) == -1) {
+        if (errno != EINTR)
+            return 0;
+    }
 
-    sharedMemory->m_impl = impl;
-    sharedMemory->m_size = size;
-    sharedMemory->m_data = impl->data();
+    while (ftruncate(fileDescriptor, size) == -1) {
+        if (errno != EINTR) {
+            while (close(fileDescriptor) == -1 && errno == EINTR) { }
+            unlink(tempNameC);
+            return 0;
+        }
+    }
+
+    void* data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
+    if (data == MAP_FAILED) {
+        while (close(fileDescriptor) == -1 && errno == EINTR) { }
+        unlink(tempNameC);
+        return 0;
+    }
 
-    // Do not leave the shared memory segment behind.
-    CleanupHandler::instance()->markForCleanup(impl);
+    unlink(tempNameC);
 
-    return sharedMemory.release();
+    RefPtr<SharedMemory> instance = adoptRef(new SharedMemory());
+    instance->m_data = data;
+    instance->m_fileDescriptor = fileDescriptor;
+    instance->m_size = size;
+    return instance.release();
 }
 
-static inline QSharedMemory::AccessMode accessMode(SharedMemory::Protection protection)
+static inline int accessModeMMap(SharedMemory::Protection protection)
 {
     switch (protection) {
     case SharedMemory::ReadOnly:
-        return QSharedMemory::ReadOnly;
+        return PROT_READ;
     case SharedMemory::ReadWrite:
-        return QSharedMemory::ReadWrite;
+        return PROT_READ | PROT_WRITE;
     }
 
     ASSERT_NOT_REACHED();
-    return QSharedMemory::ReadWrite;
+    return PROT_READ | PROT_WRITE;
 }
 
 PassRefPtr<SharedMemory> SharedMemory::create(const Handle& handle, Protection protection)
 {
-    if (handle.isNull())
-        return 0;
+    ASSERT(!handle.isNull());
 
-    QSharedMemory* impl = new QSharedMemory(QString(handle.m_key));
-    bool attached = impl->attach(accessMode(protection));
-    if (!attached) {
-        delete impl;
+    void* data = mmap(0, handle.m_size, accessModeMMap(protection), MAP_SHARED, handle.m_fileDescriptor, 0);
+    if (data == MAP_FAILED)
         return 0;
-    }
-
-    RefPtr<SharedMemory> sharedMemory(adoptRef(new SharedMemory));
-    sharedMemory->m_impl = impl;
-    ASSERT(handle.m_size == impl->size());
-    sharedMemory->m_size = handle.m_size;
-    sharedMemory->m_data = impl->data();
 
-    // Do not leave the shared memory segment behind.
-    CleanupHandler::instance()->markForCleanup(impl);
-
-    return sharedMemory.release();
+    RefPtr<SharedMemory> instance = adoptRef(new SharedMemory());
+    instance->m_data = data;
+    instance->m_fileDescriptor = handle.m_fileDescriptor;
+    instance->m_size = handle.m_size;
+    handle.m_fileDescriptor = -1;
+    return instance;
 }
 
 SharedMemory::~SharedMemory()
 {
-    if (CleanupHandler::instance()->hasStartedDeleting())
-        return;
+    munmap(m_data, m_size);
+    while (close(m_fileDescriptor) == -1 && errno == EINTR) { }
+}
 
-    CleanupHandler::instance()->unmark(m_impl);
-    delete m_impl;
+static inline int accessModeFile(SharedMemory::Protection protection)
+{
+    switch (protection) {
+    case SharedMemory::ReadOnly:
+        return O_RDONLY;
+    case SharedMemory::ReadWrite:
+        return O_RDWR;
+    }
+
+    ASSERT_NOT_REACHED();
+    return O_RDWR;
 }
 
 bool SharedMemory::createHandle(Handle& handle, Protection protection)
 {
-    ASSERT_ARG(handle, handle.m_key.isNull());
     ASSERT_ARG(handle, !handle.m_size);
+    ASSERT_ARG(handle, handle.isNull());
+
+    int duplicatedHandle;
+    while ((duplicatedHandle = dup(m_fileDescriptor)) == -1) {
+        if (errno != EINTR) {
+            ASSERT_NOT_REACHED();
+            return false;
+        }
+    }
 
-    QString key = m_impl->key();
-    if (key.isNull())
-        return false;
-    handle.m_key = String(key);
+    while ((fcntl(duplicatedHandle, F_SETFD,  O_CLOEXEC | accessModeFile(protection)) == -1)) {
+        if (errno != EINTR) {
+            ASSERT_NOT_REACHED();
+            while (close(duplicatedHandle) == -1 && errno == EINTR) { }
+            return false;
+        }
+    }
+    handle.m_fileDescriptor = duplicatedHandle;
     handle.m_size = m_size;
-
     return true;
 }
 
index 271984f..99ce96e 100644 (file)
@@ -29,6 +29,7 @@
 #include <QLocalSocket>
 #include <QObject>
 #include <QThread>
+#include <QProcess>
 #include <wtf/Threading.h>
 #include "NotImplemented.h"
 
@@ -75,32 +76,17 @@ public:
     WorkItem* m_workItem;
 };
 
-void WorkQueue::connectSignal(QObject* o, const char* signal, PassOwnPtr<WorkItem> workItem)
-{
-    WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, o, signal, workItem.leakPtr());
-    itemQt->moveToThread(m_workThread);
-    m_signalListeners.add(o, itemQt);
-}
-
-void WorkQueue::disconnectSignal(QObject* o, const char* name)
-{
-    HashMap<QObject*, WorkItemQt*>::iterator it = m_signalListeners.find(o);
-    for (; it != m_signalListeners.end(); ++it) {
-        if (strcmp(it->second->m_signal, name))
-            continue;
-        delete it->second;
-        m_signalListeners.remove(it);
-        return;
-    }
-}
-
-void WorkQueue::moveSocketToWorkThread(QLocalSocket* socket)
+QSocketNotifier* WorkQueue::registerSocketEventHandler(int socketDescriptor, QSocketNotifier::Type type, PassOwnPtr<WorkItem> workItem)
 {
     ASSERT(m_workThread);
-    ASSERT(socket);
 
-    socket->setParent(0);
-    socket->moveToThread(m_workThread);
+    QSocketNotifier* notifier = new QSocketNotifier(socketDescriptor, type, 0);
+    notifier->setEnabled(false);
+    notifier->moveToThread(m_workThread);
+    WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, notifier, SIGNAL(activated(int)), workItem.leakPtr());
+    itemQt->moveToThread(m_workThread);
+    notifier->setEnabled(true);
+    return notifier;
 }
 
 void WorkQueue::platformInitialize(const char*)
@@ -129,4 +115,10 @@ void WorkQueue::scheduleWorkAfterDelay(PassOwnPtr<WorkItem>, double)
     notImplemented();
 }
 
+void WorkQueue::scheduleWorkOnTermination(WebKit::PlatformProcessIdentifier process, PassOwnPtr<WorkItem> workItem)
+{
+    WorkQueue::WorkItemQt* itemQt = new WorkQueue::WorkItemQt(this, process, SIGNAL(finished(int, QProcess::ExitStatus)), workItem.leakPtr());
+    itemQt->moveToThread(m_workThread);
+}
+
 #include "WorkQueueQt.moc"
index 4d8e62d..2f9be45 100644 (file)
@@ -29,7 +29,6 @@
 
 #include "ArgumentDecoder.h"
 #include "ArgumentEncoder.h"
-#include "MappedMemoryPool.h"
 #include "WebCoreArgumentCoders.h"
 #include <QIODevice>
 #include <QImage>
@@ -43,28 +42,35 @@ using namespace std;
 namespace WebKit {
 
 UpdateChunk::UpdateChunk()
-    : m_mappedMemory(0)
 {
 }
 
 UpdateChunk::UpdateChunk(const IntRect& rect)
     : m_rect(rect)
-    , m_mappedMemory(MappedMemoryPool::instance()->mapMemory(size()))
+    , m_sharedMemory(SharedMemory::create(size()))
 {
 }
 
 UpdateChunk::~UpdateChunk()
 {
-    if (m_mappedMemory)
-        m_mappedMemory->markFree();
 }
 
 void UpdateChunk::encode(CoreIPC::ArgumentEncoder* encoder) const
 {
     encoder->encode(m_rect);
-    encoder->encode(String(m_mappedMemory->mappedFileName()));
+    if (!m_sharedMemory) {
+        encoder->encode(false);
+        return;
+    }
+
+    SharedMemory::Handle handle;
+    if (m_sharedMemory->createHandle(handle, SharedMemory::ReadOnly)) {
+        encoder->encode(true);
+        encoder->encode(handle);
+    } else
+        encoder->encode(false);
 
-    m_mappedMemory = 0;
+    m_sharedMemory = 0;
 }
 
 bool UpdateChunk::decode(CoreIPC::ArgumentDecoder* decoder, UpdateChunk& chunk)
@@ -74,16 +80,23 @@ bool UpdateChunk::decode(CoreIPC::ArgumentDecoder* decoder, UpdateChunk& chunk)
     IntRect rect;
     if (!decoder->decode(rect))
         return false;
+
     chunk.m_rect = rect;
 
-    if (chunk.isEmpty())
-        return true; // Successfully decoded empty chunk.
+    bool hasSharedMemory;
+    if (!decoder->decode(hasSharedMemory))
+        return false;
 
-    String fileName;
-    if (!decoder->decode(fileName))
+    if (!hasSharedMemory) {
+        chunk.m_sharedMemory = 0;
+        return true;
+    }
+
+    SharedMemory::Handle handle;
+    if (!decoder->decode(handle))
         return false;
 
-    chunk.m_mappedMemory = MappedMemoryPool::instance()->mapFile(fileName, chunk.size());
+    chunk.m_sharedMemory = SharedMemory::create(handle, SharedMemory::ReadOnly);
     return true;
 }
 
@@ -101,7 +114,10 @@ size_t UpdateChunk::size() const
 
 QImage UpdateChunk::createImage() const
 {
-    ASSERT(m_mappedMemory);
+    ASSERT(m_sharedMemory);
+    if (!m_sharedMemory)
+        return QImage();
+
     QImage::Format format;
     int bpp;
     if (QPixmap::defaultDepth() == 16) {
@@ -112,7 +128,7 @@ QImage UpdateChunk::createImage() const
         bpp = 4;
     }
 
-    return QImage(m_mappedMemory->data(), m_rect.width(), m_rect.height(), (m_rect.width() * bpp + 3) & ~0x3, format);
+    return QImage(reinterpret_cast<unsigned char*>(m_sharedMemory->data()), m_rect.width(), m_rect.height(), (m_rect.width() * bpp + 3) & ~0x3, format);
 }
 
 } // namespace WebKit
index f506ba7..664056a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <QImage>
 #include <WebCore/IntRect.h>
+#include "SharedMemory.h"
 
 namespace CoreIPC {
 class ArgumentEncoder;
@@ -37,8 +38,6 @@ class ArgumentDecoder;
 
 namespace WebKit {
 
-class MappedMemory;
-
 class UpdateChunk {
 public:
     UpdateChunk();
@@ -58,7 +57,7 @@ private:
 
     WebCore::IntRect m_rect;
 
-    mutable MappedMemory* m_mappedMemory;
+    mutable RefPtr<SharedMemory> m_sharedMemory;
 };
 
 } // namespace WebKit
index 31efd4d..79d1253 100644 (file)
@@ -72,11 +72,6 @@ public:
 
     static bool getProcessTypeFromString(const char*, ProcessType&);
 
-#if PLATFORM(QT)
-    friend class ProcessLauncherHelper;
-    static QLocalSocket* takePendingConnection();
-#endif
-
 private:
     ProcessLauncher(Client*, const LaunchOptions& launchOptions);
 
index 7dff894..baa5ee7 100644 (file)
 #include "ProcessLauncher.h"
 
 #include "Connection.h"
-#include "CleanupHandler.h"
 #include "NotImplemented.h"
 #include "RunLoop.h"
 #include "WebProcess.h"
-#include <runtime/InitializeThreading.h>
-#include <string>
-#include <wtf/HashSet.h>
-#include <wtf/PassRefPtr.h>
-#include <wtf/Threading.h>
-#include <wtf/text/WTFString.h>
-
 #include <QApplication>
 #include <QDebug>
 #include <QFile>
 #include <QMetaType>
 #include <QProcess>
 #include <QString>
-
 #include <QtCore/qglobal.h>
-
+#include <errno.h>
+#include <fcntl.h>
+#include <runtime/InitializeThreading.h>
+#include <string>
 #include <sys/resource.h>
+#include <sys/socket.h>
 #include <unistd.h>
+#include <wtf/HashSet.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/Threading.h>
+#include <wtf/text/WTFString.h>
+#if defined Q_OS_UNIX
+#include <sys/prctl.h>
+#include <signal.h>
+#endif
 
 using namespace WebCore;
 
 namespace WebKit {
 
-class ProcessLauncherHelper : public QObject {
-    Q_OBJECT
-public:
-    ~ProcessLauncherHelper();
-    void launch(WebKit::ProcessLauncher*);
-    QLocalSocket* takePendingConnection();
-    static ProcessLauncherHelper* instance();
-
-    const QString serverName() const { return m_server.serverName(); }
-
-private:
-    ProcessLauncherHelper();
-    QLocalServer m_server;
-    QList<WorkItem*> m_items;
-
-    Q_SLOT void newConnection();
-};
-
-Q_GLOBAL_STATIC(WTF::HashSet<QProcess*>, processes);
-
-static void cleanupAtExit()
-{
-    // Terminate our web process(es).
-    WTF::HashSet<QProcess*>::const_iterator end = processes()->end();
-    for (WTF::HashSet<QProcess*>::const_iterator it = processes()->begin(); it != end; ++it) {
-        QProcess* process = *it;
-        process->disconnect(process);
-        process->terminate();
-        if (!process->waitForFinished(200))
-            process->kill();
-    }
-
-    // Do not leave the socket file behind.
-    QLocalServer::removeServer(ProcessLauncherHelper::instance()->serverName());
-}
-
 class QtWebProcess : public QProcess
 {
     Q_OBJECT
@@ -98,32 +65,20 @@ public:
     QtWebProcess(QObject* parent = 0)
         : QProcess(parent)
     {
-        static bool isRegistered = false;
-        if (!isRegistered) {
-            qRegisterMetaType<QProcess::ProcessState>("QProcess::ProcessState");
-            isRegistered = true;
-        }
-
-        connect(this, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(processStateChanged(QProcess::ProcessState)));
     }
 
-private slots:
-    void processStateChanged(QProcess::ProcessState state);
+protected:
+    virtual void setupChildProcess();
 };
 
-void QtWebProcess::processStateChanged(QProcess::ProcessState state)
+void QtWebProcess::setupChildProcess()
 {
-    QProcess* process = qobject_cast<QProcess*>(sender());
-    if (!process)
-        return;
-
-    if (state == QProcess::Running)
-        processes()->add(process);
-    else if (state == QProcess::NotRunning)
-        processes()->remove(process);
+#if defined Q_OS_UNIX
+    prctl(PR_SET_PDEATHSIG, SIGKILL);
+#endif
 }
 
-void ProcessLauncherHelper::launch(WebKit::ProcessLauncher* launcher)
+void ProcessLauncher::launchProcess()
 {
     QString applicationPath = "%1 %2";
 
@@ -133,12 +88,38 @@ void ProcessLauncherHelper::launch(WebKit::ProcessLauncher* launcher)
         applicationPath = applicationPath.arg("QtWebProcess");
     }
 
-    QString program(applicationPath.arg(m_server.serverName()));
+    int sockets[2];
+    if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) == -1) {
+        qDebug() << "Creation of socket failed with errno:" << errno;
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    // Don't expose the ui socket to the web process
+    while (fcntl(sockets[1], F_SETFD, FD_CLOEXEC == -1)) {
+        if (errno != EINTR) {
+            ASSERT_NOT_REACHED();
+            while (close(sockets[0]) == -1 && errno == EINTR) { }
+            while (close(sockets[1]) == -1 && errno == EINTR) { }
+            return;
+        }
+    }
+
+    QString program(applicationPath.arg(sockets[0]));
 
     QProcess* webProcess = new QtWebProcess();
     webProcess->setProcessChannelMode(QProcess::ForwardedChannels);
     webProcess->start(program);
 
+    // Don't expose the web socket to possible future web processes
+    while (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1) {
+        if (errno != EINTR) {
+            ASSERT_NOT_REACHED();
+            delete webProcess;
+            return;
+        }
+    }
+
     if (!webProcess->waitForStarted()) {
         qDebug() << "Failed to start" << program;
         ASSERT_NOT_REACHED();
@@ -148,55 +129,7 @@ void ProcessLauncherHelper::launch(WebKit::ProcessLauncher* launcher)
 
     setpriority(PRIO_PROCESS, webProcess->pid(), 10);
 
-    m_items.append(WorkItem::create(launcher, &WebKit::ProcessLauncher::didFinishLaunchingProcess, webProcess, m_server.serverName()).leakPtr());
-}
-
-QLocalSocket* ProcessLauncherHelper::takePendingConnection()
-{
-    return m_server.nextPendingConnection();
-}
-
-ProcessLauncherHelper::~ProcessLauncherHelper()
-{
-    m_server.close();
-}
-
-ProcessLauncherHelper::ProcessLauncherHelper()
-{
-    srandom(time(0));
-    if (!m_server.listen("QtWebKit" + QString::number(random()))) {
-        qDebug() << "Failed to create server socket.";
-        ASSERT_NOT_REACHED();
-    }
-    connect(&m_server, SIGNAL(newConnection()), this, SLOT(newConnection()));
-}
-
-ProcessLauncherHelper* ProcessLauncherHelper::instance()
-{
-    static ProcessLauncherHelper* result = 0;
-    if (!result) {
-        result = new ProcessLauncherHelper();
-
-        // The purpose of the following line is to ensure that our static is initialized before the exit handler is installed.
-        processes()->clear();
-
-        atexit(cleanupAtExit);
-    }
-    return result;
-}
-
-void ProcessLauncherHelper::newConnection()
-{
-    ASSERT(!m_items.isEmpty());
-
-    m_items[0]->execute();
-    delete m_items[0];
-    m_items.pop_front();
-}
-
-void ProcessLauncher::launchProcess()
-{
-    ProcessLauncherHelper::instance()->launch(this);
+    RunLoop::main()->scheduleWork(WorkItem::create(this, &WebKit::ProcessLauncher::didFinishLaunchingProcess, webProcess, sockets[1]));
 }
 
 void ProcessLauncher::terminateProcess()
@@ -208,14 +141,9 @@ void ProcessLauncher::terminateProcess()
     m_processIdentifier->terminate();
 }
 
-QLocalSocket* ProcessLauncher::takePendingConnection()
-{
-    return ProcessLauncherHelper::instance()->takePendingConnection();
-}
-
 void ProcessLauncher::platformInvalidate()
 {
-    notImplemented();
+
 }
 
 } // namespace WebKit
index 471a424..344580c 100644 (file)
@@ -54,7 +54,7 @@ static void* webThreadBody(void* /* context */)
 
     // FIXME: We do not support threaded mode for now.
 
-    WebProcess::shared().initialize("foo", RunLoop::current());
+    WebProcess::shared().initialize(-1, RunLoop::current());
     RunLoop::run();
 
     return 0;
@@ -70,8 +70,7 @@ CoreIPC::Connection::Identifier ThreadLauncher::createWebThread()
         return 0;
     }
 
-    QString serverIdentifier = QString::number(connectionIdentifier);
-    return serverIdentifier;
+    return connectionIdentifier;
 }
 
 } // namespace WebKit
index c7e9382..6d115dc 100644 (file)
@@ -344,8 +344,10 @@ void WebProcessProxy::didFinishLaunching(CoreIPC::Connection::Identifier connect
     m_connection = CoreIPC::Connection::createServerConnection(connectionIdentifier, this, RunLoop::main());
 #if PLATFORM(MAC)
     m_connection->setShouldCloseConnectionOnMachExceptions();
+#elif PLATFORM(QT)
+    m_connection->setShouldCloseConnectionOnProcessTermination(processIdentifier());
 #endif
-    
+
     m_connection->open();
     
     for (size_t i = 0; i < m_pendingMessages.size(); ++i) {
index 5b2cd88..f6b846d 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "ApplicationCacheStorage.h"
 #include "WebProcessCreationParameters.h"
+#include <QProcess>
 
 namespace WebKit {
 
@@ -42,6 +43,7 @@ String WebContext::applicationCacheDirectory()
 
 void WebContext::platformInitializeWebProcess(WebProcessCreationParameters&)
 {
+    qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
 }
 
 } // namespace WebKit
index ed6bf1b..ea98904 100644 (file)
@@ -232,7 +232,6 @@ HEADERS += \
     Platform/SharedMemory.h \
     Platform/WorkItem.h \
     Platform/WorkQueue.h \
-    Platform/qt/MappedMemoryPool.h \
     Shared/API/c/WKBase.h \
     Shared/API/c/WKCertificateInfo.h \
     Shared/API/c/WKContextMenuItem.h \
@@ -293,7 +292,6 @@ HEADERS += \
     Shared/WebURLResponse.h \
     Shared/WebUserContentURLPattern.h \
     Shared/Plugins/Netscape/NetscapePluginModule.h \
-    Shared/qt/CleanupHandler.h \
     Shared/qt/PlatformCertificateInfo.h \
     Shared/qt/UpdateChunk.h \
     Shared/qt/WebEventFactoryQt.h \
@@ -459,12 +457,12 @@ SOURCES += \
     Platform/CoreIPC/BinarySemaphore.cpp \
     Platform/CoreIPC/Connection.cpp \
     Platform/CoreIPC/DataReference.cpp \
+    Platform/CoreIPC/qt/AttachmentQt.cpp \
     Platform/CoreIPC/qt/ConnectionQt.cpp \
     Platform/Logging.cpp \
     Platform/Module.cpp \
     Platform/RunLoop.cpp \
     Platform/WorkQueue.cpp \
-    Platform/qt/MappedMemoryPool.cpp \
     Platform/qt/ModuleQt.cpp \
     Platform/qt/RunLoopQt.cpp \
     Platform/qt/SharedMemoryQt.cpp \
@@ -517,7 +515,6 @@ SOURCES += \
     Shared/WebURLResponse.cpp \
     Shared/WebWheelEvent.cpp \
     Shared/qt/ShareableBitmapQt.cpp \
-    Shared/qt/CleanupHandler.cpp \
     Shared/qt/NativeWebKeyboardEventQt.cpp \
     Shared/qt/UpdateChunk.cpp \
     Shared/qt/WebCoreArgumentCodersQt.cpp \
index bd4e370..3e122ff 100644 (file)
@@ -160,7 +160,18 @@ QWEBKIT_EXPORT int WebProcessMainQt(int argc, char** argv)
     RunLoop::initializeMainRunLoop();
 
     // Create the connection.
-    QString identifier(app->arguments().size() > 1 ? app->arguments().at(1) : "");
+    if (app->arguments().size() <= 1) {
+        qDebug() << "Error: wrong number of arguments.";
+        return 1;
+    }
+
+    bool wasNumber = false;
+    int identifier = app->arguments().at(1).toInt(&wasNumber, 10);
+    if (!wasNumber) {
+        qDebug() << "Error: connection identifier wrong.";
+        return 1;
+    }
+
     WebKit::WebProcess::shared().initialize(identifier, RunLoop::main());
 
     RunLoop::run();