1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131

base / sequence_token.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BASE_SEQUENCE_TOKEN_H_
#define BASE_SEQUENCE_TOKEN_H_

// TODO: Remove this unused include once no other file indirectly depends on it.
#include "base/auto_reset.h"
#include "base/base_export.h"

namespace base {
namespace internal {

// A token that identifies a series of sequenced work items (i.e. tasks, native
// message handlers, code blocks running outside or a `RunLoop`, etc. that are
// mutually exclusive).
class BASE_EXPORT SequenceToken {
 public:
  // Instantiates an invalid SequenceToken.
  constexpr SequenceToken() = default;

  // Explicitly allow copy.
  SequenceToken(const SequenceToken& other) = default;
  SequenceToken& operator=(const SequenceToken& other) = default;

  // An invalid SequenceToken is not equal to any other SequenceToken, including
  // other invalid SequenceTokens.
  bool operator==(const SequenceToken& other) const;
  bool operator!=(const SequenceToken& other) const;

  // Returns true if this is a valid SequenceToken.
  bool IsValid() const;

  // Returns the integer uniquely representing this SequenceToken. This method
  // should only be used for tracing and debugging.
  int ToInternalValue() const;

  // Returns a valid SequenceToken which isn't equal to any previously returned
  // SequenceToken.
  static SequenceToken Create();

  // Returns the `SequenceToken` for the work item currently running on this
  // thread. A valid and unique `SequenceToken` is assigned to each thread. It
  // can be overridden in a scope with `TaskScope`.
  static SequenceToken GetForCurrentThread();

 private:
  explicit SequenceToken(int token) : token_(token) {}

  static constexpr int kInvalidSequenceToken = -1;
  int token_ = kInvalidSequenceToken;
};

// A token that identifies a task.
//
// This is used by ThreadCheckerImpl to determine whether calls to
// CalledOnValidThread() come from the same task and hence are deterministically
// single-threaded (vs. calls coming from different sequenced or parallel tasks,
// which may or may not run on the same thread).
class BASE_EXPORT TaskToken {
 public:
  // Instantiates an invalid TaskToken.
  constexpr TaskToken() = default;

  // Explicitly allow copy.
  TaskToken(const TaskToken& other) = default;
  TaskToken& operator=(const TaskToken& other) = default;

  // An invalid TaskToken is not equal to any other TaskToken, including
  // other invalid TaskTokens.
  bool operator==(const TaskToken& other) const;
  bool operator!=(const TaskToken& other) const;

  // Returns true if this is a valid TaskToken.
  bool IsValid() const;

  // In the scope of a `TaskScope`, returns a valid `TaskToken` which isn't
  // equal to any `TaskToken` returned in the scope of a different `TaskScope`.
  // Otherwise, returns an invalid `TaskToken`.
  static TaskToken GetForCurrentThread();

 private:
  friend class TaskScope;

  explicit TaskToken(int token) : token_(token) {}

  // Returns a valid `TaskToken` which isn't equal to any previously returned
  // `TaskToken`. Private as it is only meant to be instantiated by `TaskScope`.
  static TaskToken Create();

  static constexpr int kInvalidTaskToken = -1;
  int token_ = kInvalidTaskToken;
};

// Returns true if a thread checker bound in a different task than the current
// one but on the same sequence and thread may return true from
// `CalledOnValidSequence()`.
bool BASE_EXPORT CurrentTaskIsThreadBound();

// Identifies a scope in which a task runs.
class BASE_EXPORT [[maybe_unused, nodiscard]] TaskScope {
 public:
  // `sequence_token` identifies the series of mutually exclusive work items
  // that this task is part of (may be unique if this task isn't mutually
  // exclusive with any other work item). `is_thread_bound` sets the value
  // returned by `CurrentTaskIsThreadBound()` within the scope.
  // `is_running_synchronously` is true iff this is instantiated for a task run
  // synchronously by `RunOrPostTask()`.
  explicit TaskScope(SequenceToken sequence_token,
                     bool is_thread_bound,
                     bool is_running_synchronously = false);
  TaskScope(const TaskScope&) = delete;
  TaskScope& operator=(const TaskScope&) = delete;
  ~TaskScope();

 private:
  const TaskToken previous_task_token_;
  const SequenceToken previous_sequence_token_;
  const bool previous_task_is_thread_bound_;
  const bool previous_task_is_running_synchronously_;
};

}  // namespace internal

// Returns true if the current task is run synchronously by `RunOrPostTask()`.
bool BASE_EXPORT CurrentTaskIsRunningSynchronously();

}  // namespace base

#endif  // BASE_SEQUENCE_TOKEN_H_