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