зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1783299 - Add support for threadsafe mirrored StaticPref strings. r=KrisWright
Prior to this patch, one would need to manually instantiate a copy of a string from a preference on the main thread in order to access it in a threadsafe manner on another thread. This patch adds support for a `DataMutexString` threadsafe type for mirror: always type StaticPrefs, and works similarly to the existing atomic types. Differential Revision: https://phabricator.services.mozilla.com/D153829
This commit is contained in:
Родитель
7b7c37a440
Коммит
e8f9ed23ec
|
@ -132,6 +132,18 @@ using ipc::FileDescriptor;
|
||||||
|
|
||||||
#endif // DEBUG
|
#endif // DEBUG
|
||||||
|
|
||||||
|
// Forward declarations.
|
||||||
|
namespace mozilla::StaticPrefs {
|
||||||
|
|
||||||
|
static void InitAll();
|
||||||
|
static void StartObservingAlwaysPrefs();
|
||||||
|
static void InitOncePrefs();
|
||||||
|
static void InitStaticPrefsFromShared();
|
||||||
|
static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder);
|
||||||
|
static void ShutdownAlwaysPrefs();
|
||||||
|
|
||||||
|
} // namespace mozilla::StaticPrefs
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
// Low-level types and operations
|
// Low-level types and operations
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
@ -1129,6 +1141,10 @@ class MOZ_STACK_CLASS PrefWrapper : public PrefWrapperBase {
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult GetValue(PrefValueKind aKind, nsACString* aResult) const {
|
||||||
|
return GetValue(aKind, *aResult);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns false if this pref doesn't have a user value worth saving.
|
// Returns false if this pref doesn't have a user value worth saving.
|
||||||
bool UserValueToStringForSaving(nsCString& aStr) {
|
bool UserValueToStringForSaving(nsCString& aStr) {
|
||||||
// Should we save the user value, if present? Only if it does not match the
|
// Should we save the user value, if present? Only if it does not match the
|
||||||
|
@ -3616,6 +3632,7 @@ void Preferences::Shutdown() {
|
||||||
if (!sShutdown) {
|
if (!sShutdown) {
|
||||||
sShutdown = true; // Don't create the singleton instance after here.
|
sShutdown = true; // Don't create the singleton instance after here.
|
||||||
sPreferences = nullptr;
|
sPreferences = nullptr;
|
||||||
|
StaticPrefs::ShutdownAlwaysPrefs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3697,17 +3714,6 @@ void Preferences::DeserializePreferences(char* aStr, size_t aPrefsLen) {
|
||||||
gContentProcessPrefsAreInited = true;
|
gContentProcessPrefsAreInited = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Forward declarations.
|
|
||||||
namespace StaticPrefs {
|
|
||||||
|
|
||||||
static void InitAll();
|
|
||||||
static void StartObservingAlwaysPrefs();
|
|
||||||
static void InitOncePrefs();
|
|
||||||
static void InitStaticPrefsFromShared();
|
|
||||||
static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder);
|
|
||||||
|
|
||||||
} // namespace StaticPrefs
|
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
FileDescriptor Preferences::EnsureSnapshot(size_t* aSize) {
|
FileDescriptor Preferences::EnsureSnapshot(size_t* aSize) {
|
||||||
MOZ_ASSERT(XRE_IsParentProcess());
|
MOZ_ASSERT(XRE_IsParentProcess());
|
||||||
|
@ -4529,6 +4535,9 @@ static nsCString PrefValueToString(const uint32_t* u) {
|
||||||
static nsCString PrefValueToString(const float* f) {
|
static nsCString PrefValueToString(const float* f) {
|
||||||
return nsPrintfCString("%f", *f);
|
return nsPrintfCString("%f", *f);
|
||||||
}
|
}
|
||||||
|
static nsCString PrefValueToString(const nsACString* s) {
|
||||||
|
return nsCString(*s);
|
||||||
|
}
|
||||||
static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); }
|
static nsCString PrefValueToString(const nsACString& s) { return nsCString(s); }
|
||||||
|
|
||||||
// These preference getter wrappers allow us to look up the value for static
|
// These preference getter wrappers allow us to look up the value for static
|
||||||
|
@ -4637,13 +4646,36 @@ struct Internals {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename V>
|
||||||
|
static void MOZ_NEVER_INLINE AssignMirror(T& aMirror, V aValue) {
|
||||||
|
aMirror = aValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MOZ_NEVER_INLINE AssignMirror(DataMutexString& aMirror,
|
||||||
|
nsCString&& aValue) {
|
||||||
|
auto lock = aMirror.Lock();
|
||||||
|
lock->Assign(std::move(aValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MOZ_NEVER_INLINE AssignMirror(DataMutexString& aMirror,
|
||||||
|
const nsLiteralCString& aValue) {
|
||||||
|
auto lock = aMirror.Lock();
|
||||||
|
lock->Assign(aValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ClearMirror(DataMutexString& aMirror) {
|
||||||
|
auto lock = aMirror.Lock();
|
||||||
|
lock->Assign(nsCString());
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void UpdateMirror(const char* aPref, void* aMirror) {
|
static void UpdateMirror(const char* aPref, void* aMirror) {
|
||||||
StripAtomic<T> value;
|
StripAtomic<T> value;
|
||||||
|
|
||||||
nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User);
|
nsresult rv = GetPrefValue(aPref, &value, PrefValueKind::User);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
*static_cast<T*>(aMirror) = value;
|
AssignMirror(*static_cast<T*>(aMirror),
|
||||||
|
std::forward<StripAtomic<T>>(value));
|
||||||
} else {
|
} else {
|
||||||
// GetPrefValue() can fail if the update is caused by the pref being
|
// GetPrefValue() can fail if the update is caused by the pref being
|
||||||
// deleted or if it fails to make a cast. This assertion is the only place
|
// deleted or if it fails to make a cast. This assertion is the only place
|
||||||
|
@ -5433,6 +5465,16 @@ static MOZ_NEVER_INLINE void AddMirror(T* aMirror, const nsACString& aPref,
|
||||||
AddMirrorCallback(aMirror, aPref);
|
AddMirrorCallback(aMirror, aPref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MOZ_NEVER_INLINE void AddMirror(DataMutexString& aMirror,
|
||||||
|
const nsACString& aPref) {
|
||||||
|
auto lock = aMirror.Lock();
|
||||||
|
nsCString result(*lock);
|
||||||
|
Internals::GetPrefValue(PromiseFlatCString(aPref).get(), result,
|
||||||
|
PrefValueKind::User);
|
||||||
|
lock->Assign(std::move(result));
|
||||||
|
AddMirrorCallback(&aMirror, aPref);
|
||||||
|
}
|
||||||
|
|
||||||
// The InitPref_*() functions below end in a `_<type>` suffix because they are
|
// The InitPref_*() functions below end in a `_<type>` suffix because they are
|
||||||
// used by the PREF macro definition in InitAll() below.
|
// used by the PREF macro definition in InitAll() below.
|
||||||
|
|
||||||
|
@ -5511,6 +5553,15 @@ static void InitAlwaysPref(const nsCString& aName, T* aCache,
|
||||||
*aCache = aDefaultValue;
|
*aCache = aDefaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void InitAlwaysPref(const nsCString& aName, DataMutexString& aCache,
|
||||||
|
const nsLiteralCString& aDefaultValue) {
|
||||||
|
// Only called in the parent process. Set/reset the pref value and the
|
||||||
|
// `always` mirror to the default value.
|
||||||
|
// `once` mirrors will be initialized lazily in InitOncePrefs().
|
||||||
|
InitPref_String(aName, aDefaultValue.get());
|
||||||
|
Internals::AssignMirror(aCache, aDefaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
static Atomic<bool> sOncePrefRead(false);
|
static Atomic<bool> sOncePrefRead(false);
|
||||||
static StaticMutex sOncePrefMutex MOZ_UNANNOTATED;
|
static StaticMutex sOncePrefMutex MOZ_UNANNOTATED;
|
||||||
|
|
||||||
|
@ -5538,11 +5589,14 @@ void MaybeInitOncePrefs() {
|
||||||
#define NEVER_PREF(name, cpp_type, value)
|
#define NEVER_PREF(name, cpp_type, value)
|
||||||
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
cpp_type sMirror_##full_id(default_value);
|
cpp_type sMirror_##full_id(default_value);
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
|
cpp_type sMirror_##full_id("DataMutexString");
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
cpp_type sMirror_##full_id(default_value);
|
cpp_type sMirror_##full_id(default_value);
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
|
|
||||||
static void InitAll() {
|
static void InitAll() {
|
||||||
|
@ -5559,11 +5613,14 @@ static void InitAll() {
|
||||||
InitPref_##cpp_type(name ""_ns, value);
|
InitPref_##cpp_type(name ""_ns, value);
|
||||||
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
InitAlwaysPref(name ""_ns, &sMirror_##full_id, value);
|
InitAlwaysPref(name ""_ns, &sMirror_##full_id, value);
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
|
InitAlwaysPref(name ""_ns, sMirror_##full_id, value);
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
InitPref_##cpp_type(name ""_ns, value);
|
InitPref_##cpp_type(name ""_ns, value);
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5577,10 +5634,13 @@ static void StartObservingAlwaysPrefs() {
|
||||||
#define NEVER_PREF(name, cpp_type, value)
|
#define NEVER_PREF(name, cpp_type, value)
|
||||||
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id);
|
AddMirror(&sMirror_##full_id, name ""_ns, sMirror_##full_id);
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
|
AddMirror(sMirror_##full_id, name ""_ns);
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5596,6 +5656,7 @@ static void InitOncePrefs() {
|
||||||
// suggest that it should instead be `always`-mirrored.
|
// suggest that it should instead be `always`-mirrored.
|
||||||
#define NEVER_PREF(name, cpp_type, value)
|
#define NEVER_PREF(name, cpp_type, value)
|
||||||
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
# define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
{ \
|
{ \
|
||||||
|
@ -5624,6 +5685,23 @@ static void InitOncePrefs() {
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
|
#undef ONCE_PREF
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShutdownAlwaysPrefs() {
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
// We may need to do clean up for leak detection for some StaticPrefs.
|
||||||
|
#define NEVER_PREF(name, cpp_type, value)
|
||||||
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
|
Internals::ClearMirror(sMirror_##full_id);
|
||||||
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
|
#undef NEVER_PREF
|
||||||
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5696,12 +5774,14 @@ static void RegisterOncePrefs(SharedPrefMapBuilder& aBuilder) {
|
||||||
// "$$$" prefix and suffix to the preference name.
|
// "$$$" prefix and suffix to the preference name.
|
||||||
#define NEVER_PREF(name, cpp_type, value)
|
#define NEVER_PREF(name, cpp_type, value)
|
||||||
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
|
#define ALWAYS_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, value)
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, value) \
|
||||||
SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name) ""_ns, \
|
SaveOncePrefToSharedMap(aBuilder, ONCE_PREF_NAME(name) ""_ns, \
|
||||||
cpp_type(sMirror_##full_id));
|
cpp_type(sMirror_##full_id));
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5744,6 +5824,20 @@ static void InitStaticPrefsFromShared() {
|
||||||
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name); \
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name); \
|
||||||
StaticPrefs::sMirror_##full_id = val; \
|
StaticPrefs::sMirror_##full_id = val; \
|
||||||
}
|
}
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
|
{ \
|
||||||
|
StripAtomic<cpp_type> val; \
|
||||||
|
if (!XRE_IsParentProcess() && IsString<cpp_type>::value && \
|
||||||
|
gContentProcessPrefsAreInited && sCrashOnBlocklistedPref) { \
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT( \
|
||||||
|
!ShouldSanitizePreference(name, XRE_IsContentProcess()), \
|
||||||
|
"Should not access the preference '" name "' in Content Processes"); \
|
||||||
|
} \
|
||||||
|
DebugOnly<nsresult> rv = Internals::GetSharedPrefValue(name, &val); \
|
||||||
|
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed accessing " name); \
|
||||||
|
Internals::AssignMirror(StaticPrefs::sMirror_##full_id, \
|
||||||
|
std::forward<StripAtomic<cpp_type>>(val)); \
|
||||||
|
}
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
{ \
|
{ \
|
||||||
cpp_type val; \
|
cpp_type val; \
|
||||||
|
@ -5761,6 +5855,7 @@ static void InitStaticPrefsFromShared() {
|
||||||
#include "mozilla/StaticPrefListAll.h"
|
#include "mozilla/StaticPrefListAll.h"
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
|
|
||||||
// `once`-mirrored prefs have been set to their value in the step above and
|
// `once`-mirrored prefs have been set to their value in the step above and
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "mozilla/Atomics.h"
|
#include "mozilla/Atomics.h"
|
||||||
|
#include "mozilla/DataMutex.h"
|
||||||
|
#include "nsString.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
@ -19,12 +21,17 @@ class SharedPrefMapBuilder;
|
||||||
|
|
||||||
typedef const char* String;
|
typedef const char* String;
|
||||||
|
|
||||||
|
using DataMutexString = StaticDataMutex<nsCString>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsString : std::false_type {};
|
struct IsString : std::false_type {};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct IsString<String> : std::true_type {};
|
struct IsString<String> : std::true_type {};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct IsString<DataMutexString> : std::true_type {};
|
||||||
|
|
||||||
typedef Atomic<bool, Relaxed> RelaxedAtomicBool;
|
typedef Atomic<bool, Relaxed> RelaxedAtomicBool;
|
||||||
typedef Atomic<bool, ReleaseAcquire> ReleaseAcquireAtomicBool;
|
typedef Atomic<bool, ReleaseAcquire> ReleaseAcquireAtomicBool;
|
||||||
typedef Atomic<bool, SequentiallyConsistent> SequentiallyConsistentAtomicBool;
|
typedef Atomic<bool, SequentiallyConsistent> SequentiallyConsistentAtomicBool;
|
||||||
|
@ -58,6 +65,11 @@ struct StripAtomicImpl<std::atomic<T>> {
|
||||||
typedef T Type;
|
typedef T Type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct StripAtomicImpl<DataMutexString> {
|
||||||
|
typedef nsCString Type;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using StripAtomic = typename StripAtomicImpl<T>::Type;
|
using StripAtomic = typename StripAtomicImpl<T>::Type;
|
||||||
|
|
||||||
|
|
|
@ -42,10 +42,11 @@
|
||||||
# and JS code).
|
# and JS code).
|
||||||
#
|
#
|
||||||
# - `type` is one of `bool`, `int32_t`, `uint32_t`, `float`, an atomic version
|
# - `type` is one of `bool`, `int32_t`, `uint32_t`, `float`, an atomic version
|
||||||
# of one of those, or `String`. Note that float prefs are stored internally
|
# of one of those, `String` or `DataMutexString`. Note that float prefs are
|
||||||
# as strings. The C++ preprocessor doesn't like template syntax in a macro
|
# stored internally as strings. The C++ preprocessor doesn't like template
|
||||||
# argument, so use the typedefs defined in StaticPrefsBase.h; for example,
|
# syntax in a macro argument, so use the typedefs defined in
|
||||||
# use `RelaxedAtomicBool` instead of `Atomic<bool, Relaxed>`.
|
# StaticPrefsBase.h; for example, use `RelaxedAtomicBool` instead of
|
||||||
|
# `Atomic<bool, Relaxed>`.
|
||||||
#
|
#
|
||||||
# - `value` is the default value. Its type should be appropriate for
|
# - `value` is the default value. Its type should be appropriate for
|
||||||
# <cpp-type>, otherwise the generated code will fail to compile. A complex
|
# <cpp-type>, otherwise the generated code will fail to compile. A complex
|
||||||
|
|
|
@ -37,6 +37,21 @@ namespace StaticPrefs {
|
||||||
inline StripAtomic<cpp_type> GetPrefDefault_##base_id() { \
|
inline StripAtomic<cpp_type> GetPrefDefault_##base_id() { \
|
||||||
return default_value; \
|
return default_value; \
|
||||||
}
|
}
|
||||||
|
#define ALWAYS_DATAMUTEX_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
|
extern cpp_type sMirror_##full_id; \
|
||||||
|
inline cpp_type::ConstAutoLock full_id() { \
|
||||||
|
if (!XRE_IsParentProcess() && IsString<cpp_type>::value && \
|
||||||
|
sCrashOnBlocklistedPref) { \
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT( \
|
||||||
|
!ShouldSanitizePreference(name, XRE_IsContentProcess()), \
|
||||||
|
"Should not access the preference '" name "' in Content Processes"); \
|
||||||
|
} \
|
||||||
|
return sMirror_##full_id.ConstLock(); \
|
||||||
|
} \
|
||||||
|
inline const char* GetPrefName_##base_id() { return name; } \
|
||||||
|
inline StripAtomic<cpp_type> GetPrefDefault_##base_id() { \
|
||||||
|
return default_value; \
|
||||||
|
}
|
||||||
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
#define ONCE_PREF(name, base_id, full_id, cpp_type, default_value) \
|
||||||
extern cpp_type sMirror_##full_id; \
|
extern cpp_type sMirror_##full_id; \
|
||||||
inline cpp_type full_id() { \
|
inline cpp_type full_id() { \
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#undef NEVER_PREF
|
#undef NEVER_PREF
|
||||||
#undef ALWAYS_PREF
|
#undef ALWAYS_PREF
|
||||||
|
#undef ALWAYS_DATAMUTEX_PREF
|
||||||
#undef ONCE_PREF
|
#undef ONCE_PREF
|
||||||
|
|
||||||
} // namespace StaticPrefs
|
} // namespace StaticPrefs
|
||||||
|
|
|
@ -46,6 +46,7 @@ VALID_TYPES.update(
|
||||||
"SequentiallyConsistentAtomicUint32": "uint32_t",
|
"SequentiallyConsistentAtomicUint32": "uint32_t",
|
||||||
"AtomicFloat": "float",
|
"AtomicFloat": "float",
|
||||||
"String": None,
|
"String": None,
|
||||||
|
"DataMutexString": None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -81,6 +82,14 @@ ALWAYS_PREF(
|
||||||
{full_id},
|
{full_id},
|
||||||
{typ}, {value}
|
{typ}, {value}
|
||||||
)
|
)
|
||||||
|
""",
|
||||||
|
"always_datamutex": """\
|
||||||
|
ALWAYS_DATAMUTEX_PREF(
|
||||||
|
"{name}",
|
||||||
|
{base_id},
|
||||||
|
{full_id},
|
||||||
|
{typ}, {value}
|
||||||
|
)
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,11 +174,11 @@ def check_pref_list(pref_list):
|
||||||
if "value" not in pref:
|
if "value" not in pref:
|
||||||
error("missing `value` key for pref `{}`".format(name))
|
error("missing `value` key for pref `{}`".format(name))
|
||||||
value = pref["value"]
|
value = pref["value"]
|
||||||
if typ == "String":
|
if typ == "String" or typ == "DataMutexString":
|
||||||
if type(value) != str:
|
if type(value) != str:
|
||||||
error(
|
error(
|
||||||
"non-string `value` value `{}` for `String` pref `{}`; "
|
"non-string `value` value `{}` for `{}` pref `{}`; "
|
||||||
"add double quotes".format(value, name)
|
"add double quotes".format(value, typ, name)
|
||||||
)
|
)
|
||||||
elif typ in VALID_BOOL_TYPES:
|
elif typ in VALID_BOOL_TYPES:
|
||||||
if value not in (True, False):
|
if value not in (True, False):
|
||||||
|
@ -179,6 +188,8 @@ def check_pref_list(pref_list):
|
||||||
if "mirror" not in pref:
|
if "mirror" not in pref:
|
||||||
error("missing `mirror` key for pref `{}`".format(name))
|
error("missing `mirror` key for pref `{}`".format(name))
|
||||||
mirror = pref["mirror"]
|
mirror = pref["mirror"]
|
||||||
|
if typ.startswith("DataMutex"):
|
||||||
|
mirror += "_datamutex"
|
||||||
if mirror not in MIRROR_TEMPLATES:
|
if mirror not in MIRROR_TEMPLATES:
|
||||||
error("invalid `mirror` value `{}` for pref `{}`".format(mirror, name))
|
error("invalid `mirror` value `{}` for pref `{}`".format(mirror, name))
|
||||||
|
|
||||||
|
@ -261,6 +272,8 @@ def generate_code(pref_list, input_filename):
|
||||||
full_id += "_AtStartup"
|
full_id += "_AtStartup"
|
||||||
if do_not_use_directly:
|
if do_not_use_directly:
|
||||||
full_id += "_DoNotUseDirectly"
|
full_id += "_DoNotUseDirectly"
|
||||||
|
if typ.startswith("DataMutex"):
|
||||||
|
mirror += "_datamutex"
|
||||||
|
|
||||||
group = mk_group(pref)
|
group = mk_group(pref)
|
||||||
|
|
||||||
|
@ -273,6 +286,9 @@ def generate_code(pref_list, input_filename):
|
||||||
if typ == "String":
|
if typ == "String":
|
||||||
# Quote string literals, and escape double-quote chars.
|
# Quote string literals, and escape double-quote chars.
|
||||||
value = '"{}"'.format(value.replace('"', '\\"'))
|
value = '"{}"'.format(value.replace('"', '\\"'))
|
||||||
|
elif typ == "DataMutexString":
|
||||||
|
# Quote string literals, and escape double-quote chars.
|
||||||
|
value = '"{}"_ns'.format(value.replace('"', '\\"'))
|
||||||
elif typ in VALID_BOOL_TYPES:
|
elif typ in VALID_BOOL_TYPES:
|
||||||
# Convert Python bools to C++ bools.
|
# Convert Python bools to C++ bools.
|
||||||
if value is True:
|
if value is True:
|
||||||
|
|
|
@ -69,6 +69,12 @@ good_input = """
|
||||||
mirror: always
|
mirror: always
|
||||||
rust: true
|
rust: true
|
||||||
|
|
||||||
|
# A comment.
|
||||||
|
- name: my.datamutex.string
|
||||||
|
type: DataMutexString
|
||||||
|
value: "foobar" # This string is quoted.
|
||||||
|
mirror: always
|
||||||
|
|
||||||
# YAML+Python interprets `10 + 10 * 20` as a string, and so it is printed
|
# YAML+Python interprets `10 + 10 * 20` as a string, and so it is printed
|
||||||
# unchanged.
|
# unchanged.
|
||||||
- name: my.atomic.int
|
- name: my.atomic.int
|
||||||
|
@ -152,6 +158,13 @@ ALWAYS_PREF(
|
||||||
RelaxedAtomicBool, true
|
RelaxedAtomicBool, true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ALWAYS_DATAMUTEX_PREF(
|
||||||
|
"my.datamutex.string",
|
||||||
|
my_datamutex_string,
|
||||||
|
my_datamutex_string,
|
||||||
|
DataMutexString, "foobar"_ns
|
||||||
|
)
|
||||||
|
|
||||||
ALWAYS_PREF(
|
ALWAYS_PREF(
|
||||||
"my.atomic.int",
|
"my.atomic.int",
|
||||||
my_atomic_int,
|
my_atomic_int,
|
||||||
|
|
|
@ -38,32 +38,33 @@ namespace mozilla {
|
||||||
template <typename T, typename MutexType>
|
template <typename T, typename MutexType>
|
||||||
class DataMutexBase {
|
class DataMutexBase {
|
||||||
public:
|
public:
|
||||||
class MOZ_STACK_CLASS AutoLock {
|
template <typename V>
|
||||||
|
class MOZ_STACK_CLASS AutoLockBase {
|
||||||
public:
|
public:
|
||||||
T* operator->() const& { return &ref(); }
|
V* operator->() const& { return &ref(); }
|
||||||
T* operator->() const&& = delete;
|
V* operator->() const&& = delete;
|
||||||
|
|
||||||
T& operator*() const& { return ref(); }
|
V& operator*() const& { return ref(); }
|
||||||
T& operator*() const&& = delete;
|
V& operator*() const&& = delete;
|
||||||
|
|
||||||
// Like RefPtr, make this act like its underlying raw pointer type
|
// Like RefPtr, make this act like its underlying raw pointer type
|
||||||
// whenever it is used in a context where a raw pointer is expected.
|
// whenever it is used in a context where a raw pointer is expected.
|
||||||
operator T*() const& { return &ref(); }
|
operator V*() const& { return &ref(); }
|
||||||
|
|
||||||
// Like RefPtr, don't allow implicit conversion of temporary to raw pointer.
|
// Like RefPtr, don't allow implicit conversion of temporary to raw pointer.
|
||||||
operator T*() const&& = delete;
|
operator V*() const&& = delete;
|
||||||
|
|
||||||
T& ref() const& {
|
V& ref() const& {
|
||||||
MOZ_ASSERT(mOwner);
|
MOZ_ASSERT(mOwner);
|
||||||
return mOwner->mValue;
|
return mOwner->mValue;
|
||||||
}
|
}
|
||||||
T& ref() const&& = delete;
|
V& ref() const&& = delete;
|
||||||
|
|
||||||
AutoLock(AutoLock&& aOther) : mOwner(aOther.mOwner) {
|
AutoLockBase(AutoLockBase&& aOther) : mOwner(aOther.mOwner) {
|
||||||
aOther.mOwner = nullptr;
|
aOther.mOwner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~AutoLock() {
|
~AutoLockBase() {
|
||||||
if (mOwner) {
|
if (mOwner) {
|
||||||
mOwner->mMutex.Unlock();
|
mOwner->mMutex.Unlock();
|
||||||
mOwner = nullptr;
|
mOwner = nullptr;
|
||||||
|
@ -73,9 +74,9 @@ class DataMutexBase {
|
||||||
private:
|
private:
|
||||||
friend class DataMutexBase;
|
friend class DataMutexBase;
|
||||||
|
|
||||||
AutoLock(const AutoLock& aOther) = delete;
|
AutoLockBase(const AutoLockBase& aOther) = delete;
|
||||||
|
|
||||||
explicit AutoLock(DataMutexBase<T, MutexType>* aDataMutex)
|
explicit AutoLockBase(DataMutexBase<T, MutexType>* aDataMutex)
|
||||||
: mOwner(aDataMutex) {
|
: mOwner(aDataMutex) {
|
||||||
MOZ_ASSERT(!!mOwner);
|
MOZ_ASSERT(!!mOwner);
|
||||||
mOwner->mMutex.Lock();
|
mOwner->mMutex.Lock();
|
||||||
|
@ -84,12 +85,16 @@ class DataMutexBase {
|
||||||
DataMutexBase<T, MutexType>* mOwner;
|
DataMutexBase<T, MutexType>* mOwner;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using AutoLock = AutoLockBase<T>;
|
||||||
|
using ConstAutoLock = AutoLockBase<const T>;
|
||||||
|
|
||||||
explicit DataMutexBase(const char* aName) : mMutex(aName) {}
|
explicit DataMutexBase(const char* aName) : mMutex(aName) {}
|
||||||
|
|
||||||
DataMutexBase(T&& aValue, const char* aName)
|
DataMutexBase(T&& aValue, const char* aName)
|
||||||
: mMutex(aName), mValue(std::move(aValue)) {}
|
: mMutex(aName), mValue(std::move(aValue)) {}
|
||||||
|
|
||||||
AutoLock Lock() { return AutoLock(this); }
|
AutoLock Lock() { return AutoLock(this); }
|
||||||
|
ConstAutoLock ConstLock() { return ConstAutoLock(this); }
|
||||||
|
|
||||||
const MutexType& Mutex() const { return mMutex; }
|
const MutexType& Mutex() const { return mMutex; }
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче