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