Bug 956899 - Move and rename rust-alike Mutex to ExclusiveData; r=fitzgen
☠☠ backed out by 359ea99d2000 ☠ ☠
authorTerrence Cole <terrence@mozilla.com>
Thu, 03 Mar 2016 11:15:53 -0800
changeset 338011 7f7f0a43f051424dbdc87db33a9947f7b87e8c89
parent 338010 17a2a03c4fe3cd5e158bf0ad8e9db8b4782668ee
child 338012 f00750b51d8fb610ff05e16c96108cf0a68b6b5f
child 338373 b9f2f42cab834474c7ff6c6da0dd421472d0f9f9
child 338605 7dba74d49660aa8bf39197bccd55b15377a2f823
child 338649 3c8a113177b294e4034e7497cf9b4e46a711eb52
child 338663 d08636ecd9abcb4b53e8f9e03baa6596cbeb7308
child 339173 661f249defdcd0fda973ef48a4dcaa951f64f040
push id12405
push usercku@mozilla.com
push dateTue, 08 Mar 2016 03:35:29 +0000
reviewersfitzgen
bugs956899
milestone47.0a1
Bug 956899 - Move and rename rust-alike Mutex to ExclusiveData; r=fitzgen
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testMutex.cpp
js/src/jsapi-tests/testThreadingExclusiveData.cpp
js/src/moz.build
js/src/threading/ExclusiveData.cpp
js/src/threading/ExclusiveData.h
js/src/vm/Mutex.cpp
js/src/vm/Mutex.h
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -54,17 +54,16 @@ UNIFIED_SOURCES += [
     'testIntString.cpp',
     'testIntTypesABI.cpp',
     'testIsInsideNursery.cpp',
     'testJSEvaluateScript.cpp',
     'testLookup.cpp',
     'testLooselyEqual.cpp',
     'testMappedArrayBuffer.cpp',
     'testMutedErrors.cpp',
-    'testMutex.cpp',
     'testNewObject.cpp',
     'testNewTargetInvokeConstructor.cpp',
     'testNullRoot.cpp',
     'testObjectEmulatingUndefined.cpp',
     'testOOM.cpp',
     'testParseJSON.cpp',
     'testPersistentRooted.cpp',
     'testPreserveJitCode.cpp',
@@ -78,16 +77,17 @@ UNIFIED_SOURCES += [
     'testScriptInfo.cpp',
     'testScriptObject.cpp',
     'testSetProperty.cpp',
     'testSetPropertyIgnoringNamedGetter.cpp',
     'testSourcePolicy.cpp',
     'testStringBuffer.cpp',
     'testStructuredClone.cpp',
     'testSymbol.cpp',
+    'testThreadingExclusiveData.cpp',
     'testToIntWidth.cpp',
     'testTypedArrays.cpp',
     'testUbiNode.cpp',
     'testUncaughtError.cpp',
     'testUTF8.cpp',
     'testWasmLEB128.cpp',
     'testWeakMap.cpp',
     'testXDR.cpp',
rename from js/src/jsapi-tests/testMutex.cpp
rename to js/src/jsapi-tests/testThreadingExclusiveData.cpp
--- a/js/src/jsapi-tests/testMutex.cpp
+++ b/js/src/jsapi-tests/testThreadingExclusiveData.cpp
@@ -2,50 +2,48 @@
  * 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 "mozilla/IntegerRange.h"
 #include "js/Vector.h"
 #include "jsapi-tests/tests.h"
-#include "vm/Mutex.h"
+#include "threading/ExclusiveData.h"
 
 // One thread for each bit in our counter.
 const static uint8_t numThreads = 64;
+const static bool showDiagnostics = false;
 
 struct CounterAndBit
 {
     uint8_t bit;
-    const js::Mutex<uint64_t>& counter;
+    const js::ExclusiveData<uint64_t>& counter;
 
-    CounterAndBit(uint8_t bit, const js::Mutex<uint64_t>& counter)
+    CounterAndBit(uint8_t bit, const js::ExclusiveData<uint64_t>& counter)
       : bit(bit)
       , counter(counter)
     {
         MOZ_ASSERT(bit < numThreads);
     }
 };
 
-const static bool shouldPrint = false;
-
 void
 printDiagnosticMessage(uint64_t seen)
 {
-    if (!shouldPrint)
-        return;
-
-    fprintf(stderr, "Thread %p saw ", PR_GetCurrentThread());
-    for (auto i : mozilla::MakeRange(numThreads)) {
-        if (seen & (uint64_t(1) << i))
-            fprintf(stderr, "1");
-        else
-            fprintf(stderr, "0");
+    if (showDiagnostics) {
+        fprintf(stderr, "Thread %p saw ", PR_GetCurrentThread());
+        for (auto i : mozilla::MakeRange(numThreads)) {
+            if (seen & (uint64_t(1) << i))
+                fprintf(stderr, "1");
+            else
+                fprintf(stderr, "0");
+        }
+        fprintf(stderr, "\n");
     }
-    fprintf(stderr, "\n");
 }
 
 void
 setBitAndCheck(void* arg)
 {
     auto& counterAndBit = *static_cast<CounterAndBit*>(arg);
 
     while (true) {
@@ -64,22 +62,19 @@ setBitAndCheck(void* arg)
             if (guard == UINT64_MAX) {
                 js_delete(&counterAndBit);
                 return;
             }
         }
     }
 }
 
-BEGIN_TEST(testMutex)
+BEGIN_TEST(testExclusiveData)
 {
-    auto maybeCounter = js::Mutex<uint64_t>::Create(0);
-    CHECK(maybeCounter.isSome());
-
-    js::Mutex<uint64_t> counter(mozilla::Move(*maybeCounter));
+    js::ExclusiveData<uint64_t> counter(0);
 
     js::Vector<PRThread*> threads(cx);
     CHECK(threads.reserve(numThreads));
 
     for (auto i : mozilla::MakeRange(numThreads)) {
         auto counterAndBit = js_new<CounterAndBit>(i, counter);
         CHECK(counterAndBit);
         auto thread = PR_CreateThread(PR_USER_THREAD,
@@ -94,9 +89,9 @@ BEGIN_TEST(testMutex)
     }
 
     for (auto thread : threads) {
         CHECK(PR_JoinThread(thread) == PR_SUCCESS);
     }
 
     return true;
 }
-END_TEST(testMutex)
+END_TEST(testExclusiveData)
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -289,16 +289,17 @@ UNIFIED_SOURCES += [
     'proxy/DeadObjectProxy.cpp',
     'proxy/DirectProxyHandler.cpp',
     'proxy/OpaqueCrossCompartmentWrapper.cpp',
     'proxy/Proxy.cpp',
     'proxy/ScriptedDirectProxyHandler.cpp',
     'proxy/ScriptedIndirectProxyHandler.cpp',
     'proxy/SecurityWrapper.cpp',
     'proxy/Wrapper.cpp',
+    'threading/ExclusiveData.cpp',
     'vm/ArgumentsObject.cpp',
     'vm/ArrayBufferObject.cpp',
     'vm/CallNonGenericMethod.cpp',
     'vm/CharacterEncoding.cpp',
     'vm/CodeCoverage.cpp',
     'vm/Compression.cpp',
     'vm/DateTime.cpp',
     'vm/Debugger.cpp',
@@ -308,17 +309,16 @@ UNIFIED_SOURCES += [
     'vm/GeneratorObject.cpp',
     'vm/GlobalObject.cpp',
     'vm/HelperThreads.cpp',
     'vm/Id.cpp',
     'vm/Interpreter.cpp',
     'vm/JSONParser.cpp',
     'vm/MemoryMetrics.cpp',
     'vm/Monitor.cpp',
-    'vm/Mutex.cpp',
     'vm/NativeObject.cpp',
     'vm/ObjectGroup.cpp',
     'vm/PIC.cpp',
     'vm/Printer.cpp',
     'vm/Probes.cpp',
     'vm/ProxyObject.cpp',
     'vm/ReceiverGuard.cpp',
     'vm/RegExpObject.cpp',
rename from js/src/vm/Mutex.cpp
rename to js/src/threading/ExclusiveData.cpp
--- a/js/src/vm/Mutex.cpp
+++ b/js/src/threading/ExclusiveData.cpp
@@ -1,39 +1,39 @@
 /* -*- 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 "vm/Mutex.h"
+#include "threading/ExclusiveData.h"
 
 namespace js {
 
-/* static */ mozilla::Maybe<detail::MutexBase>
-detail::MutexBase::Create()
+/* static */ mozilla::Maybe<detail::ExclusiveDataBase>
+detail::ExclusiveDataBase::Create()
 {
     auto lock = PR_NewLock();
     if (!lock)
         return mozilla::Nothing();
 
-    return mozilla::Some(detail::MutexBase(lock));
+    return mozilla::Some(detail::ExclusiveDataBase(lock));
 }
 
-detail::MutexBase::~MutexBase()
+detail::ExclusiveDataBase::~ExclusiveDataBase()
 {
     if (lock_)
         PR_DestroyLock(lock_);
 }
 
 void
-detail::MutexBase::acquire() const
+detail::ExclusiveDataBase::acquire() const
 {
     PR_Lock(lock_);
 }
 
 void
-detail::MutexBase::release() const
+detail::ExclusiveDataBase::release() const
 {
     MOZ_RELEASE_ASSERT(PR_Unlock(lock_) == PR_SUCCESS);
 }
 
 } // namespace js
rename from js/src/vm/Mutex.h
rename to js/src/threading/ExclusiveData.h
--- a/js/src/vm/Mutex.h
+++ b/js/src/threading/ExclusiveData.h
@@ -1,64 +1,64 @@
 /* -*- 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 js_Mutex_h
-#define js_Mutex_h
+#ifndef threading_ExclusiveData_h
+#define threading_ExclusiveData_h
 
 #include "mozilla/Maybe.h"
 #include "mozilla/Move.h"
 
 #include "jslock.h"
 
 namespace js {
 
 namespace detail {
 
-class MutexBase
+class ExclusiveDataBase
 {
   private:
     mutable PRLock* lock_;
 
-    MutexBase(const MutexBase&) = delete;
-    MutexBase& operator=(const MutexBase&) = delete;
+    ExclusiveDataBase(const ExclusiveDataBase&) = delete;
+    ExclusiveDataBase& operator=(const ExclusiveDataBase&) = delete;
 
   public:
     // This move constructor is only public for `mozilla::Forward`.
-    MutexBase(MutexBase&& rhs)
+    ExclusiveDataBase(ExclusiveDataBase&& rhs)
       : lock_(rhs.lock_)
     {
         MOZ_ASSERT(&rhs != this, "self-move disallowed!");
         rhs.lock_ = nullptr;
     }
 
-    ~MutexBase();
+    ~ExclusiveDataBase();
 
   protected:
-    explicit MutexBase(PRLock* lock)
+    explicit ExclusiveDataBase(PRLock* lock)
       : lock_(lock)
     {
         MOZ_ASSERT(lock_);
     }
 
-    static mozilla::Maybe<MutexBase> Create();
+    static mozilla::Maybe<ExclusiveDataBase> Create();
 
     void acquire() const;
     void release() const;
 };
 
 } // namespace detail
 
 /**
  * A mutual exclusion lock class.
  *
- * `Mutex` provides an RAII guard to automatically lock and unlock when
+ * `ExclusiveData` provides an RAII guard to automatically lock and unlock when
  * accessing the protected inner value.
  *
  * Unlike the STL's `std::mutex`, the protected value is internal to this
  * class. This is a huge win: one no longer has to rely on documentation to
  * explain the relationship between a lock and its protected data, and the type
  * system can enforce[0] it.
  *
  * For example, suppose we have a counter class:
@@ -72,109 +72,111 @@ class MutexBase
  *     };
  *
  * If we share a counter across threads with `std::mutex`, we rely solely on
  * comments to document the relationship between the lock and its data, like
  * this:
  *
  *     class SharedCounter
  *     {
- *         // Remember to acquire `counter_lock` when accessing `counter`, pretty please!
+ *         // Remember to acquire `counter_lock` when accessing `counter`,
+ *         // pretty please!
  *         Counter counter;
  *         std::mutex counter_lock;
  *
  *       public:
  *         void inc(size_t n) {
  *             // Whoops, forgot to acquire the lock! Off to the races!
  *             counter.inc(n);
  *         }
  *     };
  *
- * In contrast, `Mutex` wraps the protected value, enabling the type system to
- * enforce that we acquire the lock before accessing the value:
+ * In contrast, `ExclusiveData` wraps the protected value, enabling the type
+ * system to enforce that we acquire the lock before accessing the value:
  *
  *     class SharedCounter
  *     {
- *         Mutex<Counter> counter;
+ *         ExclusiveData<Counter> counter;
  *
  *       public:
  *         void inc(size_t n) {
  *             auto guard = counter.lock();
  *             guard->inc(n);
  *         }
  *     };
  *
  * The API design is based on Rust's `std::sync::Mutex<T>` type.
  *
  * [0]: Of course, we don't have a borrow checker in C++, so the type system
  *      cannot guarantee that you don't stash references received from
- *      `Mutex<T>::Guard` somewhere such that the reference outlives the guard's
- *      lifetime and therefore becomes invalid. To help avoid this last
+ *      `ExclusiveData<T>::Guard` somewhere such that the reference outlives the
+ *      guard's lifetime and therefore becomes invalid. To help avoid this last
  *      foot-gun, prefer using the guard directly! Do not store raw references
  *      to the protected value in other structures!
  */
 template <typename T>
-class Mutex : private detail::MutexBase
+class ExclusiveData : private detail::ExclusiveDataBase
 {
     mutable T value_;
 
-    Mutex(const Mutex&) = delete;
-    Mutex& operator=(const Mutex&) = delete;
+    ExclusiveData(const ExclusiveData&) = delete;
+    ExclusiveData& operator=(const ExclusiveData&) = delete;
 
     template <typename U>
-    explicit Mutex(U&& u, MutexBase&& base)
-      : MutexBase(mozilla::Move(base))
+    explicit ExclusiveData(U&& u, ExclusiveDataBase&& base)
+      : ExclusiveDataBase(mozilla::Move(base))
       , value_(mozilla::Forward<U>(u))
     { }
 
   public:
     /**
-     * Create a new `Mutex`, with perfect forwarding of the protected value.
+     * Create a new `ExclusiveData`, with perfect forwarding of the protected
+     * value.
      *
      * On success, `mozilla::Some` is returned. On failure, `mozilla::Nothing`
      * is returned.
      */
     template <typename U>
-    static mozilla::Maybe<Mutex<T>> Create(U&& u) {
-        auto base = detail::MutexBase::Create();
+    static mozilla::Maybe<ExclusiveData<T>> Create(U&& u) {
+        auto base = detail::ExclusiveDataBase::Create();
         if (base.isNothing())
             return mozilla::Nothing();
-        return mozilla::Some(Mutex(mozilla::Forward<U>(u), mozilla::Move(*base)));
+        return mozilla::Some(ExclusiveData(mozilla::Forward<U>(u), mozilla::Move(*base)));
     }
 
-    Mutex(Mutex&& rhs)
-      : MutexBase(mozilla::Move(static_cast<MutexBase&&>(rhs)))
+    ExclusiveData(ExclusiveData&& rhs)
+      : ExclusiveDataBase(mozilla::Move(static_cast<ExclusiveDataBase&&>(rhs)))
       , value_(mozilla::Move(rhs.value_))
     {
         MOZ_ASSERT(&rhs != this, "self-move disallowed!");
     }
 
-    Mutex& operator=(Mutex&& rhs) {
-        this->~Mutex();
-        new (this) Mutex(mozilla::Move(rhs));
+    ExclusiveData& operator=(ExclusiveData&& rhs) {
+        this->~ExclusiveData();
+        new (this) ExclusiveData(mozilla::Move(rhs));
         return *this;
     }
 
     /**
-     * An RAII class that provides exclusive access to a `Mutex<T>`'s protected
-     * inner `T` value.
+     * An RAII class that provides exclusive access to a `ExclusiveData<T>`'s
+     * protected inner `T` value.
      *
      * Note that this is intentionally marked MOZ_STACK_CLASS instead of
      * MOZ_RAII_CLASS, as the latter disallows moves and returning by value, but
      * Guard utilizes both.
      */
     class MOZ_STACK_CLASS Guard
     {
-        const Mutex* parent_;
+        const ExclusiveData* parent_;
 
         Guard(const Guard&) = delete;
         Guard& operator=(const Guard&) = delete;
 
       public:
-        explicit Guard(const Mutex& parent)
+        explicit Guard(const ExclusiveData& parent)
           : parent_(&parent)
         {
             parent_->acquire();
         }
 
         Guard(Guard&& rhs)
           : parent_(rhs.parent_)
         {
@@ -207,9 +209,9 @@ class Mutex : private detail::MutexBase
      */
     Guard lock() const {
         return Guard(*this);
     }
 };
 
 } // namespace js
 
-#endif // js_Mutex_h
+#endif // threading_ExclusiveData_h