ipc/mscom/SpinEvent.cpp
author Ehsan Akhgari <ehsan@mozilla.com>
Fri, 03 Mar 2017 15:16:23 -0500
changeset 346288 69abc17ea32fd2b12a8bba5f7a34cb5de2b05133
parent 345436 0ae0446f58c340060db184d6760755a3b289d731
child 349849 8c31849e2a065875d203d553219c59387872d1df
permissions -rw-r--r--
Bug 1340710 - Part 5: Make nsIPrincipal.origin throw for about:blank codebase URI principals; r=bholley Two about:blank codebase URI principals are only equal if their object identities are the same, but not if their string serializations happen to be equal (as they always will be.) In order to ensure that we always get this right in places where we compare the origin properties of two principals to check for their equality, we should ensure that the origin getter would throw so that we never incorrectly conclude that two such principals are equal. We will soon start returning a null principal instead of a codebase principal under this situation.

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 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 "mozilla/mscom/SpinEvent.h"

#include "mozilla/ArrayUtils.h"
#include "mozilla/Assertions.h"
#include "nsServiceManagerUtils.h"
#include "nsString.h"
#include "nsSystemInfo.h"

// This gives us compiler intrinsics for the x86 PAUSE instruction
#if defined(_MSC_VER)
#include <intrin.h>
#pragma intrinsic(_mm_pause)
#define CPU_PAUSE() _mm_pause()
#elif defined(__GNUC__) || defined(__clang__)
#define CPU_PAUSE() __builtin_ia32_pause()
#endif

namespace mozilla {
namespace mscom {

SpinEvent::SpinEvent()
  : mDone(false)
{
  static const bool sIsMulticore = []() {
    nsCOMPtr<nsIPropertyBag2> infoService = do_GetService(NS_SYSTEMINFO_CONTRACTID);
    if (!infoService) {
      return false;
    }

    uint32_t cpuCount;
    nsresult rv = infoService->GetPropertyAsUint32(NS_LITERAL_STRING("cpucount"),
                                                   &cpuCount);
    return NS_SUCCEEDED(rv) && cpuCount > 1;
  }();

  if (!sIsMulticore) {
    mDoneEvent.own(::CreateEventW(nullptr, FALSE, FALSE, nullptr));
    MOZ_ASSERT(mDoneEvent);
  }
}

bool
SpinEvent::Wait(HANDLE aTargetThread)
{
  MOZ_ASSERT(aTargetThread);
  if (!aTargetThread) {
    return false;
  }

  if (mDoneEvent) {
    HANDLE handles[] = {mDoneEvent, aTargetThread};
    DWORD waitResult = ::WaitForMultipleObjects(mozilla::ArrayLength(handles),
                                                handles, FALSE, INFINITE);
    return waitResult == WAIT_OBJECT_0;
  }

  while (!mDone) {
    // The PAUSE instruction is a hint to the CPU that we're doing a spin
    // loop. It is a no-op on older processors that don't support it, so
    // it is safe to use here without any CPUID checks.
    CPU_PAUSE();
  }
  return true;
}

void
SpinEvent::Signal()
{
  if (mDoneEvent) {
    ::SetEvent(mDoneEvent);
  } else {
    mDone = true;
  }
}

} // namespace mscom
} // namespace mozilla