1 /*
2 * Copyright (C) 2021 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 #pragma once
18
19 #include <functional>
20 #include <map>
21 #include <mutex>
22 #include <optional>
23 #include <sstream>
24 #include <string>
25 #include <thread>
26
27 #include <android-base/logging.h>
28
29 #include "common/libs/confui/confui.h"
30 #include "host/commands/kernel_log_monitor/utils.h"
31 #include "host/libs/config/logging.h"
32
33 namespace cuttlefish {
34 namespace confui {
35
36 namespace thread {
37 /* thread id to name
38 * these three functions internally uses the singleton ThreadTracer object.
39 *
40 * When running a thread, use the global RunThread function
41 */
42 std::string GetName(const std::thread::id tid = std::this_thread::get_id());
43 std::optional<std::thread::id> GetId(const std::string& name);
44 void Set(const std::string& name, const std::thread::id tid);
45
46 /*
47 * This is wrapping std::thread. However, we keep the bidirectional map
48 * between the given thread name and the thread id. The main purpose is
49 * to help debugging.
50 *
51 */
52 template <typename F, typename... Args>
53 std::thread RunThread(const std::string& name, F&& f, Args&&... args);
54
55 class ThreadTracer;
56 ThreadTracer& GetThreadTracer();
57
58 class ThreadTracer {
59 friend ThreadTracer& GetThreadTracer();
60 friend std::string GetName(const std::thread::id tid);
61 friend std::optional<std::thread::id> GetId(const std::string& name);
62 friend void Set(const std::string& name, const std::thread::id tid);
63
64 template <typename F, typename... Args>
65 friend std::thread RunThread(const std::string& name, F&& f, Args&&... args);
66
67 private:
68 template <typename F, typename... Args>
RunThread(const std::string & name,F && f,Args &&...args)69 std::thread RunThread(const std::string& name, F&& f, Args&&... args) {
70 auto th = std::thread(std::forward<F>(f), std::forward<Args>(args)...);
71 if (name2id_.find(name) != name2id_.end()) {
72 ConfUiLog(FATAL) << "Thread name is duplicated";
73 }
74 name2id_[name] = th.get_id();
75 id2name_[th.get_id()] = name;
76 ConfUiLog(DEBUG) << name << "thread started.";
77 return th;
78 }
79 std::string Get(const std::thread::id id = std::this_thread::get_id());
80 std::optional<std::thread::id> Get(const std::string& name);
81
82 // add later on even though it wasn't started with RunThread
83 // if tid is already added, update the name only
84 void Set(const std::string& name, const std::thread::id tid);
85
86 ThreadTracer() = default;
87 std::map<std::thread::id, std::string> id2name_;
88 std::map<std::string, std::thread::id> name2id_;
89 std::mutex mtx_;
90 };
91
92 template <typename F, typename... Args>
RunThread(const std::string & name,F && f,Args &&...args)93 std::thread RunThread(const std::string& name, F&& f, Args&&... args) {
94 auto& tracer = GetThreadTracer();
95 return tracer.RunThread(name, std::forward<F>(f),
96 std::forward<Args>(args)...);
97 }
98
99 } // namespace thread
100 } // namespace confui
101 } // namespace cuttlefish
102