blob: 3471db832e8b599a2e5afd7a393304d3a87e20e9 [file] [log] [blame]
[email protected]399ed422012-12-27 19:58:001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// 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
Hans Wennborg7b533712020-06-22 20:52:278#include "base/check.h"
Lei Zhangf28a4c62021-12-21 01:31:579#include "base/dcheck_is_on.h"
[email protected]399ed422012-12-27 19:58:0010#include "base/sequence_checker_impl.h"
Etienne Pierre-doray841f3e82020-01-14 17:10:2511#include "base/strings/string_piece.h"
[email protected]399ed422012-12-27 19:58:0012
danakj894364e2021-01-27 21:51:2913#if DCHECK_IS_ON()
14#include "base/debug/stack_trace.h"
15#endif
16
gabd52c912a2017-05-11 04:15:5917// SequenceChecker is a helper class used to help verify that some methods of a
Etienne Pierre-doray841f3e82020-01-14 17:10:2518// class are called sequentially (for thread-safety). It supports thread safety
19// annotations (see base/thread_annotations.h).
gabd52c912a2017-05-11 04:15:5920//
21// Use the macros below instead of the SequenceChecker directly so that the
22// unused member doesn't result in an extra byte (four when padded) per
23// instance in production.
24//
25// This class is much prefered to ThreadChecker for thread-safety checks.
26// ThreadChecker should only be used for classes that are truly thread-affine
27// (use thread-local-storage or a third-party API that does).
28//
danakj894364e2021-01-27 21:51:2929// Debugging:
30// If SequenceChecker::EnableStackLogging() is called beforehand, then when
31// SequenceChecker fails, in addition to crashing with a stack trace of where
32// the violation occurred, it will also dump a stack trace of where the
33// checker was bound to a sequence.
34//
gabd52c912a2017-05-11 04:15:5935// Usage:
36// class MyClass {
37// public:
38// MyClass() {
Victor Costane1b5971e2021-01-06 01:35:0839// // Detaching on construction is necessary for objects that are
40// // constructed on one sequence and forever after used from another
gabd52c912a2017-05-11 04:15:5941// // sequence.
42// DETACH_FROM_SEQUENCE(my_sequence_checker_);
43// }
44//
45// ~MyClass() {
46// // SequenceChecker doesn't automatically check it's destroyed on origin
47// // sequence for the same reason it's sometimes detached in the
48// // constructor. It's okay to destroy off sequence if the owner
49// // otherwise knows usage on the associated sequence is done. If you're
50// // not detaching in the constructor, you probably want to explicitly
51// // check in the destructor.
Christian Fremerey177b9b932017-06-02 16:55:0252// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
gabd52c912a2017-05-11 04:15:5953// }
54// void MyMethod() {
55// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
56// ... (do stuff) ...
Etienne Pierre-doray841f3e82020-01-14 17:10:2557// MyOtherMethod();
58// }
59//
60// void MyOtherMethod()
61// VALID_CONTEXT_REQUIRED(my_sequence_checker_) {
62// foo_ = 42;
gabd52c912a2017-05-11 04:15:5963// }
64//
65// private:
Etienne Pierre-doray841f3e82020-01-14 17:10:2566// // GUARDED_BY_CONTEXT() enforces that this member is only
67// // accessed from a scope that invokes DCHECK_CALLED_ON_VALID_SEQUENCE()
68// // or from a function annotated with VALID_CONTEXT_REQUIRED(). A
69// // DCHECK build will not compile if the member is accessed and these
70// // conditions are not met.
71// int foo_ GUARDED_BY_CONTEXT(my_sequence_checker_);
72//
gabd52c912a2017-05-11 04:15:5973// SEQUENCE_CHECKER(my_sequence_checker_);
74// }
75
Etienne Pierre-doray841f3e82020-01-14 17:10:2576#define SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b) a##b
77#define SEQUENCE_CHECKER_INTERNAL_CONCAT(a, b) \
78 SEQUENCE_CHECKER_INTERNAL_CONCAT2(a, b)
79#define SEQUENCE_CHECKER_INTERNAL_UID(prefix) \
80 SEQUENCE_CHECKER_INTERNAL_CONCAT(prefix, __LINE__)
81
gabd52c912a2017-05-11 04:15:5982#if DCHECK_IS_ON()
83#define SEQUENCE_CHECKER(name) base::SequenceChecker name
Etienne Pierre-doray841f3e82020-01-14 17:10:2584#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) \
85 base::ScopedValidateSequenceChecker SEQUENCE_CHECKER_INTERNAL_UID( \
Zhenyao Mo8f19d6a2020-04-14 10:47:3086 scoped_validate_sequence_checker_)(name, ##__VA_ARGS__)
gabd52c912a2017-05-11 04:15:5987#define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence()
88#else // DCHECK_IS_ON()
Nico Weber140566b12020-06-20 08:29:1889// A no-op expansion that can be followed by a semicolon at class level.
Nico Weberdcacb332019-03-09 02:32:0290#define SEQUENCE_CHECKER(name) static_assert(true, "")
Hans Wennborg7b533712020-06-22 20:52:2791#define DCHECK_CALLED_ON_VALID_SEQUENCE(name, ...) EAT_CHECK_STREAM_PARAMS()
gabd52c912a2017-05-11 04:15:5992#define DETACH_FROM_SEQUENCE(name)
93#endif // DCHECK_IS_ON()
94
[email protected]399ed422012-12-27 19:58:0095namespace base {
96
[email protected]399ed422012-12-27 19:58:0097// Do nothing implementation, for use in release mode.
98//
gabd52c912a2017-05-11 04:15:5999// Note: You should almost always use the SequenceChecker class (through the
100// above macros) to get the right version for your build configuration.
Etienne Pierre-dorayf19e5742020-12-09 00:47:43101// Note: This is marked with "context" capability in order to support
102// thread_annotations.h.
103class THREAD_ANNOTATION_ATTRIBUTE__(capability("context"))
104 SequenceCheckerDoNothing {
[email protected]399ed422012-12-27 19:58:00105 public:
danakj894364e2021-01-27 21:51:29106 static void EnableStackLogging() {}
107
tzikc342ef572017-07-21 08:09:50108 SequenceCheckerDoNothing() = default;
Gabriel Charette9746ffce2019-07-30 20:27:17109
110 // Moving between matching sequences is allowed to help classes with
111 // SequenceCheckers that want a default move-construct/assign.
112 SequenceCheckerDoNothing(SequenceCheckerDoNothing&& other) = default;
113 SequenceCheckerDoNothing& operator=(SequenceCheckerDoNothing&& other) =
114 default;
David Bienvenu5f4d4f02020-09-27 16:55:03115 SequenceCheckerDoNothing(const SequenceCheckerDoNothing&) = delete;
116 SequenceCheckerDoNothing& operator=(const SequenceCheckerDoNothing&) = delete;
Gabriel Charette9746ffce2019-07-30 20:27:17117
danakj894364e2021-01-27 21:51:29118 bool CalledOnValidSequence(void* = nullptr) const WARN_UNUSED_RESULT {
119 return true;
120 }
[email protected]d52426c2013-07-30 19:26:40121 void DetachFromSequence() {}
[email protected]399ed422012-12-27 19:58:00122};
123
gab190f7542016-08-01 20:03:41124#if DCHECK_IS_ON()
Etienne Pierre-dorayf19e5742020-12-09 00:47:43125using SequenceChecker = SequenceCheckerImpl;
[email protected]399ed422012-12-27 19:58:00126#else
Etienne Pierre-dorayf19e5742020-12-09 00:47:43127using SequenceChecker = SequenceCheckerDoNothing;
gab190f7542016-08-01 20:03:41128#endif // DCHECK_IS_ON()
[email protected]399ed422012-12-27 19:58:00129
danakj894364e2021-01-27 21:51:29130#if DCHECK_IS_ON()
Etienne Pierre-doray841f3e82020-01-14 17:10:25131class SCOPED_LOCKABLE ScopedValidateSequenceChecker {
132 public:
133 explicit ScopedValidateSequenceChecker(const SequenceChecker& checker)
134 EXCLUSIVE_LOCK_FUNCTION(checker) {
danakj894364e2021-01-27 21:51:29135 std::unique_ptr<debug::StackTrace> bound_at;
136 DCHECK(checker.CalledOnValidSequence(&bound_at))
137 << (bound_at ? "\nWas attached to sequence at:\n" + bound_at->ToString()
138 : "");
Etienne Pierre-doray841f3e82020-01-14 17:10:25139 }
140
Etienne Pierre-doray841f3e82020-01-14 17:10:25141 ~ScopedValidateSequenceChecker() UNLOCK_FUNCTION() {}
142
143 private:
144};
danakj894364e2021-01-27 21:51:29145#endif
Etienne Pierre-doray841f3e82020-01-14 17:10:25146
[email protected]399ed422012-12-27 19:58:00147} // namespace base
148
149#endif // BASE_SEQUENCE_CHECKER_H_