Skip to content

Commit ac330b4

Browse files
committed
Backed out changeset 81c5f8fff63e (bug 1665411) for causing deadlock on older OS X versions (e.g. OS X 10.12), see bug 1673826
1 parent 64a3416 commit ac330b4

File tree

4 files changed

+99
-24
lines changed

4 files changed

+99
-24
lines changed

js/src/threading/ProtectedData.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
#ifndef threading_ProtectedData_h
88
#define threading_ProtectedData_h
99

10-
#include "mozilla/Atomics.h"
1110
#include "jstypes.h"
1211
#include "threading/LockGuard.h"
1312
#include "threading/Mutex.h"

mozglue/misc/AutoProfilerLabel.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
#include "mozilla/AutoProfilerLabel.h"
88

9-
#include "mozilla/Assertions.h"
109
#include "mozilla/PlatformMutex.h"
1110

1211
namespace mozilla {

mozglue/misc/Mutex_posix.cpp

Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,15 @@
55
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
66

77
#include "mozilla/Assertions.h"
8+
#include "mozilla/Maybe.h"
89

10+
#include <algorithm>
911
#include <errno.h>
1012
#include <pthread.h>
1113
#include <stdio.h>
12-
13-
#if defined(XP_DARWIN)
14-
# include <pthread_spis.h>
15-
#endif
14+
#include <unistd.h>
1615

1716
#include "mozilla/PlatformMutex.h"
18-
#include "mozilla/Unused.h"
1917
#include "MutexPlatformData_posix.h"
2018

2119
#define REPORT_PTHREADS_ERROR(result, msg) \
@@ -33,22 +31,53 @@
3331
} \
3432
}
3533

36-
mozilla::detail::MutexImpl::MutexImpl() {
34+
#ifdef XP_DARWIN
35+
36+
// CPU count. Read concurrently from multiple threads. Written once during the
37+
// first mutex initialization; re-initialization is safe hence relaxed ordering
38+
// is OK.
39+
static mozilla::Atomic<uint32_t, mozilla::MemoryOrdering::Relaxed> sCPUCount(0);
40+
41+
static void EnsureCPUCount() {
42+
if (sCPUCount) {
43+
return;
44+
}
45+
46+
// _SC_NPROCESSORS_CONF and _SC_NPROCESSORS_ONLN are common, but not
47+
// standard.
48+
# if defined(_SC_NPROCESSORS_CONF)
49+
long n = sysconf(_SC_NPROCESSORS_CONF);
50+
sCPUCount = (n > 0) ? uint32_t(n) : 1;
51+
# elif defined(_SC_NPROCESSORS_ONLN)
52+
long n = sysconf(_SC_NPROCESSORS_ONLN);
53+
sCPUCount = (n > 0) ? uint32_t(n) : 1;
54+
# else
55+
sCPUCount = 1;
56+
# endif
57+
}
58+
59+
#endif // XP_DARWIN
60+
61+
mozilla::detail::MutexImpl::MutexImpl()
62+
#ifdef XP_DARWIN
63+
: averageSpins(0)
64+
#endif
65+
{
3766
pthread_mutexattr_t* attrp = nullptr;
3867

39-
#if defined(DEBUG)
40-
# define MUTEX_KIND PTHREAD_MUTEX_ERRORCHECK
41-
// Linux with glibc, FreeBSD and macOS 10.14+ support adaptive mutexes that
42-
// spin for a short number of tries before sleeping. NSPR's locks did this,
43-
// too, and it seems like a reasonable thing to do.
44-
#elif (defined(__linux__) && defined(__GLIBC__)) || defined(__FreeBSD__)
45-
# define MUTEX_KIND PTHREAD_MUTEX_ADAPTIVE_NP
46-
#elif defined(XP_DARWIN)
47-
# define POLICY_KIND _PTHREAD_MUTEX_POLICY_FIRSTFIT
68+
// Linux with glibc and FreeBSD support adaptive mutexes that spin
69+
// for a short number of tries before sleeping. NSPR's locks did
70+
// this, too, and it seems like a reasonable thing to do.
71+
#if (defined(__linux__) && defined(__GLIBC__)) || defined(__FreeBSD__)
72+
# define ADAPTIVE_MUTEX_SUPPORTED
4873
#endif
4974

50-
#if defined(MUTEX_KIND) || defined(POLICY_KIND)
75+
#if defined(DEBUG)
76+
# define ATTR_REQUIRED
77+
# define MUTEX_KIND PTHREAD_MUTEX_ERRORCHECK
78+
#elif defined(ADAPTIVE_MUTEX_SUPPORTED)
5179
# define ATTR_REQUIRED
80+
# define MUTEX_KIND PTHREAD_MUTEX_ADAPTIVE_NP
5281
#endif
5382

5483
#if defined(ATTR_REQUIRED)
@@ -58,14 +87,9 @@ mozilla::detail::MutexImpl::MutexImpl() {
5887
pthread_mutexattr_init(&attr),
5988
"mozilla::detail::MutexImpl::MutexImpl: pthread_mutexattr_init failed");
6089

61-
# if defined(MUTEX_KIND)
6290
TRY_CALL_PTHREADS(pthread_mutexattr_settype(&attr, MUTEX_KIND),
6391
"mozilla::detail::MutexImpl::MutexImpl: "
6492
"pthread_mutexattr_settype failed");
65-
# elif defined(POLICY_KIND)
66-
// This can fail on macOS 10.13 and lower but that's OK
67-
Unused << pthread_mutexattr_setpolicy_np(&attr, POLICY_KIND);
68-
# endif
6993
attrp = &attr;
7094
#endif
7195

@@ -78,6 +102,10 @@ mozilla::detail::MutexImpl::MutexImpl() {
78102
"mozilla::detail::MutexImpl::MutexImpl: "
79103
"pthread_mutexattr_destroy failed");
80104
#endif
105+
106+
#ifdef XP_DARWIN
107+
EnsureCPUCount();
108+
#endif
81109
}
82110

83111
mozilla::detail::MutexImpl::~MutexImpl() {
@@ -109,7 +137,49 @@ bool mozilla::detail::MutexImpl::mutexTryLock() {
109137
"mozilla::detail::MutexImpl::mutexTryLock: pthread_mutex_trylock failed");
110138
}
111139

112-
void mozilla::detail::MutexImpl::lock() { mutexLock(); }
140+
void mozilla::detail::MutexImpl::lock() {
141+
#ifndef XP_DARWIN
142+
mutexLock();
143+
#else
144+
// Mutex performance on OSX can be very poor if there's a lot of contention as
145+
// this causes excessive context switching. On Linux/FreeBSD we use the
146+
// adaptive mutex type (PTHREAD_MUTEX_ADAPTIVE_NP) to address this, but this
147+
// isn't available on OSX. The code below is a reimplementation of this
148+
// feature.
149+
150+
MOZ_ASSERT(sCPUCount);
151+
if (sCPUCount == 1) {
152+
mutexLock();
153+
return;
154+
}
155+
156+
if (!mutexTryLock()) {
157+
const int32_t SpinLimit = 100;
158+
159+
int32_t count = 0;
160+
int32_t maxSpins = std::min(SpinLimit, 2 * averageSpins + 10);
161+
do {
162+
if (count >= maxSpins) {
163+
mutexLock();
164+
break;
165+
}
166+
// Hint to the processor that we're spinning.
167+
# ifdef __x86_64__
168+
# define SPIN_HINT "pause"
169+
# elif defined(__aarch64__)
170+
# define SPIN_HINT "yield"
171+
# endif
172+
asm volatile(SPIN_HINT ::: "memory");
173+
# undef SPIN_HINT
174+
count++;
175+
} while (!mutexTryLock());
176+
177+
// Update moving average.
178+
averageSpins += (count - averageSpins) / 8;
179+
MOZ_ASSERT(averageSpins >= 0 && averageSpins <= SpinLimit);
180+
}
181+
#endif // XP_DARWIN
182+
}
113183

114184
void mozilla::detail::MutexImpl::unlock() {
115185
TRY_CALL_PTHREADS(

mozglue/misc/PlatformMutex.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <utility>
1111

12+
#include "mozilla/Atomics.h"
1213
#include "mozilla/Attributes.h"
1314

1415
#if !defined(XP_WIN)
@@ -52,6 +53,12 @@ class MutexImpl {
5253
static_assert(sizeof(pthread_mutex_t) / sizeof(void*) != 0 &&
5354
sizeof(pthread_mutex_t) % sizeof(void*) == 0,
5455
"pthread_mutex_t must have pointer alignment");
56+
# ifdef XP_DARWIN
57+
// Moving average of the number of spins it takes to acquire the mutex if we
58+
// have to wait. May be accessed by multiple threads concurrently. Getting the
59+
// latest value is not essential hence relaxed memory ordering is sufficient.
60+
mozilla::Atomic<int32_t, mozilla::MemoryOrdering::Relaxed> averageSpins;
61+
# endif
5562
#else
5663
void* platformData_[6];
5764
#endif

0 commit comments

Comments
 (0)