1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef XPCOM_THREADS_EVENTTARGETCAPABILITY_H_
8 #define XPCOM_THREADS_EVENTTARGETCAPABILITY_H_
10 #include "mozilla/ThreadSafety.h"
11 #include "nsIEventTarget.h"
15 // A helper to ensure that data access and function usage only take place on a
16 // specific nsIEventTarget.
18 // This class works with Clang's thread safety analysis so that static analysis
19 // can ensure AssertOnCurrentThread is called before using guarded data and
22 // This means using the class is similar to calling
23 // `MOZ_ASSERT(mTarget->IsOnCurrentThread())`
24 // prior to accessing things we expect to be on `mTarget`. However, using this
25 // helper has the added benefit that static analysis will warn you if you
26 // fail to assert prior to usage.
28 // The following is a basic example of a class using this to ensure
29 // a data member is only accessed on a specific target.
31 // class SomeMediaHandlerThing {
33 // SomeMediaHandlerThing(nsIEventTarget* aTarget) : mTargetCapability(aTarget)
36 // void UpdateMediaState() {
37 // mTargetCapability.Dispatch(
38 // NS_NewRunnableFunction("UpdateMediaState", [this] {
39 // mTargetCapability.AssertOnCurrentThread();
40 // IncreaseMediaCount();
45 // void IncreaseMediaCount() MOZ_REQUIRES(mTargetCapability) { mMediaCount +=
48 // uint32_t mMediaCount MOZ_GUARDED_BY(mTargetCapability) = 0;
49 // EventTargetCapability<nsIEventTarget> mTargetCapability;
52 // NOTE: If you need a thread-safety capability for specifically the main
53 // thread, the static `mozilla::sMainThreadCapability` capability exists, and
54 // can be asserted using `AssertIsOnMainThread()`.
57 class MOZ_CAPABILITY("event target") EventTargetCapability final
{
58 static_assert(std::is_base_of_v
<nsIEventTarget
, T
>,
59 "T must derive from nsIEventTarget");
62 explicit EventTargetCapability(T
* aTarget
) : mTarget(aTarget
) {
63 MOZ_ASSERT(mTarget
, "mTarget should be non-null");
65 ~EventTargetCapability() = default;
67 EventTargetCapability(const EventTargetCapability
&) = default;
68 EventTargetCapability(EventTargetCapability
&&) = default;
69 EventTargetCapability
& operator=(const EventTargetCapability
&) = default;
70 EventTargetCapability
& operator=(EventTargetCapability
&&) = default;
72 void AssertOnCurrentThread() const MOZ_ASSERT_CAPABILITY(this) {
73 MOZ_ASSERT(IsOnCurrentThread());
76 // Allow users to check if we're on the same thread as the event target.
77 bool IsOnCurrentThread() const { return mTarget
->IsOnCurrentThread(); }
79 // Allow users to get the event target, so classes don't have to store the
80 // target as a separate member to use it.
81 T
* GetEventTarget() const { return mTarget
; }
83 // Helper to simplify dispatching to mTarget.
84 nsresult
Dispatch(already_AddRefed
<nsIRunnable
> aRunnable
,
85 uint32_t aFlags
= NS_DISPATCH_NORMAL
) const {
86 return mTarget
->Dispatch(std::move(aRunnable
), aFlags
);
93 } // namespace mozilla
95 #endif // XPCOM_THREADS_EVENTTARGETCAPABILITY_H_