• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "perfetto/base/thread_task_runner.h"
18 
19 #include <condition_variable>
20 #include <functional>
21 #include <mutex>
22 #include <thread>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/base/unix_task_runner.h"
26 
27 namespace perfetto {
28 namespace base {
29 
ThreadTaskRunner(ThreadTaskRunner && other)30 ThreadTaskRunner::ThreadTaskRunner(ThreadTaskRunner&& other) noexcept
31     : thread_(std::move(other.thread_)), task_runner_(other.task_runner_) {
32   other.task_runner_ = nullptr;
33 }
34 
operator =(ThreadTaskRunner && other)35 ThreadTaskRunner& ThreadTaskRunner::operator=(ThreadTaskRunner&& other) {
36   this->~ThreadTaskRunner();
37   new (this) ThreadTaskRunner(std::move(other));
38   return *this;
39 }
40 
~ThreadTaskRunner()41 ThreadTaskRunner::~ThreadTaskRunner() {
42   if (task_runner_) {
43     PERFETTO_CHECK(!task_runner_->QuitCalled());
44     task_runner_->Quit();
45 
46     PERFETTO_DCHECK(thread_.joinable());
47   }
48   if (thread_.joinable())
49     thread_.join();
50 }
51 
ThreadTaskRunner()52 ThreadTaskRunner::ThreadTaskRunner() {
53   std::mutex init_lock;
54   std::condition_variable init_cv;
55 
56   std::function<void(UnixTaskRunner*)> initializer =
57       [this, &init_lock, &init_cv](UnixTaskRunner* task_runner) {
58         std::lock_guard<std::mutex> lock(init_lock);
59         task_runner_ = task_runner;
60         // Notify while still holding the lock, as init_cv ceases to exist as
61         // soon as the main thread observes a non-null task_runner_, and it can
62         // wake up spuriously (i.e. before the notify if we had unlocked before
63         // notifying).
64         init_cv.notify_one();
65       };
66   thread_ = std::thread(&ThreadTaskRunner::RunTaskThread, this,
67                         std::move(initializer));
68 
69   std::unique_lock<std::mutex> lock(init_lock);
70   init_cv.wait(lock, [this] { return !!task_runner_; });
71 }
72 
RunTaskThread(std::function<void (UnixTaskRunner *)> initializer)73 void ThreadTaskRunner::RunTaskThread(
74     std::function<void(UnixTaskRunner*)> initializer) {
75   UnixTaskRunner task_runner;
76   task_runner.PostTask(std::bind(std::move(initializer), &task_runner));
77   task_runner.Run();
78 }
79 
80 }  // namespace base
81 }  // namespace perfetto
82