blob: 406854e12f4a7d23c987187572a7d3088c53a3d1 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2012 The Chromium Authors
[email protected]399ed422012-12-27 19:58:002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_SEQUENCE_CHECKER_H_
6#define BASE_SEQUENCE_CHECKER_H_
7
Lei Zhangb9e7c4b82021-12-21 17:56:058#include "base/base_export.h"
Lei Zhangf28a4c62021-12-21 01:31:579#include "base/dcheck_is_on.h"
Peter Kasting71f64d72023-08-03 20:41:3010#include "base/macros/uniquify.h"
[email protected]399ed422012-12-27 19:58:0011#include "base/sequence_checker_impl.h"
[email protected]399ed422012-12-27 19:58:0012
François Doray62cb8e92024-06-05 14:49:0213// SequenceChecker verifies mutual exclusion between calls to its
14// `CalledOnValidSequence()` method. Mutual exclusion is guaranteed if all calls
15// are made from the same thread, from the same sequence (see
François Doray6671c402024-06-21 17:47:3916// `SequencedTaskRunner`) or under the same lock acquired with
17// `base::subtle::LockTracking::kEnabled`. SequenceChecker supports thread
18// safety annotations (see base/thread_annotations.h).
gabd52c912a2017-05-11 04:15:5919//
20// Use the macros below instead of the SequenceChecker directly so that the
François Doray62cb8e92024-06-05 14:49:0221// unused member doesn't result in an extra byte (four when padded) per instance
22// in production.
gabd52c912a2017-05-11 04:15:5923//
24// This class is much prefered to ThreadChecker for thread-safety checks.
25// ThreadChecker should only be used for classes that are truly thread-affine
26// (use thread-local-storage or a third-party API that does).
27//
danakj894364e2021-01-27 21:51:2928// Debugging:
29// If SequenceChecker::EnableStackLogging() is called beforehand, then when
30// SequenceChecker fails, in addition to crashing with a stack trace of where
31// the violation occurred, it will also dump a stack trace of where the
32// checker was bound to a sequence.
33//
gabd52c912a2017-05-11 04:15:5934// Usage:
35// class MyClass {
36// public:
37// MyClass() {
Victor Costane1b5971e2021-01-06 01:35:0838// // Detaching on construction is necessary for objects that are
39// // constructed on one sequence and forever after used from another
gabd52c912a2017-05-11 04:15:5940// // sequence.
François Doray62cb8e92024-06-05 14:49:0241// DETACH_FROM_SEQUENCE(sequence_checker_);
gabd52c912a2017-05-11 04:15:5942// }
43//
44// ~MyClass() {
45// // SequenceChecker doesn't automatically check it's destroyed on origin
46// // sequence for the same reason it's sometimes detached in the
47// // constructor. It's okay to destroy off sequence if the owner
48// // otherwise knows usage on the associated sequence is done. If you're
49// // not detaching in the constructor, you probably want to explicitly
50// // check in the destructor.
François Doray62cb8e92024-06-05 14:49:0251// DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gabd52c912a2017-05-11 04:15:5952// }
53// void MyMethod() {
François Doray62cb8e92024-06-05 14:49:0254// DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
gabd52c912a2017-05-11 04:15:5955// ... (do stuff) ...
Etienne Pierre-doray841f3e82020-01-14 17:10:2556// MyOtherMethod();
57// }
58//
François Doray62cb8e92024-06-05 14:49:0259// void MyOtherMethod() VALID_CONTEXT_REQUIRED(sequence_checker_) {
Etienne Pierre-doray841f3e82020-01-14 17:10:2560// foo_ = 42;
gabd52c912a2017-05-11 04:15:5961// }
62//
63// private:
Etienne Pierre-doray841f3e82020-01-14 17:10:2564// // GUARDED_BY_CONTEXT() enforces that this member is only
65// // accessed from a scope that invokes DCHECK_CALLED_ON_VALID_SEQUENCE()
66// // or from a function annotated with VALID_CONTEXT_REQUIRED(). A
67// // DCHECK build will not compile if the member is accessed and these
68// // conditions are not met.
François Doray62cb8e92024-06-05 14:49:0269// int foo_ GUARDED_BY_CONTEXT(sequence_checker_);
Etienne Pierre-doray841f3e82020-01-14 17:10:2570//
François Doray62cb8e92024-06-05 14:49:0271// SEQUENCE_CHECKER(sequence_checker_);
gabd52c912a2017-05-11 04:15:5972// }
73
74#if DCHECK_IS_ON()
75#define SEQUENCE_CHECKER(name) base::SequenceChecker name
Peter Kasting71f64d72023-08-03 20:41:3076#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) \
77 base::ScopedValidateSequenceChecker BASE_UNIQUIFY( \
Zhenyao Mo8f19d6a2020-04-14 10:47:3078 scoped_validate_sequence_checker_)(name, ##__VA_ARGS__)
gabd52c912a2017-05-11 04:15:5979#define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence()
80#else // DCHECK_IS_ON()
Nico Weber140566b12020-06-20 08:29:1881// A no-op expansion that can be followed by a semicolon at class level.
Nico Weberdcacb332019-03-09 02:32:0282#define SEQUENCE_CHECKER(name) static_assert(true, "")
Hans Wennborg7b533712020-06-22 20:52:2783#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) EAT_CHECK_STREAM_PARAMS()
gabd52c912a2017-05-11 04:15:5984#define DETACH_FROM_SEQUENCE(name)
85#endif // DCHECK_IS_ON()
86
[email protected]399ed422012-12-27 19:58:0087namespace base {
88
[email protected]399ed422012-12-27 19:58:0089// Do nothing implementation, for use in release mode.
90//
gabd52c912a2017-05-11 04:15:5991// Note: You should almost always use the SequenceChecker class (through the
92// above macros) to get the right version for your build configuration.
Etienne Pierre-dorayf19e5742020-12-09 00:47:4393// Note: This is marked with "context" capability in order to support
94// thread_annotations.h.
95class THREAD_ANNOTATION_ATTRIBUTE__(capability("context"))
96 SequenceCheckerDoNothing {
[email protected]399ed422012-12-27 19:58:0097 public:
danakj894364e2021-01-27 21:51:2998 static void EnableStackLogging() {}
99
tzikc342ef572017-07-21 08:09:50100 SequenceCheckerDoNothing() = default;
Gabriel Charette9746ffce2019-07-30 20:27:17101
102 // Moving between matching sequences is allowed to help classes with
103 // SequenceCheckers that want a default move-construct/assign.
104 SequenceCheckerDoNothing(SequenceCheckerDoNothing&& other) = default;
105 SequenceCheckerDoNothing& operator=(SequenceCheckerDoNothing&& other) =
106 default;
David Bienvenu5f4d4f02020-09-27 16:55:03107 SequenceCheckerDoNothing(const SequenceCheckerDoNothing&) = delete;
108 SequenceCheckerDoNothing& operator=(const SequenceCheckerDoNothing&) = delete;
Gabriel Charette9746ffce2019-07-30 20:27:17109
Daniel Cheng4455c9842022-01-13 23:26:37110 [[nodiscard]] bool CalledOnValidSequence(void* = nullptr) const {
danakj894364e2021-01-27 21:51:29111 return true;
112 }
[email protected]d52426c2013-07-30 19:26:40113 void DetachFromSequence() {}
[email protected]399ed422012-12-27 19:58:00114};
115
gab190f7542016-08-01 20:03:41116#if DCHECK_IS_ON()
Etienne Pierre-dorayf19e5742020-12-09 00:47:43117using SequenceChecker = SequenceCheckerImpl;
[email protected]399ed422012-12-27 19:58:00118#else
Etienne Pierre-dorayf19e5742020-12-09 00:47:43119using SequenceChecker = SequenceCheckerDoNothing;
gab190f7542016-08-01 20:03:41120#endif // DCHECK_IS_ON()
[email protected]399ed422012-12-27 19:58:00121
danakj894364e2021-01-27 21:51:29122#if DCHECK_IS_ON()
Lei Zhangb9e7c4b82021-12-21 17:56:05