blob: 266d519b6d862f853f5b9fbaf14d30f09361ad1e [file] [log] [blame]
Rhed Jao27077b12020-07-14 18:38:08 +08001/*
2 * Copyright (C) 2020 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#ifndef FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
18#define FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_
19
20#include <future>
21#include <map>
22#include <queue>
23#include <string>
24
25#include <android-base/file.h>
26#include <android-base/macros.h>
27
28namespace android {
29namespace os {
30namespace dumpstate {
31
32/*
33 * A thread pool with the fixed number of threads to execute multiple dump tasks
34 * simultaneously for the dumpstate. The dump task is a callable function
35 * included a file descriptor as a parameter, and the task could dump results to
36 * that fd. For example:
37 *
38 * void DumpXXXX(int out_fd) {
39 * dprintf(out_fd, "Dump result to out_fd ...");
40 * }
41 * ...
42 * DumpPool pool(tmp_root);
43 * pool.enqueueTask("TaskName", &DumpXXXX, std::placeholders::_1);
44 * ...
45 * pool.waitForTask("TaskName");
46 *
47 * DumpXXXX is a callable function included a out_fd parameter. Using the
48 * enqueueTask method in DumpPool to enqueue the task to the pool. The
49 * std::placeholders::_1 is placeholder for DumpPool to pass a fd argument.
50 */
51class DumpPool {
52 public:
53 /*
54 * Creates a thread pool.
55 *
56 * |tmp_root| A path to a temporary folder for threads to create temporary
57 * files.
58 */
59 explicit DumpPool(const std::string& tmp_root);
60 ~DumpPool();
61
62 /*
63 * Starts the threads in the pool.
64 *
65 * |thread_counts| the number of threads to start.
66 */
67 void start(int thread_counts = MAX_THREAD_COUNT);
68
69 /*
70 * Requests to shutdown the pool and waits until all threads exit the loop.
71 */
72 void shutdown();
73
74 /*
75 * Adds a task with a task name into the queue of the thread pool.
76 *
77 * |task_name| The name of the task.
78 * |f| Callable function to execute the task. This function must
79 * include a parameter of file descriptor to output dump result.
80 * |args| A list of arguments.
81 */
82 template<class F, class... Args> void enqueueTask(const std::string& task_name,
83 F&& f, Args&&... args) {
84 auto func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
85 futures_map_[task_name] = post(func);
86 if (threads_.empty()) {
87 start();
88 }
89 }
90
91 /*
92 * Waits until the task is finished. Dumps the task results to the STDOUT_FILENO.
93 */
94 void waitForTask(const std::string& task_name) {
95 waitForTask(task_name, "", STDOUT_FILENO);
96 }
97
98 /*
99 * Waits until the task is finished. Dumps the task results to the specified
100 * out_fd.
101 *
102 * |task_name| The name of the task.
103 * |title| Dump title string to the out_fd, an empty string for nothing.
104 * |out_fd| The target file to dump the result from the task.
105 */
106 void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
107
108 static const std::string PREFIX_TMPFILE_NAME;
109
110 private:
111 using Task = std::packaged_task<std::string()>;
112 using Future = std::shared_future<std::string>;
113
114 template<class T> Future post(T dump_func) {
115 Task packaged_task([=]() {
116 std::unique_ptr<TmpFile> tmp_file_ptr = createTempFile();
117 if (!tmp_file_ptr) {
118 return std::string("");
119 }
120 std::invoke(dump_func, tmp_file_ptr->fd.get());
121 fsync(tmp_file_ptr->fd.get());
122 return std::string(tmp_file_ptr->path);
123 });
124 std::unique_lock lock(lock_);
125 auto future = packaged_task.get_future().share();
126 tasks_.push(std::move(packaged_task));
127 condition_variable_.notify_one();
128 return future;
129 }
130
131 typedef struct {
132 android::base::unique_fd fd;
133 char path[1024];
134 } TmpFile;
135
136 std::unique_ptr<TmpFile> createTempFile();
137 void deleteTempFiles(const std::string& folder);
138 void setThreadName(const pthread_t thread, int id);
139 void loop();
140
141 private:
142 static const int MAX_THREAD_COUNT = 4;
143
144 /* A path to a temporary folder for threads to create temporary files. */
145 std::string tmp_root_;
146 bool shutdown_;
147 std::mutex lock_; // A lock for the tasks_.
148 std::condition_variable condition_variable_;
149
150 std::vector<std::thread> threads_;
151 std::queue<Task> tasks_;
152 std::map<std::string, Future> futures_map_;
153
154 DISALLOW_COPY_AND_ASSIGN(DumpPool);
155};
156
157} // namespace dumpstate
158} // namespace os
159} // namespace android
160
161#endif //FRAMEWORK_NATIVE_CMD_DUMPPOOL_H_