• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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 
8 #include <cstdint>
9 #include <memory>
10 #include <vector>
11 
12 #include "base/base_export.h"
13 #include "base/sequence_token.h"
14 #include "base/synchronization/lock.h"
15 #include "base/thread_annotations.h"
16 #include "base/threading/platform_thread_ref.h"
17 
18 namespace base {
19 namespace debug {
20 class StackTrace;
21 }
22 
23 // Real implementation of SequenceChecker.
24 //
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.
35 class THREAD_ANNOTATION_ATTRIBUTE__(capability("context"))
36     BASE_EXPORT SequenceCheckerImpl {
37  public:
38   static void EnableStackLogging();
39 
40   SequenceCheckerImpl();
41 
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);
50   SequenceCheckerImpl(const SequenceCheckerImpl&) = delete;
51   SequenceCheckerImpl& operator=(const SequenceCheckerImpl&) = delete;
52   ~SequenceCheckerImpl();
53 
54   // Returns true if called in sequence with previous calls to this method and
55   // the constructor.
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.
61   [[nodiscard]] bool CalledOnValidSequence(
62       std::unique_ptr<debug::StackTrace>* out_bound_at = nullptr) const;
63 
64   // Unbinds the checker from the currently associated sequence. The checker
65   // will be re-bound on the next call to CalledOnValidSequence().
66   void DetachFromSequence();
67 
68  private:
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 
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 
86   // Thread to which this is bound. Only used to evaluate
87   // `CalledOnValidSequence()` after TLS destruction.
88   mutable PlatformThreadRef thread_ref_ GUARDED_BY(lock_);
89 };
90 
91 }  // namespace base
92 
93 #endif  // BASE_SEQUENCE_CHECKER_IMPL_H_
94