blob: ab8657553882f88542a1beee09019d7b078e61bf [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
5#ifndef API_IMPL_TASK_RUNNER_IMPL_H_
6#define API_IMPL_TASK_RUNNER_IMPL_H_
7
8#include <atomic>
9#include <condition_variable> // NOLINT
10#include <deque>
11#include <functional>
12#include <memory>
13#include <mutex> // NOLINT
14#include <queue>
15#include <thread> // NOLINT
16#include <utility>
17#include <vector>
18
19#include "absl/base/thread_annotations.h"
20#include "absl/types/optional.h"
21#include "api/public/task_runner.h"
22#include "platform/api/time.h"
23
24namespace openscreen {
25namespace platform {
26
27class TaskRunnerImpl : public TaskRunner {
28 public:
29 explicit TaskRunnerImpl(platform::ClockNowFunctionPtr now_function);
30
31 // TaskRunner overrides
32 ~TaskRunnerImpl() override;
33 void PostTask(Task task) override;
34 void PostTaskWithDelay(Task task, Clock::duration delay) override;
35
36 // Tasks will only be executed if RunUntilStopped has been called, and Stop
37 // has not. Important note: TaskRunnerImpl does NOT do any threading, so
38 // calling "RunUntilStopped()" will block whatever thread you are calling it
39 // on.
40 void RunUntilStopped();
41 void RequestStopSoon();
42
43 // Execute all tasks immediately, useful for testing only. Note: this method
44 // will schedule any delayed tasks that are ready to run, but does not block
45 // waiting for delayed tasks to become eligible.
46 void RunUntilIdleForTesting();
47
48 private:
49 struct DelayedTask {
50 DelayedTask(Task task_, Clock::time_point time_runnable_after_)
51 : task(std::move(task_)), time_runnable_after(time_runnable_after_) {}
52
53 Task task;
54 Clock::time_point time_runnable_after;
55
56 bool operator>(const DelayedTask& other) const {
57 return this->time_runnable_after > other.time_runnable_after;
58 }
59 };
60
61 // Run all tasks already in the task queue.
62 void RunCurrentTasksBlocking();
63 void RunCurrentTasksForTesting();
64
65 // Loop method that runs tasks in the current thread, until the Stop
66 // method is called.
67 void RunTasksUntilStopped();
68
69 // Look at all tasks in the delayed task queue, then schedule them if the
70 // minimum delay time has elapsed.
71 void ScheduleDelayedTasks();
72
73 // Puts the task running thread into a waiting state for a notify on the
74 // run loop wakeup condition variable, and returns the acquired lock.
75 std::unique_lock<std::mutex> WaitForWorkAndAcquireLock();
76
77 const platform::ClockNowFunctionPtr now_function_;
78
79 // Atomic so that we can perform atomic exchanges.
80 std::atomic_bool is_running_;
81
82 // This mutex is used for both tasks_ and notifying the run loop to wake
83 // up when it is waiting for a task to be added to the queue in
84 // run_loop_wakeup_.
85 std::mutex task_mutex_;
86 std::priority_queue<DelayedTask,
87 std::vector<DelayedTask>,
88 std::greater<DelayedTask>>
89 delayed_tasks_ GUARDED_BY(task_mutex_);
90
91 std::condition_variable run_loop_wakeup_;
92 std::deque<Task> tasks_ GUARDED_BY(task_mutex_);
93};
94} // namespace platform
95} // namespace openscreen
96
97#endif // API_IMPL_TASK_RUNNER_IMPL_H_