xref: /aosp_15_r20/external/cronet/base/task/common/scoped_defer_task_posting.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 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_TASK_COMMON_SCOPED_DEFER_TASK_POSTING_H_
6 #define BASE_TASK_COMMON_SCOPED_DEFER_TASK_POSTING_H_
7 
8 #include <vector>
9 
10 #include "base/base_export.h"
11 #include "base/location.h"
12 #include "base/task/sequenced_task_runner.h"
13 #include "base/time/time.h"
14 
15 namespace base {
16 
17 // Tracing wants to post tasks from within a trace event within PostTask, but
18 // this can lead to a deadlock. Create a scope to ensure that we are posting
19 // the tasks in question outside of the scope of the lock.
20 // NOTE: This scope affects only the thread it is created on. All other threads
21 // still can post tasks.
22 //
23 // TODO(altimin): It should be possible to get rid of this scope, but this
24 // requires refactoring TimeDomain to ensure that TimeDomain never changes and
25 // we can read current time without grabbing a lock.
26 class BASE_EXPORT [[maybe_unused, nodiscard]] ScopedDeferTaskPosting {
27  public:
28   static void PostOrDefer(scoped_refptr<SequencedTaskRunner> task_runner,
29                           const Location& from_here,
30                           OnceClosure task,
31                           base::TimeDelta delay);
32 
33   static bool IsPresent();
34 
35   ScopedDeferTaskPosting();
36 
37   ScopedDeferTaskPosting(const ScopedDeferTaskPosting&) = delete;
38   ScopedDeferTaskPosting& operator=(const ScopedDeferTaskPosting&) = delete;
39 
40   ~ScopedDeferTaskPosting();
41 
42  private:
43   static ScopedDeferTaskPosting* Get();
44   // Returns whether the |scope| was set as active, which happens only
45   // when the scope wasn't set before.
46   static bool Set(ScopedDeferTaskPosting* scope);
47 
48   void DeferTaskPosting(scoped_refptr<SequencedTaskRunner> task_runner,
49                         const Location& from_here,
50                         OnceClosure task,
51                         base::TimeDelta delay);
52 
53   struct DeferredTask {
54     DeferredTask(scoped_refptr<SequencedTaskRunner> task_runner,
55                  Location from_here,
56                  OnceClosure task,
57                  base::TimeDelta delay);
58 
59     DeferredTask(const DeferredTask&) = delete;
60     DeferredTask& operator=(const DeferredTask&) = delete;
61 
62     DeferredTask(DeferredTask&& task);
63 
64     ~DeferredTask();
65 
66     scoped_refptr<SequencedTaskRunner> task_runner;
67     Location from_here;
68     OnceClosure task;
69     base::TimeDelta delay;
70   };
71 
72   std::vector<DeferredTask> deferred_tasks_;
73 
74   // Scopes can be nested (e.g. ScheduleWork inside PostTasks can post a task
75   // to another task runner), so we want to know whether the scope is top-level
76   // or not.
77   bool top_level_scope_ = false;
78 };
79 
80 }  // namespace base
81 
82 #endif  // BASE_TASK_COMMON_SCOPED_DEFER_TASK_POSTING_H_
83