Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 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_IMPL_H_ |
| 6 | #define BASE_SEQUENCE_CHECKER_IMPL_H_ |
| 7 | |
François Doray | 62cb8e9 | 2024-06-05 14:49:02 | [diff] [blame] | 8 | #include <cstdint> |
tzik | 0c2fcf5 | 2017-02-16 08:52:31 | [diff] [blame] | 9 | #include <memory> |
François Doray | 62cb8e9 | 2024-06-05 14:49:02 | [diff] [blame] | 10 | #include <vector> |
tzik | 0c2fcf5 | 2017-02-16 08:52:31 | [diff] [blame] | 11 | |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 12 | #include "base/base_export.h" |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 13 | #include "base/sequence_token.h" |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 14 | #include "base/synchronization/lock.h" |
Aditya Keerthi | d2f44c7 | 2019-04-26 17:45:14 | [diff] [blame] | 15 | #include "base/thread_annotations.h" |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 16 | #include "base/threading/platform_thread_ref.h" |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 17 | |
| 18 | namespace base { |
danakj | 894364e | 2021-01-27 21:51:29 | [diff] [blame] | 19 | namespace debug { |
| 20 | class StackTrace; |
| 21 | } |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 22 | |
François Doray | 62cb8e9 | 2024-06-05 14:49:02 | [diff] [blame] | 23 | // Real implementation of SequenceChecker. |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 24 | // |
François Doray | 62cb8e9 | 2024-06-05 14:49:02 | [diff] [blame] | 25 | // In most cases, SEQUENCE_CHECKER should be used instead of this, get the right |
| 26 | // implementation for the build configuration. It's possible to temporarily use |
| 27 | // this directly to get sequence checking in production builds, which can be |
| 28 | // handy to debug issues only seen in the field. However, when used in a |
| 29 | // non-DCHECK build, SequenceCheckerImpl::CalledOnValidSequence() will not |
| 30 | // consider locks as a valid way to guarantee mutual exclusion (returns false if |
| 31 | // not invoked from the bound sequence, even if all calls are made under the |
| 32 | // same lock). |
| 33 | |
| 34 | // Marked with "context" capability to support thread_annotations.h. |
Etienne Pierre-doray | f19e574 | 2020-12-09 00:47:43 | [diff] [blame] | 35 | class THREAD_ANNOTATION_ATTRIBUTE__(capability("context")) |
| 36 | BASE_EXPORT SequenceCheckerImpl { |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 37 | public: |
danakj | 894364e | 2021-01-27 21:51:29 | [diff] [blame] | 38 | static void EnableStackLogging(); |
| 39 | |
[email protected] | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 40 | SequenceCheckerImpl(); |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 41 | |
Gabriel Charette | 9746ffce | 2019-07-30 20:27:17 | [diff] [blame] | 42 | // Allow move construct/assign. This must be called on |other|'s associated |
| 43 | // sequence and assignment can only be made into a SequenceCheckerImpl which |
| 44 | // is detached or already associated with the current sequence. This isn't |
| 45 | // thread-safe (|this| and |other| shouldn't be in use while this move is |
| 46 | // performed). If the assignment was legal, the resulting SequenceCheckerImpl |
| 47 | // will be bound to the current sequence and |other| will be detached. |
| 48 | SequenceCheckerImpl(SequenceCheckerImpl&& other); |
| 49 | SequenceCheckerImpl& operator=(SequenceCheckerImpl&& other); |
David Bienvenu | 5f4d4f0 | 2020-09-27 16:55:03 | [diff] [blame] | 50 | SequenceCheckerImpl(const SequenceCheckerImpl&) = delete; |
| 51 | SequenceCheckerImpl& operator=(const SequenceCheckerImpl&) = delete; |
| 52 | ~SequenceCheckerImpl(); |
Gabriel Charette | 9746ffce | 2019-07-30 20:27:17 | [diff] [blame] | 53 | |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 54 | // Returns true if called in sequence with previous calls to this method and |
| 55 | // the constructor. |
danakj | 894364e | 2021-01-27 21:51:29 | [diff] [blame] | 56 | // On returning false, if logging is enabled with EnableStackLogging() and |
| 57 | // `out_bound_at` is not null, this method allocates a StackTrace and returns |
| 58 | // it in the out-parameter, storing inside it the stack from where the failing |
| 59 | // SequenceChecker was bound to its sequence. Otherwise, out_bound_at is left |
| 60 | // untouched. |
Daniel Cheng | 4455c984 | 2022-01-13 23:26:37 | [diff] [blame] | 61 | [[nodiscard]] bool CalledOnValidSequence( |
| 62 | std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const; |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 63 | |
fdoray | eed5fa7 | 2016-07-26 22:28:45 | [diff] [blame] | 64 | // Unbinds the checker from the currently associated sequence. The checker |
fdoray | e2b19a1 | 2016-07-29 02:30:16 | [diff] [blame] | 65 | // will be re-bound on the next call to CalledOnValidSequence(). |
[email protected] | d52426c | 2013-07-30 19:26:40 | [diff] [blame] | 66 | void DetachFromSequence(); |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 67 | |
| 68 | private: |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 69 | void EnsureAssigned() const EXCLUSIVE_LOCKS_REQUIRED(lock_); |
| 70 | |
| 71 | // Members are mutable so that `CalledOnValidSequence()` can set them. |
| 72 | |
| 73 | mutable Lock lock_; |
| 74 | |
| 75 | // Stack from which this was bound (set if `EnableStackLogging()` was called). |
| 76 | mutable std::unique_ptr<debug::StackTrace> bound_at_ GUARDED_BY(lock_); |
| 77 | |
| 78 | // Sequence to which this is bound. |
| 79 | mutable internal::SequenceToken sequence_token_ GUARDED_BY(lock_); |
| 80 | |
François Doray | 62cb8e9 | 2024-06-05 14:49:02 | [diff] [blame] | 81 | #if DCHECK_IS_ON() |
| 82 | // Locks to which this is bound. |
| 83 | mutable std::vector<uintptr_t> locks_ GUARDED_BY(lock_); |
| 84 | #endif // DCHECK_IS_ON() |
| 85 | |
François Doray | 524d2a2 | 2024-01-04 09:54:16 | [diff] [blame] | 86 | // Thread to which this is bound. Only used to evaluate |
| 87 | // `CalledOnValidSequence()` after TLS destruction. |
| 88 | mutable PlatformThreadRef thread_ref_ GUARDED_BY(lock_); |
[email protected] | 399ed42 | 2012-12-27 19:58:00 | [diff] [blame] | 89 | }; |
| 90 | |
| 91 | } // namespace base |
| 92 | |
| 93 | #endif // BASE_SEQUENCE_CHECKER_IMPL_H_ |