gecko-dev/xpcom/threads/DataMutex.h

101 строка
2.6 KiB
C++

/* -*- 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"
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>
class DataMutex {
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 DataMutex;
AutoLock(const AutoLock& aOther) = delete;
explicit AutoLock(DataMutex<T>* aDataMutex) : mOwner(aDataMutex) {
MOZ_ASSERT(!!mOwner);
mOwner->mMutex.Lock();
}
DataMutex<T>* mOwner;
};
public:
explicit DataMutex(const char* aName) : mMutex(aName) {}
DataMutex(T&& aValue, const char* aName)
: mMutex(aName), mValue(std::move(aValue)) {}
AutoLock Lock() { return AutoLock(this); }
private:
Mutex mMutex;
T mValue;
};
} // namespace mozilla
#endif // DataMutex_h__