DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (5b81998bb7ab)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: sw=4 ts=4 et :
 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef ipc_glue_SyncChannel_h
#define ipc_glue_SyncChannel_h 1

#include "mozilla/ipc/AsyncChannel.h"

namespace mozilla {
namespace ipc {
//-----------------------------------------------------------------------------

class SyncChannel : public AsyncChannel
{
protected:
    typedef IPC::Message::msgid_t msgid_t;

public:
    static const int32_t kNoTimeout;

    class /*NS_INTERFACE_CLASS*/ SyncListener : 
        public AsyncChannel::AsyncListener
    {
    public:
        virtual ~SyncListener() { }

        virtual void OnChannelClose() = 0;
        virtual void OnChannelError() = 0;
        virtual Result OnMessageReceived(const Message& aMessage) = 0;
        virtual void OnProcessingError(Result aError) = 0;
        virtual int32_t GetProtocolTypeId() = 0;
        virtual bool OnReplyTimeout() = 0;
        virtual Result OnMessageReceived(const Message& aMessage,
                                         Message*& aReply) = 0;
        virtual void OnChannelConnected(int32_t peer_pid) {}
    };

    SyncChannel(SyncListener* aListener);
    virtual ~SyncChannel();

    virtual bool Send(Message* msg) MOZ_OVERRIDE {
        return AsyncChannel::Send(msg);
    }

    // Synchronously send |msg| (i.e., wait for |reply|)
    virtual bool Send(Message* msg, Message* reply);

    // Set channel timeout value. Since this is broken up into
    // two period, the minimum timeout value is 2ms.
    void SetReplyTimeoutMs(int32_t aTimeoutMs) {
        AssertWorkerThread();
        mTimeoutMs = (aTimeoutMs <= 0) ? kNoTimeout :
          // timeouts are broken up into two periods
          (int32_t)ceil((double)aTimeoutMs/2.0);
    }

    static bool IsPumpingMessages() {
        return sIsPumpingMessages;
    }
    static void SetIsPumpingMessages(bool aIsPumping) {
        sIsPumpingMessages = aIsPumping;
    }

#ifdef OS_WIN
public:
    struct NS_STACK_CLASS SyncStackFrame
    {
        SyncStackFrame(SyncChannel* channel, bool rpc);
        ~SyncStackFrame();

        bool mRPC;
        bool mSpinNestedEvents;
        bool mListenerNotified;
        SyncChannel* mChannel;

        /* the previous stack frame for this channel */
        SyncStackFrame* mPrev;

        /* the previous stack frame on any channel */
        SyncStackFrame* mStaticPrev;
    };
    friend struct SyncChannel::SyncStackFrame;

    static bool IsSpinLoopActive() {
        for (SyncStackFrame* frame = sStaticTopFrame;
             frame;
             frame = frame->mPrev) {
            if (frame->mSpinNestedEvents)
                return true;
        }
        return false;
    }

protected:
    /* the deepest sync stack frame for this channel */
    SyncStackFrame* mTopFrame;

    /* the deepest sync stack frame on any channel */
    static SyncStackFrame* sStaticTopFrame;
#endif // OS_WIN

protected:
    // Executed on the link thread
    // Override the AsyncChannel handler so we can dispatch sync messages
    virtual void OnMessageReceivedFromLink(const Message& msg) MOZ_OVERRIDE;
    virtual void OnChannelErrorFromLink() MOZ_OVERRIDE;

    // Executed on the worker thread
    bool ProcessingSyncMessage() const {
        return mProcessingSyncMessage;
    }

    void OnDispatchMessage(const Message& aMsg);

    //
    // Return true if the wait ended because a notification was
    // received.  That is, true => event received.
    //
    // Return false if the time elapsed from when we started the
    // process of waiting until afterwards exceeded the currently
    // allotted timeout.  That *DOES NOT* mean false => "no event" (==
    // timeout); there are many circumstances that could cause the
    // measured elapsed time to exceed the timeout EVEN WHEN we were
    // notified.
    //
    // So in sum: true is a meaningful return value; false isn't,
    // necessarily.
    //
    bool WaitForNotify();

    bool ShouldContinueFromTimeout();

    // Executed on the IO thread.
    void NotifyWorkerThread();

    // On both
    bool AwaitingSyncReply() const {
        mMonitor->AssertCurrentThreadOwns();
        return mPendingReply != 0;
    }

    int32_t NextSeqno() {
        AssertWorkerThread();
        return mChild ? --mNextSeqno : ++mNextSeqno;
    }

    msgid_t mPendingReply;
    bool mProcessingSyncMessage;
    Message mRecvd;
    // This is only accessed from the worker thread; seqno's are
    // completely opaque to the IO thread.
    int32_t mNextSeqno;

    static bool sIsPumpingMessages;

    // Timeout periods are broken up in two to prevent system suspension from
    // triggering an abort. This method (called by WaitForNotify with a 'did
    // timeout' flag) decides if we should wait again for half of mTimeoutMs
    // or give up.
    bool WaitResponse(bool aWaitTimedOut);
    bool mInTimeoutSecondHalf;
    int32_t mTimeoutMs;

#ifdef OS_WIN
    HANDLE mEvent;
#endif

private:
    bool EventOccurred();
};


} // namespace ipc
} // namespace mozilla
#endif  // ifndef ipc_glue_SyncChannel_h