Home | History | Annotate | Download | only in base
      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 
     30 ThreadTaskRunner::ThreadTaskRunner(ThreadTaskRunner&& other) noexcept
     31     : thread_(std::move(other.thread_)), task_runner_(other.task_runner_) {
     32   other.task_runner_ = nullptr;
     33 }
     34 
     35 ThreadTaskRunner& ThreadTaskRunner::operator=(ThreadTaskRunner&& other) {
     36   this->~ThreadTaskRunner();
     37   new (this) ThreadTaskRunner(std::move(other));
     38   return *this;
     39 }
     40 
     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 
     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 
     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