mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 703444. Port SPS profiler to Windows. r=jmuizelaar
Some changes and fixes by Felipe Gomes. r=benwa,ehsan
This commit is contained in:
parent
1c476ec47b
commit
3c6aabb3df
@ -51,6 +51,7 @@ include $(DEPTH)/config/autoconf.mk
|
||||
EXPORTS = \
|
||||
sampler.h \
|
||||
sps_sampler.h \
|
||||
thread_helper.h \
|
||||
$(NULL)
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
@ -96,6 +97,17 @@ CPPSRCS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),WINNT)
|
||||
|
||||
DEFINES += -DMOZ_ENABLE_PROFILER_SPS
|
||||
|
||||
CPPSRCS += \
|
||||
platform-win32.cc \
|
||||
TableTicker.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
|
@ -67,11 +67,14 @@ NS_IMETHODIMP
|
||||
nsProfiler::GetProfile(char **aProfile)
|
||||
{
|
||||
char *profile = SAMPLER_GET_PROFILE();
|
||||
PRUint32 len = strlen(profile);
|
||||
char *profileStr = static_cast<char *>
|
||||
(nsMemory::Clone(profile, len * sizeof(char)));
|
||||
*aProfile = profileStr;
|
||||
free(profile);
|
||||
if (profile) {
|
||||
PRUint32 len = strlen(profile);
|
||||
char *profileStr = static_cast<char *>
|
||||
(nsMemory::Clone(profile, (len + 1) * sizeof(char)));
|
||||
profileStr[len] = '\0';
|
||||
*aProfile = profileStr;
|
||||
free(profile);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@
|
||||
#endif
|
||||
|
||||
// Redefine the macros for platforms where SPS is supported.
|
||||
#if defined(ANDROID) || defined(XP_MACOSX)
|
||||
#if defined(ANDROID) || defined(XP_MACOSX) || defined(XP_WIN)
|
||||
|
||||
#include "sps_sampler.h"
|
||||
|
||||
|
@ -36,12 +36,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <sys/stat.h> // open
|
||||
#include <fcntl.h> // open
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
#include <semaphore.h>
|
||||
#include "sps_sampler.h"
|
||||
#include "platform.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
@ -50,8 +46,33 @@
|
||||
|
||||
using std::string;
|
||||
|
||||
pthread_key_t pkey_stack;
|
||||
pthread_key_t pkey_ticker;
|
||||
#ifdef XP_WIN
|
||||
#include <windows.h>
|
||||
#define getpid GetCurrentProcessId
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef MAXPATHLEN
|
||||
#ifdef PATH_MAX
|
||||
#define MAXPATHLEN PATH_MAX
|
||||
#elif defined(MAX_PATH)
|
||||
#define MAXPATHLEN MAX_PATH
|
||||
#elif defined(_MAX_PATH)
|
||||
#define MAXPATHLEN _MAX_PATH
|
||||
#elif defined(CCHMAXPATH)
|
||||
#define MAXPATHLEN CCHMAXPATH
|
||||
#else
|
||||
#define MAXPATHLEN 1024
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
mozilla::tls::key pkey_stack;
|
||||
mozilla::tls::key pkey_ticker;
|
||||
// We need to track whether we've been initialized otherwise
|
||||
// we end up using pkey_stack without initializing it.
|
||||
// Because pkey_stack is totally opaque to us we can't reuse
|
||||
@ -235,15 +256,27 @@ public:
|
||||
SaveProfileTask() {}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
TableTicker *t = (TableTicker*)pthread_getspecific(pkey_ticker);
|
||||
TableTicker *t = mozilla::tls::get<TableTicker>(pkey_ticker);
|
||||
|
||||
char buff[PATH_MAX];
|
||||
char buff[MAXPATHLEN];
|
||||
#ifdef ANDROID
|
||||
#define FOLDER "/sdcard/"
|
||||
#elif defined(XP_WIN)
|
||||
#define FOLDER "%TEMP%\\"
|
||||
#else
|
||||
#define FOLDER "/tmp/"
|
||||
#endif
|
||||
snprintf(buff, PATH_MAX, FOLDER "profile_%i_%i.txt", XRE_GetProcessType(), getpid());
|
||||
|
||||
snprintf(buff, MAXPATHLEN, "%sprofile_%i_%i.txt", FOLDER, XRE_GetProcessType(), getpid());
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Expand %TEMP% on Windows
|
||||
{
|
||||
char tmp[MAXPATHLEN];
|
||||
ExpandEnvironmentStringsA(buff, tmp, mozilla::ArrayLength(tmp));
|
||||
strcpy(buff, tmp);
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE* stream = ::fopen(buff, "w");
|
||||
if (stream) {
|
||||
@ -374,19 +407,15 @@ void ProfileEntry::WriteTag(Profile *profile, FILE *stream)
|
||||
void mozilla_sampler_init()
|
||||
{
|
||||
// TODO linux port: Use TLS with ifdefs
|
||||
// TODO window port: See bug 683229 comment 15
|
||||
// profiler uses getspecific because TLS is not supported on android.
|
||||
// getspecific was picked over nspr because it had less overhead required
|
||||
// to make the checkpoint function fast.
|
||||
if (pthread_key_create(&pkey_stack, NULL) ||
|
||||
pthread_key_create(&pkey_ticker, NULL)) {
|
||||
if (!mozilla::tls::create(&pkey_stack) ||
|
||||
!mozilla::tls::create(&pkey_ticker)) {
|
||||
LOG("Failed to init.");
|
||||
return;
|
||||
}
|
||||
stack_key_initialized = true;
|
||||
|
||||
Stack *stack = new Stack();
|
||||
pthread_setspecific(pkey_stack, stack);
|
||||
mozilla::tls::set(pkey_stack, stack);
|
||||
|
||||
// We can't open pref so we use an environment variable
|
||||
// to know if we should trigger the profiler on startup
|
||||
@ -408,7 +437,7 @@ void mozilla_sampler_deinit()
|
||||
}
|
||||
|
||||
void mozilla_sampler_save() {
|
||||
TableTicker *t = (TableTicker*)pthread_getspecific(pkey_ticker);
|
||||
TableTicker *t = mozilla::tls::get<TableTicker>(pkey_ticker);
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
@ -420,7 +449,7 @@ void mozilla_sampler_save() {
|
||||
}
|
||||
|
||||
char* mozilla_sampler_get_profile() {
|
||||
TableTicker *t = (TableTicker*)pthread_getspecific(pkey_ticker);
|
||||
TableTicker *t = mozilla::tls::get<TableTicker>(pkey_ticker);
|
||||
if (!t) {
|
||||
return NULL;
|
||||
}
|
||||
@ -436,7 +465,7 @@ char* mozilla_sampler_get_profile() {
|
||||
// Values are only honored on the first start
|
||||
void mozilla_sampler_start(int aProfileEntries, int aInterval)
|
||||
{
|
||||
Stack *stack = (Stack*)pthread_getspecific(pkey_stack);
|
||||
Stack *stack = mozilla::tls::get<Stack>(pkey_stack);
|
||||
if (!stack) {
|
||||
ASSERT(false);
|
||||
return;
|
||||
@ -445,24 +474,24 @@ void mozilla_sampler_start(int aProfileEntries, int aInterval)
|
||||
mozilla_sampler_stop();
|
||||
|
||||
TableTicker *t = new TableTicker(aInterval, aProfileEntries, stack);
|
||||
pthread_setspecific(pkey_ticker, t);
|
||||
mozilla::tls::set(pkey_ticker, t);
|
||||
t->Start();
|
||||
}
|
||||
|
||||
void mozilla_sampler_stop()
|
||||
{
|
||||
TableTicker *t = (TableTicker*)pthread_getspecific(pkey_ticker);
|
||||
TableTicker *t = mozilla::tls::get<TableTicker>(pkey_ticker);
|
||||
if (!t) {
|
||||
return;
|
||||
}
|
||||
|
||||
t->Stop();
|
||||
pthread_setspecific(pkey_ticker, NULL);
|
||||
mozilla::tls::set(pkey_ticker, (Stack*)NULL);
|
||||
}
|
||||
|
||||
bool mozilla_sampler_is_active()
|
||||
{
|
||||
TableTicker *t = (TableTicker*)pthread_getspecific(pkey_ticker);
|
||||
TableTicker *t = mozilla::tls::get<TableTicker>(pkey_ticker);
|
||||
if (!t) {
|
||||
return false;
|
||||
}
|
||||
|
@ -246,7 +246,6 @@ static void* SenderEntry(void* arg) {
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: interval_(interval),
|
||||
profiling_(profiling),
|
||||
synchronous_(profiling),
|
||||
active_(false) {
|
||||
data_ = new PlatformData(this);
|
||||
}
|
||||
|
@ -280,7 +280,6 @@ Sampler::Sampler(int interval, bool profiling)
|
||||
: // isolate_(isolate),
|
||||
interval_(interval),
|
||||
profiling_(profiling),
|
||||
synchronous_(profiling),
|
||||
active_(false) /*,
|
||||
samples_taken_(0)*/ {
|
||||
data_ = new PlatformData;
|
||||
|
194
tools/profiler/sps/platform-win32.cc
Normal file
194
tools/profiler/sps/platform-win32.cc
Normal file
@ -0,0 +1,194 @@
|
||||
// Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <windows.h>
|
||||
#include "v8-support.h"
|
||||
#include "platform.h"
|
||||
#include <process.h>
|
||||
|
||||
|
||||
class Sampler::PlatformData : public Malloced {
|
||||
public:
|
||||
// Get a handle to the calling thread. This is the thread that we are
|
||||
// going to profile. We need to make a copy of the handle because we are
|
||||
// going to use it in the sampler thread. Using GetThreadHandle() will
|
||||
// not work in this case. We're using OpenThread because DuplicateHandle
|
||||
// for some reason doesn't work in Chrome's sandbox.
|
||||
PlatformData() : profiled_thread_(OpenThread(THREAD_GET_CONTEXT |
|
||||
THREAD_SUSPEND_RESUME |
|
||||
THREAD_QUERY_INFORMATION,
|
||||
false,
|
||||
GetCurrentThreadId())) {}
|
||||
|
||||
~PlatformData() {
|
||||
if (profiled_thread_ != NULL) {
|
||||
CloseHandle(profiled_thread_);
|
||||
profiled_thread_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
HANDLE profiled_thread() { return profiled_thread_; }
|
||||
|
||||
private:
|
||||
HANDLE profiled_thread_;
|
||||
};
|
||||
|
||||
|
||||
class SamplerThread : public Thread {
|
||||
public:
|
||||
SamplerThread(int interval, Sampler* sampler)
|
||||
: Thread("SamplerThread"),
|
||||
interval_(interval),
|
||||
sampler_(sampler) {}
|
||||
|
||||
static void StartSampler(Sampler* sampler) {
|
||||
if (instance_ == NULL) {
|
||||
instance_ = new SamplerThread(sampler->interval(), sampler);
|
||||
instance_->Start();
|
||||
} else {
|
||||
ASSERT(instance_->interval_ == sampler->interval());
|
||||
}
|
||||
}
|
||||
|
||||
static void StopSampler() {
|
||||
instance_->Join();
|
||||
delete instance_;
|
||||
instance_ = NULL;
|
||||
}
|
||||
|
||||
// Implement Thread::Run().
|
||||
virtual void Run() {
|
||||
while (sampler_->IsActive()) {
|
||||
SampleContext(sampler_);
|
||||
OS::Sleep(interval_);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
HANDLE profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
if (profiled_thread == NULL)
|
||||
return;
|
||||
|
||||
// Context used for sampling the register state of the profiled thread.
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
|
||||
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
|
||||
if (SuspendThread(profiled_thread) == kSuspendFailed)
|
||||
return;
|
||||
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
if (GetThreadContext(profiled_thread, &context) != 0) {
|
||||
#if V8_HOST_ARCH_X64
|
||||
sample->pc = reinterpret_cast<Address>(context.Rip);
|
||||
sample->sp = reinterpret_cast<Address>(context.Rsp);
|
||||
sample->fp = reinterpret_cast<Address>(context.Rbp);
|
||||
#else
|
||||
sample->pc = reinterpret_cast<Address>(context.Eip);
|
||||
sample->sp = reinterpret_cast<Address>(context.Esp);
|
||||
sample->fp = reinterpret_cast<Address>(context.Ebp);
|
||||
#endif
|
||||
sampler->SampleStack(sample);
|
||||
sampler->Tick(sample);
|
||||
}
|
||||
ResumeThread(profiled_thread);
|
||||
}
|
||||
|
||||
Sampler* sampler_;
|
||||
const int interval_;
|
||||
|
||||
// Protects the process wide state below.
|
||||
static SamplerThread* instance_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SamplerThread);
|
||||
};
|
||||
|
||||
SamplerThread* SamplerThread::instance_ = NULL;
|
||||
|
||||
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: interval_(interval),
|
||||
profiling_(profiling),
|
||||
active_(false),
|
||||
data_(new PlatformData) {
|
||||
}
|
||||
|
||||
Sampler::~Sampler() {
|
||||
ASSERT(!IsActive());
|
||||
delete data_;
|
||||
}
|
||||
|
||||
void Sampler::Start() {
|
||||
ASSERT(!IsActive());
|
||||
SetActive(true);
|
||||
SamplerThread::StartSampler(this);
|
||||
}
|
||||
|
||||
void Sampler::Stop() {
|
||||
ASSERT(IsActive());
|
||||
SetActive(false);
|
||||
SamplerThread::StopSampler();
|
||||
}
|
||||
|
||||
|
||||
static const HANDLE kNoThread = INVALID_HANDLE_VALUE;
|
||||
|
||||
static unsigned int __stdcall ThreadEntry(void* arg) {
|
||||
Thread* thread = reinterpret_cast<Thread*>(arg);
|
||||
thread->Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
class Thread::PlatformData : public Malloced {
|
||||
public:
|
||||
explicit PlatformData(HANDLE thread) : thread_(thread) {}
|
||||
HANDLE thread_;
|
||||
unsigned thread_id_;
|
||||
};
|
||||
|
||||
// Initialize a Win32 thread object. The thread has an invalid thread
|
||||
// handle until it is started.
|
||||
Thread::Thread(const char* name)
|
||||
: stack_size_(0) {
|
||||
data_ = new PlatformData(kNoThread);
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
void Thread::set_name(const char* name) {
|
||||
strncpy(name_, name, sizeof(name_));
|
||||
name_[sizeof(name_) - 1] = '\0';
|
||||
}
|
||||
|
||||
// Close our own handle for the thread.
|
||||
Thread::~Thread() {
|
||||
if (data_->thread_ != kNoThread) CloseHandle(data_->thread_);
|
||||
delete data_;
|
||||
}
|
||||
|
||||
// Create a new thread. It is important to use _beginthreadex() instead of
|
||||
// the Win32 function CreateThread(), because the CreateThread() does not
|
||||
// initialize thread specific structures in the C runtime library.
|
||||
void Thread::Start() {
|
||||
data_->thread_ = reinterpret_cast<HANDLE>(
|
||||
_beginthreadex(NULL,
|
||||
static_cast<unsigned>(stack_size_),
|
||||
ThreadEntry,
|
||||
this,
|
||||
0,
|
||||
&data_->thread_id_));
|
||||
}
|
||||
|
||||
// Wait for thread to terminate.
|
||||
void Thread::Join() {
|
||||
if (data_->thread_id_ != GetCurrentThreadId()) {
|
||||
WaitForSingleObject(data_->thread_, INFINITE);
|
||||
}
|
||||
}
|
||||
|
||||
void OS::Sleep(int milliseconds) {
|
||||
::Sleep(milliseconds);
|
||||
}
|
@ -20,8 +20,16 @@
|
||||
#define LOG(text) printf("Profiler: %s\n", text)
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
typedef uint8 byte;
|
||||
#ifdef _MSC_VER
|
||||
typedef __int8 byte;
|
||||
typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#else
|
||||
#include <stdint.h>
|
||||
typedef uint8 byte;
|
||||
#endif
|
||||
typedef byte* Address;
|
||||
|
||||
class MapEntry {
|
||||
@ -163,7 +171,6 @@ class OS {
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
|
||||
// Create new thread.
|
||||
explicit Thread(const char* name);
|
||||
virtual ~Thread();
|
||||
@ -265,7 +272,6 @@ class Sampler {
|
||||
|
||||
const int interval_;
|
||||
const bool profiling_;
|
||||
const bool synchronous_;
|
||||
Atomic32 active_;
|
||||
PlatformData* data_; // Platform specific data.
|
||||
};
|
||||
|
@ -36,16 +36,16 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "thread_helper.h"
|
||||
#include "nscore.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
using mozilla::TimeStamp;
|
||||
using mozilla::TimeDuration;
|
||||
|
||||
// TODO Merge into Sampler.h
|
||||
|
||||
extern pthread_key_t pkey_stack;
|
||||
extern mozilla::tls::key pkey_stack;
|
||||
extern mozilla::tls::key pkey_ticker;
|
||||
extern bool stack_key_initialized;
|
||||
|
||||
#define SAMPLER_INIT() mozilla_sampler_init();
|
||||
@ -87,7 +87,22 @@ LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
|
||||
|
||||
# define STORE_SEQUENCER() pLinuxKernelMemoryBarrier()
|
||||
#elif defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
|
||||
# define STORE_SEQUENCER() asm volatile("" ::: "memory")
|
||||
# if defined(_MSC_VER)
|
||||
// MSVC2005 has a name collision bug caused when both <intrin.h> and <windows.h> are included together.
|
||||
# define _interlockedbittestandreset _interlockedbittestandreset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
|
||||
# define _interlockedbittestandset _interlockedbittestandset_NAME_CHANGED_TO_AVOID_MSVS2005_ERROR
|
||||
# include <intrin.h>
|
||||
// Even though MSVC2005 has the intrinsic _ReadWriteBarrier, it fails to link to it when it's
|
||||
// not explicitly declared.
|
||||
# pragma intrinsic(_ReadWriteBarrier)
|
||||
# define STORE_SEQUENCER() _ReadWriteBarrier();
|
||||
# elif defined(__INTEL_COMPILER)
|
||||
# define STORE_SEQUENCER() __memory_barrier();
|
||||
# elif __GNUC__
|
||||
# define STORE_SEQUENCER() asm volatile("" ::: "memory");
|
||||
# else
|
||||
# error "Memory clobber not supported for your compiler."
|
||||
# endif
|
||||
#else
|
||||
# error "Memory clobber not supported for your platform."
|
||||
#endif
|
||||
@ -181,7 +196,7 @@ public:
|
||||
// been written such that mStack is always consistent.
|
||||
mStack[mStackPointer] = aName;
|
||||
// Prevent the optimizer from re-ordering these instructions
|
||||
asm("":::"memory");
|
||||
STORE_SEQUENCER();
|
||||
mStackPointer++;
|
||||
}
|
||||
void pop()
|
||||
@ -198,15 +213,15 @@ public:
|
||||
}
|
||||
|
||||
// Keep a list of active checkpoints
|
||||
const char *mStack[1024];
|
||||
char const * volatile mStack[1024];
|
||||
// Keep a list of active markers to be applied to the next sample taken
|
||||
const char *mMarkers[1024];
|
||||
sig_atomic_t mStackPointer;
|
||||
sig_atomic_t mMarkerPointer;
|
||||
sig_atomic_t mDroppedStackEntries;
|
||||
char const * volatile mMarkers[1024];
|
||||
volatile mozilla::sig_safe_t mStackPointer;
|
||||
volatile mozilla::sig_safe_t mMarkerPointer;
|
||||
volatile mozilla::sig_safe_t mDroppedStackEntries;
|
||||
// We don't want to modify _markers from within the signal so we allow
|
||||
// it to queue a clear operation.
|
||||
sig_atomic_t mQueueClearMarker;
|
||||
volatile mozilla::sig_safe_t mQueueClearMarker;
|
||||
};
|
||||
|
||||
inline void* mozilla_sampler_call_enter(const char *aInfo)
|
||||
@ -216,7 +231,7 @@ inline void* mozilla_sampler_call_enter(const char *aInfo)
|
||||
if (!stack_key_initialized)
|
||||
return NULL;
|
||||
|
||||
Stack *stack = (Stack*)pthread_getspecific(pkey_stack);
|
||||
Stack *stack = mozilla::tls::get<Stack>(pkey_stack);
|
||||
// we can't infer whether 'stack' has been initialized
|
||||
// based on the value of stack_key_intiailized because
|
||||
// 'stack' is only intialized when a thread is being
|
||||
@ -245,7 +260,7 @@ inline void mozilla_sampler_call_exit(void *aHandle)
|
||||
|
||||
inline void mozilla_sampler_add_marker(const char *aMarker)
|
||||
{
|
||||
Stack *stack = (Stack*)pthread_getspecific(pkey_stack);
|
||||
Stack *stack = mozilla::tls::get<Stack>(pkey_stack);
|
||||
if (!stack) {
|
||||
return;
|
||||
}
|
||||
|
109
tools/profiler/sps/thread_helper.h
Normal file
109
tools/profiler/sps/thread_helper.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Ehsan Akhgari <ehsan@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
// Cross-platform lightweight thread local data wrappers
|
||||
|
||||
#if defined(XP_WIN)
|
||||
// This file will get included in any file that wants to add
|
||||
// a profiler mark. In order to not bring <windows.h> together
|
||||
// we just include windef.h and winbase.h which are sufficient
|
||||
// to get the prototypes for the Tls* functions.
|
||||
# include <windef.h>
|
||||
# include <winbase.h>
|
||||
#else
|
||||
# include <pthread.h>
|
||||
# include <signal.h>
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#if defined(XP_WIN)
|
||||
typedef unsigned long sig_safe_t;
|
||||
#else
|
||||
typedef sig_atomic_t sig_safe_t;
|
||||
#endif
|
||||
|
||||
namespace tls {
|
||||
|
||||
#if defined(XP_WIN)
|
||||
|
||||
typedef DWORD key;
|
||||
|
||||
template <typename T>
|
||||
static T* get(key mykey) {
|
||||
return (T*) TlsGetValue(mykey);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool set(key mykey, const T* value) {
|
||||
return TlsSetValue(mykey, const_cast<T*>(value));
|
||||
}
|
||||
|
||||
static inline bool create(key* mykey) {
|
||||
key newkey = TlsAlloc();
|
||||
if (newkey == TLS_OUT_OF_INDEXES) {
|
||||
return false;
|
||||
}
|
||||
*mykey = newkey;
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef pthread_key_t key;
|
||||
|
||||
template <typename T>
|
||||
static T* get(key mykey) {
|
||||
return (T*) pthread_getspecific(mykey);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static bool set(key mykey, const T* value) {
|
||||
return !pthread_setspecific(mykey, value);
|
||||
}
|
||||
|
||||
static bool create(key* mykey) {
|
||||
return !pthread_key_create(mykey, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,7 +51,11 @@
|
||||
#warning Please add support for your architecture in chromium_types.h
|
||||
#endif
|
||||
|
||||
typedef int32_t Atomic32;
|
||||
#ifdef _MSC_VER
|
||||
typedef __int32 Atomic32;
|
||||
#else
|
||||
typedef int32_t Atomic32;
|
||||
#endif
|
||||
|
||||
#if defined(V8_HOST_ARCH_X64) || defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_ARM)
|
||||
inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
|
Loading…
Reference in New Issue
Block a user