blob: 629e23cb7b2fe4ab7fba33467d6df4707497fb3d [file] [log] [blame]
Jordan Baylesb0c191e2019-03-26 15:49:57 -07001// Copyright 2019 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
Jordan Baylesa26582d2019-07-10 14:44:58 -07005#ifndef PLATFORM_IMPL_TASK_RUNNER_H_
6#define PLATFORM_IMPL_TASK_RUNNER_H_
Jordan Baylesb0c191e2019-03-26 15:49:57 -07007
Jordan Baylesb0c191e2019-03-26 15:49:57 -07008#include <condition_variable> // NOLINT
Yuri Wiitalab929b832019-06-05 17:13:15 -07009#include <map>
Jordan Baylesb0c191e2019-03-26 15:49:57 -070010#include <memory>
Ryan Keanea973b512019-07-29 15:50:39 -070011#include <mutex> // NOLINT
Max Yakimakhabf567dc2019-09-20 13:37:04 -070012#include <thread>
Jordan Baylesb0c191e2019-03-26 15:49:57 -070013#include <utility>
14#include <vector>
15
16#include "absl/base/thread_annotations.h"
17#include "absl/types/optional.h"
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -080018#include "build/config/features.h"
Ryan Keane230920e2019-08-29 13:21:40 -070019#include "platform/api/task_runner.h"
Jordan Baylesb0c191e2019-03-26 15:49:57 -070020#include "platform/api/time.h"
Jordan Baylesa26582d2019-07-10 14:44:58 -070021#include "platform/base/error.h"
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -080022#include "util/trace_logging.h"
Jordan Baylesb0c191e2019-03-26 15:49:57 -070023
24namespace openscreen {
Jordan Baylesb0c191e2019-03-26 15:49:57 -070025
btolsch4051e722019-06-07 16:15:17 -070026class TaskRunnerImpl final : public TaskRunner {
Jordan Baylesb0c191e2019-03-26 15:49:57 -070027 public:
btolsch4051e722019-06-07 16:15:17 -070028 using Task = TaskRunner::Task;
29
btolschd94fe622019-05-09 14:21:40 -070030 class TaskWaiter {
31 public:
32 virtual ~TaskWaiter() = default;
33
34 // These calls should be thread-safe. The absolute minimum is that
35 // OnTaskPosted must be safe to call from another thread while this is
36 // inside WaitForTaskToBePosted. NOTE: There may be spurious wakeups from
37 // WaitForTaskToBePosted depending on whether the specific implementation
38 // chooses to clear queued WakeUps before entering WaitForTaskToBePosted.
39
40 // Blocks until some event occurs, which means new tasks may have been
41 // posted. Wait may only block up to |timeout| where 0 means don't block at
42 // all (not block forever).
43 virtual Error WaitForTaskToBePosted(Clock::duration timeout) = 0;
44
45 // If a WaitForTaskToBePosted call is currently blocking, unblock it
46 // immediately.
47 virtual void OnTaskPosted() = 0;
48 };
49
50 explicit TaskRunnerImpl(
Yuri Wiitala2b02e322019-12-03 16:59:40 -080051 ClockNowFunctionPtr now_function,
btolschd94fe622019-05-09 14:21:40 -070052 TaskWaiter* event_waiter = nullptr,
53 Clock::duration waiter_timeout = std::chrono::milliseconds(100));
Jordan Baylesb0c191e2019-03-26 15:49:57 -070054
55 // TaskRunner overrides
Yuri Wiitalab929b832019-06-05 17:13:15 -070056 ~TaskRunnerImpl() final;
57 void PostPackagedTask(Task task) final;
58 void PostPackagedTaskWithDelay(Task task, Clock::duration delay) final;
Max Yakimakhabf567dc2019-09-20 13:37:04 -070059 bool IsRunningOnTaskRunner() final;
Jordan Baylesb0c191e2019-03-26 15:49:57 -070060
Yuri Wiitalac05ada22019-09-24 14:25:19 -070061 // Blocks the current thread, executing tasks from the queue with the desired
62 // timing; and does not return until some time after RequestStopSoon() is
63 // called.
Jordan Baylesb0c191e2019-03-26 15:49:57 -070064 void RunUntilStopped();
Jordan Baylesa8e96772019-04-08 10:53:54 -070065
Yuri Wiitala341085a2020-03-11 17:13:54 -070066 // Blocks the current thread, executing tasks from the queue with the desired
67 // timing; and does not return until some time after the current process is
68 // signaled with SIGINT or SIGTERM, or after RequestStopSoon() is called.
69 void RunUntilSignaled();
70
Yuri Wiitalac05ada22019-09-24 14:25:19 -070071 // Thread-safe method for requesting the TaskRunner to stop running after all
72 // non-delayed tasks in the queue have run. This behavior allows final
73 // clean-up tasks to be executed before the TaskRunner stops.
74 //
75 // If any non-delayed tasks post additional non-delayed tasks, those will be
76 // run as well before returning.
Jordan Baylesb0c191e2019-03-26 15:49:57 -070077 void RequestStopSoon();
78
Jordan Baylesb0c191e2019-03-26 15:49:57 -070079 private:
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -080080#if defined(ENABLE_TRACE_LOGGING)
Ryan Keaneefab2ed2019-07-22 12:36:53 -070081 // Wrapper around a Task used to store the TraceId Metadata along with the
82 // task itself, and to set the current TraceIdHierarchy before executing the
83 // task.
84 class TaskWithMetadata {
85 public:
Ryan Keane1d9c0c42019-07-29 15:22:19 -070086 // NOTE: 'explicit' keyword omitted so that conversion construtor can be
87 // used. This simplifies switching between 'Task' and 'TaskWithMetadata'
88 // based on the compilation flag.
89 TaskWithMetadata(Task task)
Yuri Wiitalaca24ee52019-12-05 16:51:42 -080090 : task_(std::move(task)), trace_ids_(TRACE_HIERARCHY) {}
Ryan Keaneefab2ed2019-07-22 12:36:53 -070091
Ryan Keane1d9c0c42019-07-29 15:22:19 -070092 void operator()() {
93 TRACE_SET_HIERARCHY(trace_ids_);
94 std::move(task_)();
95 }
Ryan Keaneefab2ed2019-07-22 12:36:53 -070096
97 private:
98 Task task_;
99 TraceIdHierarchy trace_ids_;
100 };
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -0800101#else // !defined(ENABLE_TRACE_LOGGING)
Ryan Keane1d9c0c42019-07-29 15:22:19 -0700102 using TaskWithMetadata = Task;
Yuri Wiitala8e6db3b2019-11-20 11:20:54 -0800103#endif // defined(ENABLE_TRACE_LOGGING)
Ryan Keaneefab2ed2019-07-22 12:36:53 -0700104
Yuri Wiitalac05ada22019-09-24 14:25:19 -0700105 // Helper that runs all tasks in |running_tasks_| and then clears it.
106 void RunRunnableTasks();
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700107
108 // Look at all tasks in the delayed task queue, then schedule them if the
109 // minimum delay time has elapsed.
110 void ScheduleDelayedTasks();
111
Yuri Wiitala71a84bc2019-09-25 12:00:23 -0700112 // Transfers all ready-to-run tasks from |tasks_| to |running_tasks_|. If
113 // there are no ready-to-run tasks, and |is_running_| is true, this method
114 // will block waiting for new tasks. Returns true if any tasks were
115 // transferred.
116 bool GrabMoreRunnableTasks();
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700117
Yuri Wiitala2b02e322019-12-03 16:59:40 -0800118 const ClockNowFunctionPtr now_function_;
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700119
Yuri Wiitalac05ada22019-09-24 14:25:19 -0700120 // Flag that indicates whether the task runner loop should continue. This is
121 // only meant to be read/written on the thread executing RunUntilStopped().
122 bool is_running_;
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700123
Yuri Wiitalab929b832019-06-05 17:13:15 -0700124 // This mutex is used for |tasks_| and |delayed_tasks_|, and also for
125 // notifying the run loop to wake up when it is waiting for a task to be added
126 // to the queue in |run_loop_wakeup_|.
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700127 std::mutex task_mutex_;
Ryan Keaneefab2ed2019-07-22 12:36:53 -0700128 std::vector<TaskWithMetadata> tasks_ GUARDED_BY(task_mutex_);
129 std::multimap<Clock::time_point, TaskWithMetadata> delayed_tasks_
130 GUARDED_BY(task_mutex_);
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700131
btolschd94fe622019-05-09 14:21:40 -0700132 // When |task_waiter_| is nullptr, |run_loop_wakeup_| is used for sleeping the
133 // task runner. Otherwise, |run_loop_wakeup_| isn't used and |task_waiter_|
134 // is used instead (along with |waiter_timeout_|).
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700135 std::condition_variable run_loop_wakeup_;
btolschd94fe622019-05-09 14:21:40 -0700136 TaskWaiter* const task_waiter_;
137 Clock::duration waiter_timeout_;
Yuri Wiitalab929b832019-06-05 17:13:15 -0700138
139 // To prevent excessive re-allocation of the underlying array of the |tasks_|
140 // vector, use an A/B vector-swap mechanism. |running_tasks_| starts out
141 // empty, and is swapped with |tasks_| when it is time to run the Tasks.
Ryan Keaneefab2ed2019-07-22 12:36:53 -0700142 std::vector<TaskWithMetadata> running_tasks_;
Ryan Keane32c88d02019-07-02 18:46:14 -0700143
Max Yakimakhabf567dc2019-09-20 13:37:04 -0700144 std::thread::id task_runner_thread_id_;
145
Ryan Keane32c88d02019-07-02 18:46:14 -0700146 OSP_DISALLOW_COPY_AND_ASSIGN(TaskRunnerImpl);
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700147};
Jordan Baylesb0c191e2019-03-26 15:49:57 -0700148} // namespace openscreen
149
Jordan Baylesa26582d2019-07-10 14:44:58 -0700150#endif // PLATFORM_IMPL_TASK_RUNNER_H_