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.

Header

Mercurial (d38398e5144e)

VCS Links

nsTransportEventSinkProxy

nsTransportStatusEvent

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
/* 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/. */

#include "mozilla/Mutex.h"
#include "nsTransportUtils.h"
#include "nsITransport.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"

using namespace mozilla;

//-----------------------------------------------------------------------------

class nsTransportStatusEvent;

class nsTransportEventSinkProxy : public nsITransportEventSink
{
public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSITRANSPORTEVENTSINK

    nsTransportEventSinkProxy(nsITransportEventSink *sink,
                              nsIEventTarget *target)
        : mSink(sink)
        , mTarget(target)
        , mLock("nsTransportEventSinkProxy.mLock")
        , mLastEvent(nullptr)
    {
        NS_ADDREF(mSink);
    }

private:
    virtual ~nsTransportEventSinkProxy()
    {
        // our reference to mSink could be the last, so be sure to release
        // it on the target thread.  otherwise, we could get into trouble.
        NS_ProxyRelease(mTarget, dont_AddRef(mSink));
    }

public:
    nsITransportEventSink           *mSink;
    nsCOMPtr<nsIEventTarget>         mTarget;
    Mutex                            mLock;
    nsTransportStatusEvent          *mLastEvent;
};

class nsTransportStatusEvent : public Runnable
{
public:
    nsTransportStatusEvent(nsTransportEventSinkProxy *proxy,
                           nsITransport *transport,
                           nsresult status,
                           int64_t progress,
                           int64_t progressMax)
        : Runnable("nsTransportStatusEvent")
        , mProxy(proxy)
        , mTransport(transport)
        , mStatus(status)
        , mProgress(progress)
        , mProgressMax(progressMax)
    {}

    ~nsTransportStatusEvent() {}

    NS_IMETHOD Run() override
    {
        // since this event is being handled, we need to clear the proxy's ref.
        // if not coalescing all, then last event may not equal self!
        {
            MutexAutoLock lock(mProxy->mLock);
            if (mProxy->mLastEvent == this)
                mProxy->mLastEvent = nullptr;
        }

        mProxy->mSink->OnTransportStatus(mTransport, mStatus, mProgress,
                                         mProgressMax);
        return NS_OK;
    }

    RefPtr<nsTransportEventSinkProxy> mProxy;

    // parameters to OnTransportStatus
    nsCOMPtr<nsITransport> mTransport;
    nsresult               mStatus;
    int64_t                mProgress;
    int64_t                mProgressMax;
};

NS_IMPL_ISUPPORTS(nsTransportEventSinkProxy, nsITransportEventSink)

NS_IMETHODIMP
nsTransportEventSinkProxy::OnTransportStatus(nsITransport *transport,
                                             nsresult status,
                                             int64_t progress,
                                             int64_t progressMax)
{
    nsresult rv = NS_OK;
    RefPtr<nsTransportStatusEvent> event;
    {
        MutexAutoLock lock(mLock);

        // try to coalesce events! ;-)
        if (mLastEvent && (mLastEvent->mStatus == status)) {
            mLastEvent->mStatus = status;
            mLastEvent->mProgress = progress;
            mLastEvent->mProgressMax = progressMax;
        }
        else {
            event = new nsTransportStatusEvent(this, transport, status,
                                               progress, progressMax);
            if (!event)
                rv = NS_ERROR_OUT_OF_MEMORY;
            mLastEvent = event;  // weak ref
        }
    }
    if (event) {
        rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL);
        if (NS_FAILED(rv)) {
            NS_WARNING("unable to post transport status event");

            MutexAutoLock lock(mLock); // cleanup.. don't reference anymore!
            mLastEvent = nullptr;
        }
    }
    return rv;
}

//-----------------------------------------------------------------------------

nsresult
net_NewTransportEventSinkProxy(nsITransportEventSink **result,
                               nsITransportEventSink *sink,
                               nsIEventTarget *target)
{
    *result = new nsTransportEventSinkProxy(sink, target);
    if (!*result)
        return NS_ERROR_OUT_OF_MEMORY;
    NS_ADDREF(*result);
    return NS_OK;
}