Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (C) 2018 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 <pthread.h>
     18 #include <stdlib.h>
     19 #include <sys/syscall.h>
     20 #include <sys/types.h>
     21 #include <unistd.h>
     22 
     23 #include <condition_variable>
     24 #include <thread>
     25 
     26 #include "perfetto/base/file_utils.h"
     27 #include "perfetto/base/string_splitter.h"
     28 #include "perfetto/base/time.h"
     29 #include "test/task_runner_thread.h"
     30 
     31 namespace perfetto {
     32 
     33 TaskRunnerThread::TaskRunnerThread(const char* name) : name_(name) {}
     34 TaskRunnerThread::~TaskRunnerThread() {
     35   Stop();
     36 }
     37 
     38 void TaskRunnerThread::Start(std::unique_ptr<ThreadDelegate> delegate) {
     39   // Begin holding the lock for the condition variable.
     40   std::unique_lock<std::mutex> lock(mutex_);
     41 
     42   // Start the thread.
     43   PERFETTO_DCHECK(!runner_);
     44   thread_ = std::thread(&TaskRunnerThread::Run, this, std::move(delegate));
     45 
     46   // Wait for runner to be ready.
     47   ready_.wait_for(lock, std::chrono::seconds(10),
     48                   [this]() { return runner_ != nullptr; });
     49 }
     50 
     51 void TaskRunnerThread::Stop() {
     52   {
     53     std::unique_lock<std::mutex> lock(mutex_);
     54     if (runner_)
     55       runner_->Quit();
     56   }
     57 
     58   if (thread_.joinable())
     59     thread_.join();
     60 }
     61 
     62 uint64_t TaskRunnerThread::GetThreadCPUTimeNs() {
     63   std::condition_variable cv;
     64   std::unique_lock<std::mutex> lock(mutex_);
     65   uint64_t thread_time_ns = 0;
     66 
     67   if (!runner_)
     68     return 0;
     69 
     70   runner_->PostTask([this, &thread_time_ns, &cv] {
     71     std::unique_lock<std::mutex> inner_lock(mutex_);
     72     thread_time_ns = static_cast<uint64_t>(base::GetThreadCPUTimeNs().count());
     73     cv.notify_one();
     74   });
     75 
     76   cv.wait(lock, [&thread_time_ns] { return thread_time_ns != 0; });
     77   return thread_time_ns;
     78 }
     79 
     80 void TaskRunnerThread::Run(std::unique_ptr<ThreadDelegate> delegate) {
     81 #if PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
     82   pthread_setname_np(name_);
     83 #else
     84   pthread_setname_np(pthread_self(), name_);
     85 #endif
     86 
     87   // Create the task runner and execute the specicalised code.
     88   base::PlatformTaskRunner task_runner;
     89   delegate->Initialize(&task_runner);
     90 
     91   // Pass the runner back to the main thread.
     92   {
     93     std::unique_lock<std::mutex> lock(mutex_);
     94     runner_ = &task_runner;
     95   }
     96 
     97   // Notify the main thread that the runner is ready.
     98   ready_.notify_one();
     99 
    100   // Spin the loop.
    101   task_runner.Run();
    102 
    103   // Ensure we clear out the delegate before runner goes out
    104   // of scope.
    105   delegate.reset();
    106 
    107   // Cleanup the runner.
    108   {
    109     std::unique_lock<std::mutex> lock(mutex_);
    110     runner_ = nullptr;
    111   }
    112 }
    113 
    114 ThreadDelegate::~ThreadDelegate() = default;
    115 
    116 }  // namespace perfetto
    117