Bug 956899 - Add a platform agnostic std::mutex work-alike; r=froydnj

This commit is contained in:
Bert Belder 2014-01-19 17:57:00 -08:00
parent bd531e5bce
commit 5f4e469c58
8 changed files with 247 additions and 0 deletions

View File

@ -83,6 +83,7 @@ UNIFIED_SOURCES += [
'testStructuredClone.cpp',
'testSymbol.cpp',
'testThreadingExclusiveData.cpp',
'testThreadingMutex.cpp',
'testToIntWidth.cpp',
'testTypedArrays.cpp',
'testUbiNode.cpp',

View File

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
*/
/* 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 "jsapi-tests/tests.h"
#include "threading/Mutex.h"
BEGIN_TEST(testThreadingMutex)
{
js::Mutex mutex;
mutex.lock();
mutex.unlock();
return true;
}
END_TEST(testThreadingMutex)

View File

@ -543,12 +543,14 @@ elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
if CONFIG['OS_ARCH'] == 'WINNT':
SOURCES += [
'jit/ExecutableAllocatorWin.cpp',
'threading/windows/Mutex.cpp',
]
# _CRT_RAND_S must be #defined before #including stdlib.h to get rand_s()
DEFINES['_CRT_RAND_S'] = True
else:
SOURCES += [
'jit/ExecutableAllocatorPosix.cpp',
'threading/posix/Mutex.cpp',
]
if CONFIG['JS_HAS_CTYPES']:

51
js/src/threading/Mutex.h Normal file
View File

@ -0,0 +1,51 @@
/* -*- 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/. */
#ifndef threading_Mutex_h
#define threading_Mutex_h
#include "mozilla/Attributes.h"
namespace js {
class Mutex
{
public:
struct PlatformData;
Mutex();
~Mutex();
void lock();
void unlock();
private:
Mutex(const Mutex&) = delete;
void operator=(const Mutex&) = delete;
Mutex(Mutex&&) = delete;
void operator=(Mutex&&) = delete;
PlatformData* platformData();
// Linux and maybe other platforms define the storage size of pthread_mutex_t in
// bytes. However, we must define it as an array of void pointers to ensure
// proper alignment.
#if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
void* platformData_[11];
#elif defined(__APPLE__) && defined(__MACH__) && defined(__amd64__)
void* platformData_[8];
#elif defined(__linux__)
void* platformData_[40 / sizeof(void*)];
#elif defined(_WIN32)
void* platformData_[6];
#else
#error "Mutex platform data size isn't known for this platform"
#endif
};
} // namespace js
#endif // threading_Mutex_h

View File

@ -0,0 +1,46 @@
/* -*- 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/Assertions.h"
#include <pthread.h>
#include "threading/Mutex.h"
#include "threading/posix/MutexPlatformData.h"
js::Mutex::Mutex()
{
int r = pthread_mutex_init(&platformData()->ptMutex, NULL);
MOZ_RELEASE_ASSERT(r == 0);
}
js::Mutex::~Mutex()
{
int r = pthread_mutex_destroy(&platformData()->ptMutex);
MOZ_RELEASE_ASSERT(r == 0);
}
void
js::Mutex::lock()
{
int r = pthread_mutex_lock(&platformData()->ptMutex);
MOZ_RELEASE_ASSERT(r == 0);
}
void
js::Mutex::unlock()
{
int r = pthread_mutex_unlock(&platformData()->ptMutex);
MOZ_RELEASE_ASSERT(r == 0);
}
js::Mutex::PlatformData*
js::Mutex::platformData()
{
static_assert(sizeof(platformData_) >= sizeof(PlatformData),
"platformData_ is too small");
return reinterpret_cast<PlatformData*>(platformData_);
}

View File

@ -0,0 +1,23 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 platform_win_MutexPlatformData_h
#define platform_win_MutexPlatformData_h
#include <pthread.h>
#include "threading/Mutex.h"
namespace js {
struct Mutex::PlatformData
{
pthread_mutex_t ptMutex;
};
} // namespace js
#endif // platform_win_MutexPlatformData_h

View File

@ -0,0 +1,83 @@
/* -*- 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/Assertions.h"
#include "mozilla/DebugOnly.h"
#include "jswin.h"
#include "threading/Mutex.h"
#include "threading/windows/MutexPlatformData.h"
namespace {
// We build with a toolkit that supports WinXP, so we have to probe
// for modern features at runtime. This is necessary because Vista and
// later automatically allocate and subsequently leak a debug info
// object for each critical section that we allocate unless we tell it
// not to. In order to tell it not to, we need the extra flags field
// provided by the Ex version of InitializeCriticalSection.
struct MutexNativeImports
{
using InitializeCriticalSectionExT = BOOL (WINAPI*)(CRITICAL_SECTION*, DWORD, DWORD);
InitializeCriticalSectionExT InitializeCriticalSectionEx;
MutexNativeImports() {
HMODULE kernel32_dll = GetModuleHandle("kernel32.dll");
MOZ_RELEASE_ASSERT(kernel32_dll != NULL);
InitializeCriticalSectionEx = reinterpret_cast<InitializeCriticalSectionExT>(
GetProcAddress(kernel32_dll, "InitializeCriticalSectionEx"));
}
bool hasInitializeCriticalSectionEx() const {
return InitializeCriticalSectionEx;
}
};
static MutexNativeImports NativeImports;
} // (anonymous namespace)
js::Mutex::Mutex()
{
// This number was adopted from NSPR.
const static DWORD LockSpinCount = 1500;
BOOL r;
if (NativeImports.hasInitializeCriticalSectionEx()) {
r = NativeImports.InitializeCriticalSectionEx(&platformData()->criticalSection,
LockSpinCount,
CRITICAL_SECTION_NO_DEBUG_INFO);
} else {
r = InitializeCriticalSectionAndSpinCount(&platformData()->criticalSection,
LockSpinCount);
}
MOZ_RELEASE_ASSERT(r);
}
js::Mutex::~Mutex()
{
DeleteCriticalSection(&platformData()->criticalSection);
}
void
js::Mutex::lock()
{
EnterCriticalSection(&platformData()->criticalSection);
}
void
js::Mutex::unlock()
{
LeaveCriticalSection(&platformData()->criticalSection);
}
js::Mutex::PlatformData*
js::Mutex::platformData()
{
static_assert(sizeof(platformData_) >= sizeof(PlatformData),
"platformData_ is too small");
return reinterpret_cast<PlatformData*>(platformData_);
}

View File

@ -0,0 +1,23 @@
/* -*- 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/. */
#ifndef platform_win_MutexPlatformData_h
#define platform_win_MutexPlatformData_h
#include "jswin.h"
#include "threading/Mutex.h"
namespace js {
struct Mutex::PlatformData
{
CRITICAL_SECTION criticalSection;
};
} // namespace js
#endif // platform_win_MutexPlatformData_h