1// 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
8#include "base/compiler_specific.h"
9#include "base/logging.h"
10#include "base/sequence_checker_impl.h"
11#include "build/build_config.h"
12
13// SequenceChecker is a helper class used to help verify that some methods of a
14// class are called sequentially (for thread-safety).
15//
16// Use the macros below instead of the SequenceChecker directly so that the
17// unused member doesn't result in an extra byte (four when padded) per
18// instance in production.
19//
20// This class is much prefered to ThreadChecker for thread-safety checks.
21// ThreadChecker should only be used for classes that are truly thread-affine
22// (use thread-local-storage or a third-party API that does).
23//
24// Usage:
25// class MyClass {
26// public:
27// MyClass() {
28// // It's sometimes useful to detach on construction for objects that are
29// // constructed in one place and forever after used from another
30// // sequence.
31// DETACH_FROM_SEQUENCE(my_sequence_checker_);
32// }
33//
34// ~MyClass() {
35// // SequenceChecker doesn't automatically check it's destroyed on origin
36// // sequence for the same reason it's sometimes detached in the
37// // constructor. It's okay to destroy off sequence if the owner
38// // otherwise knows usage on the associated sequence is done. If you're
39// // not detaching in the constructor, you probably want to explicitly
40// // check in the destructor.
41// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
42// }
43// void MyMethod() {
44// DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);
45// ... (do stuff) ...
46// }
47//
48// private:
49// SEQUENCE_CHECKER(my_sequence_checker_);
50// }
51
52#if DCHECK_IS_ON()
53#define SEQUENCE_CHECKER(name) base::SequenceChecker name
54#define DCHECK_CALLED_ON_VALID_SEQUENCE(name) \
55 DCHECK((name).CalledOnValidSequence())
56#define DETACH_FROM_SEQUENCE(name) (name).DetachFromSequence()
57#else // DCHECK_IS_ON()
58#if __OBJC__ && defined(OS_IOS) && !HAS_FEATURE(objc_cxx_static_assert)
59// TODO(thakis): Remove this branch once Xcode's clang has clang r356148.
60#define SEQUENCE_CHECKER(name)
61#else
62#define SEQUENCE_CHECKER(name) static_assert(true, "")
63#endif
64#define DCHECK_CALLED_ON_VALID_SEQUENCE(name) EAT_STREAM_PARAMETERS
65#define DETACH_FROM_SEQUENCE(name)
66#endif // DCHECK_IS_ON()
67
68namespace base {
69
70// Do nothing implementation, for use in release mode.
71//
72// Note: You should almost always use the SequenceChecker class (through the
73// above macros) to get the right version for your build configuration.
74class SequenceCheckerDoNothing {
75 public:
76 SequenceCheckerDoNothing() = default;
77 bool CalledOnValidSequence() const WARN_UNUSED_RESULT { return true; }
78 void DetachFromSequence() {}
79
80 private:
81 DISALLOW_COPY_AND_ASSIGN(SequenceCheckerDoNothing);
82};
83
84#if DCHECK_IS_ON()
85class SequenceChecker : public SequenceCheckerImpl {
86};
87#else
88class SequenceChecker : public SequenceCheckerDoNothing {
89};
90#endif // DCHECK_IS_ON()
91
92} // namespace base
93
94#endif // BASE_SEQUENCE_CHECKER_H_
95