forked from Floorp-Projects/Floorp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 1347963 - part 1 - introduce mozilla::RecursiveMutex; r=erahm
Having a proper recursively-acquirable mutex type makes intent clearer, and RecursiveMutex also happens to be somewhat faster than ReentrantMonitor.
- Loading branch information
Showing
11 changed files
with
332 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/* -*- 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 "nsThreadUtils.h" | ||
#include "mozilla/RecursiveMutex.h" | ||
#include "gtest/gtest.h" | ||
|
||
using mozilla::RecursiveMutex; | ||
using mozilla::RecursiveMutexAutoLock; | ||
|
||
// Basic test to make sure the underlying implementation of RecursiveMutex is, | ||
// well, actually recursively acquirable. | ||
|
||
TEST(RecursiveMutex, SmokeTest) | ||
{ | ||
RecursiveMutex mutex("testing mutex"); | ||
|
||
RecursiveMutexAutoLock lock1(mutex); | ||
RecursiveMutexAutoLock lock2(mutex); | ||
|
||
//...and done. | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* -*- 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/RecursiveMutex.h" | ||
|
||
#ifdef XP_WIN | ||
#include <windows.h> | ||
|
||
#define NativeHandle(m) (reinterpret_cast<CRITICAL_SECTION*>(&m)) | ||
#endif | ||
|
||
namespace mozilla { | ||
|
||
RecursiveMutex::RecursiveMutex(const char* aName MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) | ||
: BlockingResourceBase(aName, eRecursiveMutex) | ||
#ifdef DEBUG | ||
, mOwningThread(nullptr) | ||
, mEntryCount(0) | ||
#endif | ||
{ | ||
MOZ_GUARD_OBJECT_NOTIFIER_INIT; | ||
#ifdef XP_WIN | ||
// This number was adapted from NSPR. | ||
static const DWORD sLockSpinCount = 100; | ||
|
||
#if defined(RELEASE_OR_BETA) | ||
// Vista and later automatically allocate and subsequently leak a debug info | ||
// object for each critical section that we allocate unless we tell the | ||
// system not to do that. | ||
DWORD flags = CRITICAL_SECTION_NO_DEBUG_INFO; | ||
#else | ||
DWORD flags = 0; | ||
#endif | ||
BOOL r = InitializeCriticalSectionEx(NativeHandle(mMutex), | ||
sLockSpinCount, flags); | ||
MOZ_RELEASE_ASSERT(r); | ||
#else | ||
pthread_mutexattr_t attr; | ||
|
||
MOZ_RELEASE_ASSERT(pthread_mutexattr_init(&attr) == 0, | ||
"pthread_mutexattr_init failed"); | ||
|
||
MOZ_RELEASE_ASSERT(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) == 0, | ||
"pthread_mutexattr_settype failed"); | ||
|
||
MOZ_RELEASE_ASSERT(pthread_mutex_init(&mMutex, &attr) == 0, | ||
"pthread_mutex_init failed"); | ||
|
||
MOZ_RELEASE_ASSERT(pthread_mutexattr_destroy(&attr) == 0, | ||
"pthread_mutexattr_destroy failed"); | ||
#endif | ||
} | ||
|
||
RecursiveMutex::~RecursiveMutex() | ||
{ | ||
#ifdef XP_WIN | ||
DeleteCriticalSection(NativeHandle(mMutex)); | ||
#else | ||
MOZ_RELEASE_ASSERT(pthread_mutex_destroy(&mMutex) == 0, | ||
"pthread_mutex_destroy failed"); | ||
#endif | ||
} | ||
|
||
void | ||
RecursiveMutex::LockInternal() | ||
{ | ||
#ifdef XP_WIN | ||
EnterCriticalSection(NativeHandle(mMutex)); | ||
#else | ||
MOZ_RELEASE_ASSERT(pthread_mutex_lock(&mMutex) == 0, | ||
"pthread_mutex_lock failed"); | ||
#endif | ||
} | ||
|
||
void | ||
RecursiveMutex::UnlockInternal() | ||
{ | ||
#ifdef XP_WIN | ||
LeaveCriticalSection(NativeHandle(mMutex)); | ||
#else | ||
MOZ_RELEASE_ASSERT(pthread_mutex_unlock(&mMutex) == 0, | ||
"pthread_mutex_unlock failed"); | ||
#endif | ||
} | ||
|
||
} // namespace mozilla |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
|
||
/* -*- 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/. */ | ||
|
||
// A lock that can be acquired multiple times on the same thread. | ||
|
||
#ifndef mozilla_RecursiveMutex_h | ||
#define mozilla_RecursiveMutex_h | ||
|
||
#include "mozilla/BlockingResourceBase.h" | ||
#include "mozilla/GuardObjects.h" | ||
|
||
#ifndef XP_WIN | ||
#include <pthread.h> | ||
#endif | ||
|
||
namespace mozilla { | ||
|
||
class RecursiveMutex : public BlockingResourceBase | ||
{ | ||
public: | ||
explicit RecursiveMutex(const char* aName MOZ_GUARD_OBJECT_NOTIFIER_PARAM); | ||
~RecursiveMutex(); | ||
|
||
#ifdef DEBUG | ||
void Lock(); | ||
void Unlock(); | ||
#else | ||
void Lock() { LockInternal(); } | ||
void Unlock() { UnlockInternal(); } | ||
#endif | ||
|
||
void AssertCurrentThreadIn() | ||
#ifdef DEBUG | ||
; | ||
#else | ||
{ | ||
} | ||
#endif | ||
|
||
private: | ||
RecursiveMutex() = delete; | ||
RecursiveMutex(const RecursiveMutex&) = delete; | ||
RecursiveMutex& operator=(const RecursiveMutex&) = delete; | ||
|
||
void LockInternal(); | ||
void UnlockInternal(); | ||
|
||
#ifdef DEBUG | ||
PRThread* mOwningThread; | ||
size_t mEntryCount; | ||
#endif | ||
|
||
#if !defined(XP_WIN) | ||
pthread_mutex_t mMutex; | ||
#else | ||
// We eschew including windows.h and using CRITICAL_SECTION here so that files | ||
// including us don't also pull in windows.h. Just use a type that's big | ||
// enough for CRITICAL_SECTION, and we'll fix it up later. | ||
void* mMutex[6]; | ||
#endif | ||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER | ||
}; | ||
|
||
class MOZ_RAII RecursiveMutexAutoLock | ||
{ | ||
public: | ||
explicit RecursiveMutexAutoLock(RecursiveMutex& aRecursiveMutex | ||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) | ||
: mRecursiveMutex(&aRecursiveMutex) | ||
{ | ||
MOZ_GUARD_OBJECT_NOTIFIER_INIT; | ||
NS_ASSERTION(mRecursiveMutex, "null mutex"); | ||
mRecursiveMutex->Lock(); | ||
} | ||
|
||
~RecursiveMutexAutoLock(void) | ||
{ | ||
mRecursiveMutex->Unlock(); | ||
} | ||
|
||
private: | ||
RecursiveMutexAutoLock() = delete; | ||
RecursiveMutexAutoLock(const RecursiveMutexAutoLock&) = delete; | ||
RecursiveMutexAutoLock& operator=(const RecursiveMutexAutoLock&) = delete; | ||
static void* operator new(size_t) CPP_THROW_NEW; | ||
|
||
mozilla::RecursiveMutex* mRecursiveMutex; | ||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER | ||
}; | ||
|
||
class MOZ_RAII RecursiveMutexAutoUnlock | ||
{ | ||
public: | ||
explicit RecursiveMutexAutoUnlock(RecursiveMutex& aRecursiveMutex | ||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM) | ||
: mRecursiveMutex(&aRecursiveMutex) | ||
{ | ||
MOZ_GUARD_OBJECT_NOTIFIER_INIT; | ||
NS_ASSERTION(mRecursiveMutex, "null mutex"); | ||
mRecursiveMutex->Unlock(); | ||
} | ||
|
||
~RecursiveMutexAutoUnlock(void) | ||
{ | ||
mRecursiveMutex->Lock(); | ||
} | ||
|
||
private: | ||
RecursiveMutexAutoUnlock() = delete; | ||
RecursiveMutexAutoUnlock(const RecursiveMutexAutoUnlock&) = delete; | ||
RecursiveMutexAutoUnlock& operator=(const RecursiveMutexAutoUnlock&) = delete; | ||
static void* operator new(size_t) CPP_THROW_NEW; | ||
|
||
mozilla::RecursiveMutex* mRecursiveMutex; | ||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER | ||
}; | ||
|
||
} // namespace mozilla | ||
|
||
#endif // mozilla_RecursiveMutex_h |
Oops, something went wrong.