DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (ae8d2f148d7d)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 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/. */

#ifndef DataMutex_h__
#define DataMutex_h__

#include <utility>
#include "mozilla/Mutex.h"
#include "mozilla/StaticMutex.h"

namespace mozilla {

// A template to wrap a type with a mutex so that accesses to the type's
// data are required to take the lock before accessing it. This ensures
// that a mutex is explicitly associated with the data that it protects,
// and makes it impossible to access the data without first taking the
// associated mutex.
//
// This is based on Rust's std::sync::Mutex, which operates under the
// strategy of locking data, rather than code.
//
// Examples:
//
//    DataMutex<uint32_t> u32DataMutex(1, "u32DataMutex");
//    auto x = u32DataMutex.Lock();
//    *x = 4;
//    assert(*x, 4u);
//
//    DataMutex<nsTArray<uint32_t>> arrayDataMutex("arrayDataMutex");
//    auto a = arrayDataMutex.Lock();
//    auto& x = a.ref();
//    x.AppendElement(1u);
//    assert(x[0], 1u);
//
template <typename T, typename MutexType>
class DataMutexBase {
 private:
  class MOZ_STACK_CLASS AutoLock {
   public:
    T* operator->() const& { return &ref(); }
    T* operator->() const&& = delete;

    T& operator*() const& { return ref(); }
    T& operator*() const&& = delete;

    // Like RefPtr, make this act like its underlying raw pointer type
    // whenever it is used in a context where a raw pointer is expected.
    operator T*() const& { return &ref(); }

    // Like RefPtr, don't allow implicit conversion of temporary to raw pointer.
    operator T*() const&& = delete;

    T& ref() const& {
      MOZ_ASSERT(mOwner);
      return mOwner->mValue;
    }
    T& ref() const&& = delete;

    AutoLock(AutoLock&& aOther) : mOwner(aOther.mOwner) {
      aOther.mOwner = nullptr;
    }

    ~AutoLock() {
      if (mOwner) {
        mOwner->mMutex.Unlock();
        mOwner = nullptr;
      }
    }

   private:
    friend class DataMutexBase;

    AutoLock(const AutoLock& aOther) = delete;

    explicit AutoLock(DataMutexBase<T, MutexType>* aDataMutex)
        : mOwner(aDataMutex) {
      MOZ_ASSERT(!!mOwner);
      mOwner->mMutex.Lock();
    }

    DataMutexBase<T, MutexType>* mOwner;
  };

 public:
  explicit DataMutexBase(const char* aName) : mMutex(aName) {}

  DataMutexBase(T&& aValue, const char* aName)
      : mMutex(aName), mValue(std::move(aValue)) {}

  AutoLock Lock() { return AutoLock(this); }

 private:
  MutexType mMutex;
  T mValue;
};

// Craft a version of StaticMutex that takes a const char* in its ctor.
// We need this so it works interchangeably with Mutex which requires a const
// char* aName in its ctor.
class StaticMutexNameless : public StaticMutexNotRecorded {
 public:
  explicit StaticMutexNameless(const char* aName) : StaticMutexNotRecorded() {}

 private:
  // Disallow copy construction, `=`, `new`, and `delete` like BaseStaticMutex.
#ifdef DEBUG
  StaticMutexNameless(StaticMutexNameless& aOther);
#endif  // DEBUG
  StaticMutexNameless& operator=(StaticMutexNameless* aRhs);
  static void* operator new(size_t) noexcept(true);
  static void operator delete(void*);
};

template <typename T>
using DataMutex = DataMutexBase<T, Mutex>;
template <typename T>
using StaticDataMutex = DataMutexBase<T, StaticMutexNameless>;

}  // namespace mozilla

#endif  // DataMutex_h__