Changeset 139514 in webkit


Ignore:
Timestamp:
Jan 11, 2013 4:01:56 PM (11 years ago)
Author:
ap@apple.com
Message:

[WK2] Make it possible to send sync messages from secondary threads
https://bugs.webkit.org/show_bug.cgi?id=106708

Reviewed by Anders Carlsson.

It is hugely beneficial to implement sync messages at Connection level, because
ad hoc code that blocks a thread and wakes it up when a reply arrives on main
thread can't be made equally performant. A CoreOPC MessageDecoder can be moved across
threads, which can't be done with a decoded argument passed by reference to client code.

Sync messages from secondary threads are tracked in much simpler data structure
than client thread ones, because we don't need to be concerned with incoming messages.

  • Platform/CoreIPC/Connection.cpp: (Connection::SecondaryThreadPendingSyncReply): (CoreIPC::Connection::SecondaryThreadPendingSyncReply::SecondaryThreadPendingSyncReply): (CoreIPC::Connection::createSyncMessageEncoder): (CoreIPC::Connection::sendSyncMessage): (CoreIPC::Connection::sendSyncMessageFromSecondaryThread): (CoreIPC::Connection::processIncomingSyncReply): (CoreIPC::Connection::connectionDidClose):
  • Platform/CoreIPC/Connection.h: Also corrected a misleading comment.
Location:
trunk/Source/WebKit2
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r139500 r139514  
     12013-01-11  Alexey Proskuryakov  <ap@apple.com>
     2
     3        [WK2] Make it possible to send sync messages from secondary threads
     4        https://bugs.webkit.org/show_bug.cgi?id=106708
     5
     6        Reviewed by Anders Carlsson.
     7
     8        It is hugely beneficial to implement sync messages at Connection level, because
     9        ad hoc code that blocks a thread and wakes it up when a reply arrives on main
     10        thread can't be made equally performant. A CoreOPC MessageDecoder can be moved across
     11        threads, which can't be done with a decoded argument passed by reference to client code.
     12
     13        Sync messages from secondary threads are tracked in much simpler data structure
     14        than client thread ones, because we don't need to be concerned with incoming messages.
     15
     16        * Platform/CoreIPC/Connection.cpp:
     17        (Connection::SecondaryThreadPendingSyncReply):
     18        (CoreIPC::Connection::SecondaryThreadPendingSyncReply::SecondaryThreadPendingSyncReply):
     19        (CoreIPC::Connection::createSyncMessageEncoder):
     20        (CoreIPC::Connection::sendSyncMessage):
     21        (CoreIPC::Connection::sendSyncMessageFromSecondaryThread):
     22        (CoreIPC::Connection::processIncomingSyncReply):
     23        (CoreIPC::Connection::connectionDidClose):
     24
     25        * Platform/CoreIPC/Connection.h: Also corrected a misleading comment.
     26
    1272013-01-11  Dan Bernstein  <mitz@apple.com>
    228
  • trunk/Source/WebKit2/Platform/CoreIPC/Connection.cpp

    r139464 r139514  
    9494};
    9595
     96class Connection::SecondaryThreadPendingSyncReply {
     97WTF_MAKE_NONCOPYABLE(SecondaryThreadPendingSyncReply);
     98public:
     99    SecondaryThreadPendingSyncReply() : replyDecoder(0) { }
     100
     101    // The reply decoder, will be null if there was an error processing the sync message on the other side.
     102    MessageDecoder* replyDecoder;
     103
     104    BinarySemaphore semaphore;
     105};
     106
     107
    96108PassRefPtr<Connection::SyncMessageState> Connection::SyncMessageState::getOrCreate(RunLoop* runLoop)
    97109{
     
    298310
    299311    // Encode the sync request ID.
    300     syncRequestID = ++m_syncRequestID;
     312    COMPILE_ASSERT(sizeof(m_syncRequestID) == sizeof(int64_t), CanUseAtomicIncrement);
     313    syncRequestID = atomicIncrement(reinterpret_cast<int64_t volatile*>(&m_syncRequestID));
    301314    encoder->encode(syncRequestID);
    302315
     
    387400PassOwnPtr<MessageDecoder> Connection::sendSyncMessage(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<MessageEncoder> encoder, double timeout, unsigned syncSendFlags)
    388401{
    389     // We only allow sending sync messages from the client run loop.
    390     ASSERT(RunLoop::current() == m_clientRunLoop);
     402    if (RunLoop::current() != m_clientRunLoop) {
     403        // No flags are supported for synchronous messages sent from secondary threads.
     404        ASSERT(!syncSendFlags);
     405        return sendSyncMessageFromSecondaryThread(messageID, syncRequestID, encoder, timeout);
     406    }
    391407
    392408    if (!isValid()) {
     
    421437    }
    422438
    423     if (!reply)
     439    // FIXME: Should we call didFailToSendSyncMessage()? It may be unexpected to get in on a background thread.
     440
     441    return reply.release();
     442}
     443
     444PassOwnPtr<MessageDecoder> Connection::sendSyncMessageFromSecondaryThread(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<MessageEncoder> encoder, double timeout)
     445{
     446    ASSERT(RunLoop::current() != m_clientRunLoop);
     447
     448    if (!isValid()) {
    424449        didFailToSendSyncMessage();
    425 
    426     return reply.release();
     450        return nullptr;
     451    }
     452
     453    SecondaryThreadPendingSyncReply pendingReply;
     454
     455    // Push the pending sync reply information on our stack.
     456    {
     457        MutexLocker locker(m_syncReplyStateMutex);
     458        if (!m_shouldWaitForSyncReplies) {
     459            didFailToSendSyncMessage();
     460            return nullptr;
     461        }
     462
     463        ASSERT(!m_secondaryThreadPendingSyncReplyMap.contains(syncRequestID));
     464        m_secondaryThreadPendingSyncReplyMap.add(syncRequestID, &pendingReply);
     465    }
     466
     467    sendMessage(messageID.messageIDWithAddedFlags(MessageID::SyncMessage), encoder, 0);
     468
     469    // Use a really long timeout.
     470    if (timeout == NoTimeout)
     471        timeout = 1e10;
     472
     473    pendingReply.semaphore.wait(timeout);
     474
     475    // Finally, pop the pending sync reply information.
     476    {
     477        MutexLocker locker(m_syncReplyStateMutex);
     478        ASSERT(m_secondaryThreadPendingSyncReplyMap.contains(syncRequestID));
     479        m_secondaryThreadPendingSyncReplyMap.remove(syncRequestID);
     480    }
     481
     482    if (!pendingReply.replyDecoder)
     483        didFailToSendSyncMessage();
     484
     485    return adoptPtr(pendingReply.replyDecoder);
    427486}
    428487
     
    503562    }
    504563
    505     // If we get here, it means we got a reply for a message that wasn't in the sync request stack.
     564    // If it's not a reply to any primary thread message, check if it is a reply to a secondary thread one.
     565    SecondaryThreadPendingSyncReplyMap::iterator secondaryThreadReplyMapItem = m_secondaryThreadPendingSyncReplyMap.find(decoder->destinationID());
     566    if (secondaryThreadReplyMapItem != m_secondaryThreadPendingSyncReplyMap.end()) {
     567        SecondaryThreadPendingSyncReply* reply = secondaryThreadReplyMapItem->value;
     568        ASSERT(!reply->replyDecoder);
     569        reply->replyDecoder = decoder.leakPtr();
     570        reply->semaphore.signal();
     571    }
     572
     573    // If we get here, it means we got a reply for a message that wasn't in the sync request stack or map.
    506574    // This can happen if the send timed out, so it's fine to ignore.
    507575}
     
    571639        if (!m_pendingSyncReplies.isEmpty())
    572640            m_syncMessageState->wakeUpClientRunLoop();
     641
     642        for (SecondaryThreadPendingSyncReplyMap::iterator iter = m_secondaryThreadPendingSyncReplyMap.begin(); iter != m_secondaryThreadPendingSyncReplyMap.end(); ++iter)
     643            iter->value->semaphore.signal();
    573644    }
    574645
  • trunk/Source/WebKit2/Platform/CoreIPC/Connection.h

    r139023 r139514  
    183183    bool sendMessage(MessageID, PassOwnPtr<MessageEncoder>, unsigned messageSendFlags = 0);
    184184    PassOwnPtr<MessageDecoder> sendSyncMessage(MessageID, uint64_t syncRequestID, PassOwnPtr<MessageEncoder>, double timeout, unsigned syncSendFlags = 0);
     185    PassOwnPtr<MessageDecoder> sendSyncMessageFromSecondaryThread(MessageID, uint64_t syncRequestID, PassOwnPtr<MessageEncoder>, double timeout);
    185186    bool sendSyncReply(PassOwnPtr<MessageEncoder>);
    186187
     
    306307        MessageDecoder* replyDecoder;
    307308
    308         // Will be set to true once a reply has been received or an error occurred.
     309        // Will be set to true once a reply has been received.
    309310        bool didReceiveReply;
    310311   
     
    331332        }
    332333    };
    333    
     334
    334335    class SyncMessageState;
    335336    friend class SyncMessageState;
     
    339340    bool m_shouldWaitForSyncReplies;
    340341    Vector<PendingSyncReply> m_pendingSyncReplies;
     342
     343    class SecondaryThreadPendingSyncReply;
     344    typedef HashMap<uint64_t, SecondaryThreadPendingSyncReply*> SecondaryThreadPendingSyncReplyMap;
     345    SecondaryThreadPendingSyncReplyMap m_secondaryThreadPendingSyncReplyMap;
    341346
    342347#if OS(DARWIN)
Note: See TracChangeset for help on using the changeset viewer.