Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/toolkit/modules/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 10.2.2025 mit Größe 18 kB image not shown  

Quelle  ProtectedData.h   Sprache: 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 threading_ProtectedData_h
#define threading_ProtectedData_h

#include "mozilla/Atomics.h"
#include "jstypes.h"
#include "threading/ThreadId.h"

struct JS_PUBLIC_API JSContext;

namespace js {

class Mutex;

// This file provides classes for encapsulating pieces of data with a check
// that ensures the data is only accessed if certain conditions are met.
// Checking is only done in debug builds; in release builds these classes
// have no space or time overhead. These classes are mainly used for ensuring
// that data is used in threadsafe ways.
//
// ProtectedData does not by itself ensure that data is threadsafe: it only
// documents and checks synchronization constraints that need to be established
// by the code using the data. If a mutex can be created and directly
// associated with the data, consider using the ExclusiveData class instead.
// Otherwise, ProtectedData should be used to document whatever synchronization
// method is used.

// Protected data checks are enabled in debug builds, except on android where
// they cause some permatimeouts in automation.
#if defined(DEBUG) && !defined(ANDROID)
#  define JS_HAS_PROTECTED_DATA_CHECKS
#endif

#define DECLARE_ONE_BOOL_OPERATOR(OP, T)     \
  template <typename U>                      \
  bool operator OP(const U& other) const {   \
    if constexpr (std::is_integral_v<T>) {   \
      return ref() OP static_cast<T>(other); \
    } else {                                 \
      return ref() OP other;                 \
    }                                        \
  }

#define DECLARE_BOOL_OPERATORS(T)  \
  DECLARE_ONE_BOOL_OPERATOR(==, T) \
  DECLARE_ONE_BOOL_OPERATOR(!=, T) \
  DECLARE_ONE_BOOL_OPERATOR(<=, T) \
  DECLARE_ONE_BOOL_OPERATOR(>=, T) \
  DECLARE_ONE_BOOL_OPERATOR(<, T)  \
  DECLARE_ONE_BOOL_OPERATOR(>, T)

// Mark a region of code that should be treated as single threaded and suppress
// any ProtectedData checks.
//
// Note that in practice there may be multiple threads running when this class
// is used, due to the presence of multiple runtimes in the process. When each
// process has only a single runtime this will no longer be a concern.
class MOZ_RAII AutoNoteSingleThreadedRegion {
 public:
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  static mozilla::Atomic<size_t, mozilla::SequentiallyConsistent> count;
  AutoNoteSingleThreadedRegion() { count++; }
  ~AutoNoteSingleThreadedRegion() { count--; }
#else
  AutoNoteSingleThreadedRegion() {}
#endif
};

// Class for protected data that may be written to any number of times. Checks
// occur when the data is both read from and written to.
template <typename Check, typename T>
class ProtectedData {
  using ThisType = ProtectedData<Check, T>;

 public:
  template <typename... Args>
  explicit ProtectedData(const Check& check, Args&&... args)
      : value(std::forward<Args>(args)...)
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
        ,
        check(check)
#endif
  {
  }

  DECLARE_BOOL_OPERATORS(T)

  operator const T&() const { return ref(); }
  const T& operator->() const { return ref(); }

  template <typename U>
  ThisType& operator=(const U& p) {
    this->ref() = p;
    return *this;
  }

  template <typename U>
  ThisType& operator=(U&& p) {
    this->ref() = std::move(p);
    return *this;
  }

  template <typename U>
  T& operator+=(const U& rhs) {
    return ref() += rhs;
  }
  template <typename U>
  T& operator-=(const U& rhs) {
    return ref() -= rhs;
  }
  template <typename U>
  T& operator*=(const U& rhs) {
    return ref() *= rhs;
  }
  template <typename U>
  T& operator/=(const U& rhs) {
    return ref() /= rhs;
  }
  template <typename U>
  T& operator&=(const U& rhs) {
    return ref() &= rhs;
  }
  template <typename U>
  T& operator|=(const U& rhs) {
    return ref() |= rhs;
  }
  T& operator++() { return ++ref(); }
  T& operator--() { return --ref(); }
  T operator++(int) { return ref()++; }
  T operator--(int) { return ref()--; }

  T& ref() {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
    if (!AutoNoteSingleThreadedRegion::count) {
      check.check();
    }
#endif
    return value;
  }

  const T& ref() const {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
    if (!AutoNoteSingleThreadedRegion::count) {
      check.check();
    }
#endif
    return value;
  }

  T& refNoCheck() { return value; }
  const T& refNoCheck() const { return value; }

  static size_t offsetOfValue() { return offsetof(ThisType, value); }

 private:
  T value;
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  Check check;
#endif
};

// Intermediate class for protected data whose checks take no constructor
// arguments.
template <typename Check, typename T>
class ProtectedDataNoCheckArgs : public ProtectedData<Check, T> {
  using Base = ProtectedData<Check, T>;

 public:
  template <typename... Args>
  explicit ProtectedDataNoCheckArgs(Args&&... args)
      : ProtectedData<Check, T>(Check(), std::forward<Args>(args)...) {}

  using Base::operator=;
};

// Intermediate class for protected data whose checks take a single argument.
template <typename CheckArg, typename Check, typename T>
class ProtectedDataWithArg : public ProtectedData<Check, T> {
  using Base = ProtectedData<Check, T>;

 public:
  template <typename... Args>
  explicit ProtectedDataWithArg(CheckArg checkArg, Args&&... args)
      : ProtectedData<Check, T>(Check(checkArg), std::forward<Args>(args)...) {}

  using Base::operator=;
};

template <typename Check, typename T>
using ProtectedDataContextArg = ProtectedDataWithArg<JSContext*, Check, T>;

template <typename Check, typename T>
using ProtectedDataMutexArg = ProtectedDataWithArg<const Mutex&, Check, T>;

class CheckUnprotected {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
 public:
  inline void check() const {}
#endif
};

// Data with a no-op check that permits all accesses. This is tantamount to not
// using ProtectedData at all, but is in place to document points which need
// to be fixed in order for runtimes to be multithreaded (see bug 1323066).
template <typename T>
using UnprotectedData = ProtectedDataNoCheckArgs<CheckUnprotected, T>;

class CheckThreadLocal {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  ThreadId id;

 public:
  CheckThreadLocal() : id(ThreadId::ThisThreadId()) {}

  void check() const;
#endif
};

class CheckContextLocal {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  JSContext* cx_;

 public:
  explicit CheckContextLocal(JSContext* cx) : cx_(cx) {}

  void check() const;
#else
 public:
  explicit CheckContextLocal(JSContext* cx) {}
#endif
};

class CheckMutexHeld {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  const Mutex& mutex_;

 public:
  explicit CheckMutexHeld(const Mutex& mutex) : mutex_(mutex) {}

  void check() const;
#else
 public:
  explicit CheckMutexHeld(const Mutex& mutex) {}
#endif
};

// Data which may only be accessed by the thread on which it is created.
template <typename T>
using ThreadData = ProtectedDataNoCheckArgs<CheckThreadLocal, T>;

// Data which belongs to a JSContext and should only be accessed from that
// JSContext's thread. Note that a JSContext may not have a thread currently
// associated with it and any associated thread may change over time.
template <typename T>
using ContextData = ProtectedDataContextArg<CheckContextLocal, T>;

template <typename T>
using MutexData = ProtectedDataMutexArg<CheckMutexHeld, T>;

// Enum describing which helper threads (GC tasks or Ion compilations) may
// access data.
enum class AllowedHelperThread {
  None,
  GCTask,
  IonCompile,
  GCTaskOrIonCompile,
};

template <AllowedHelperThread Helper>
class CheckMainThread {
 public:
  void check() const;
};

// Data which may only be accessed by the runtime's main thread.
template <typename T>
using MainThreadData =
    ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::None>, T>;

// Data which may only be accessed by the runtime's main thread or by various
// helper thread tasks.
template <typename T>
using MainThreadOrGCTaskData =
    ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::GCTask>, T>;
template <typename T>
using MainThreadOrIonCompileData =
    ProtectedDataNoCheckArgs<CheckMainThread<AllowedHelperThread::IonCompile>,
                             T>;
template <typename T>
using MainThreadOrGCTaskOrIonCompileData = ProtectedDataNoCheckArgs<
    CheckMainThread<AllowedHelperThread::GCTaskOrIonCompile>, T>;

// Runtime wide locks which might protect some data.
enum class GlobalLock { GCLock, HelperThreadLock };

template <GlobalLock Lock, AllowedHelperThread Helper>
class CheckGlobalLock {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
 public:
  void check() const;
#endif
};

// Data which may only be accessed while holding the GC lock.
template <typename T>
using GCLockData = ProtectedDataNoCheckArgs<
    CheckGlobalLock<GlobalLock::GCLock, AllowedHelperThread::None>, T>;

// Data which may only be accessed while holding the helper thread lock.
template <typename T>
using HelperThreadLockData = ProtectedDataNoCheckArgs<
    CheckGlobalLock<GlobalLock::HelperThreadLock, AllowedHelperThread::None>,
    T>;

// Class for protected data that is only written to once. 'const' may sometimes
// be usable instead of this class, but in cases where the data cannot be set
// to its final value in its constructor this class is helpful. Protected data
// checking only occurs when writes are performed, not reads. Steps may need to
// be taken to ensure that reads do not occur until the written value is fully
// initialized, as such guarantees are not provided by this class.
template <typename Check, typename T>
class ProtectedDataWriteOnce {
  using ThisType = ProtectedDataWriteOnce<Check, T>;

 public:
  template <typename... Args>
  explicit ProtectedDataWriteOnce(Args&&... args)
      : value(std::forward<Args>(args)...)
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
        ,
        nwrites(0)
#endif
  {
  }

  DECLARE_BOOL_OPERATORS(T)

  operator const T&() const { return ref(); }
  const T& operator->() const { return ref(); }

  template <typename U>
  ThisType& operator=(const U& p) {
    if (ref() != p) {
      this->writeRef() = p;
    }
    return *this;
  }

  const T& ref() const { return value; }

  T& writeRef() {
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
    if (!AutoNoteSingleThreadedRegion::count) {
      check.check();
    }
    // Despite the WriteOnce name, actually allow two writes to accommodate
    // data that is cleared during teardown.
    MOZ_ASSERT(++nwrites <= 2);
#endif
    return value;
  }

 private:
  T value;
#ifdef JS_HAS_PROTECTED_DATA_CHECKS
  Check check;
  size_t nwrites;
#endif
};

// Data that is written once with no requirements for exclusive access when
// that write occurs.
template <typename T>
using WriteOnceData = ProtectedDataWriteOnce<CheckUnprotected, T>;

#undef DECLARE_ASSIGNMENT_OPERATOR
#undef DECLARE_ONE_BOOL_OPERATOR
#undef DECLARE_BOOL_OPERATORS

}  // namespace js

#endif  // threading_ProtectedData_h

92%


¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.