netwerk/ipc/ChannelEventQueue.cpp
author Luke Chang <lchang@mozilla.com>
Mon, 09 Jan 2017 14:43:21 +0800
changeset 462921 0884750dadefe2fd9ba24f82fd7755bd6c0b9832
parent 453586 83c36290906985c3f6a4a211cb7ed45ab902f9c2
child 485700 99c4534aadbf840e506c88e472e05096a9ab0398
child 489668 cbb8fdf1daf98a15f7d57f6b08d273bdf96aa1a0
child 493880 47029ae9df65b220c89872dedda8007dcb087c95
child 499122 8a6e96f31060a97d892b82f69079fa83e53ba619
child 499901 c595aaf540b3df7a90a0873f22236a875de2b3e9
child 501107 de237ef25f65ca5fe4327afa09bcecc6237ad626
child 504548 fe56fdac3fa23c4be95c1784a51d0da6ddeba6cd
permissions -rw-r--r--
Bug 1299405 - [jsplugins][UI] Implement presentation mode. r=evelyn MozReview-Commit-ID: DYkul38pL3v

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set sw=2 ts=8 et tw=80 :
 */
/* 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 "nsISupports.h"
#include "mozilla/net/ChannelEventQueue.h"
#include "mozilla/Unused.h"
#include "nsThreadUtils.h"
#include "mozilla/Unused.h"

namespace mozilla {
namespace net {

ChannelEvent*
ChannelEventQueue::TakeEvent()
{
  MutexAutoLock lock(mMutex);
  MOZ_ASSERT(mFlushing);

  if (mSuspended || mEventQueue.IsEmpty()) {
    return nullptr;
  }

  UniquePtr<ChannelEvent> event(Move(mEventQueue[0]));
  mEventQueue.RemoveElementAt(0);

  return event.release();
}

void
ChannelEventQueue::FlushQueue()
{
  // Events flushed could include destruction of channel (and our own
  // destructor) unless we make sure its refcount doesn't drop to 0 while this
  // method is running.
  nsCOMPtr<nsISupports> kungFuDeathGrip(mOwner);
  mozilla::Unused << kungFuDeathGrip; // Not used in this function

  // Prevent flushed events from flushing the queue recursively
  {
    MutexAutoLock lock(mMutex);
    mFlushing = true;
  }

  while (true) {
    UniquePtr<ChannelEvent> event(TakeEvent());
    if (!event) {
      break;
    }

    event->Run();
  }

  MutexAutoLock lock(mMutex);
  mFlushing = false;
}

void
ChannelEventQueue::Resume()
{
  MutexAutoLock lock(mMutex);

  // Resuming w/o suspend: error in debug mode, ignore in build
  MOZ_ASSERT(mSuspendCount > 0);
  if (mSuspendCount <= 0) {
    return;
  }

  if (!--mSuspendCount) {
    RefPtr<Runnable> event =
      NewRunnableMethod(this, &ChannelEventQueue::CompleteResume);
    if (mTargetThread) {
      mTargetThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
    } else {
      MOZ_RELEASE_ASSERT(NS_IsMainThread());
      Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event.forget())));
    }
  }
}

nsresult
ChannelEventQueue::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
{
  MOZ_RELEASE_ASSERT(NS_IsMainThread());
  MOZ_RELEASE_ASSERT(!mTargetThread);
  MOZ_RELEASE_ASSERT(aTargetThread);

  mTargetThread = do_QueryInterface(aTargetThread);
  MOZ_RELEASE_ASSERT(mTargetThread);

  return NS_OK;
}

nsresult
ChannelEventQueue::ResetDeliveryTarget()
{
  MutexAutoLock lock(mMutex);

  MOZ_RELEASE_ASSERT(mEventQueue.IsEmpty());
  MOZ_RELEASE_ASSERT(mSuspendCount == 0);
  MOZ_RELEASE_ASSERT(!mSuspended);
  MOZ_RELEASE_ASSERT(!mForced);
  MOZ_RELEASE_ASSERT(!mFlushing);
  mTargetThread = nullptr;

  return NS_OK;
}

} // namespace net
} // namespace mozilla