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