2 * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "launchpad/thread_control.hh"
19 #include <sys/types.h>
27 #include "launchpad/log_private.hh"
32 const int SIGRTINT = SIGRTMIN + 2;
34 std::vector<pid_t> GetTasks() {
35 std::vector<pid_t> tasks;
36 std::filesystem::path task_path("/proc/self/task");
38 for (auto& entry : std::filesystem::directory_iterator(task_path)) {
39 if (!std::isdigit(entry.path().filename().c_str()[0]))
42 tasks.push_back(std::stoi(entry.path().filename().string()));
44 } catch (const std::filesystem::filesystem_error& e) {
45 _E("Exception occurs. error: %s", e.what());
51 std::string GetThreadName(pid_t tid) {
52 std::string path = "/proc/" + std::to_string(tid) + "/comm";
53 std::ifstream proc_file(path);
54 if (proc_file.is_open()) {
56 std::getline(proc_file, name);
61 _E("Failed to read name. tid(%d)", tid);
65 int GetThreadCountWithoutGmain(const std::vector<pid_t>& tasks) {
66 int count = tasks.size() - 1;
67 for (auto tid : tasks) {
68 if (getpid() != tid) {
69 // Unfortunately, the signal handler of the gmain thread is not invoked.
70 // The gmain thread always calls poll().
71 // To avoid delay issue of calling usleep(), this function decreases
72 // the count if the gmain threads exists.
73 if (GetThreadName(tid) == "gmain") {
74 _D("%d is gmain thread", tid);
85 ThreadControl& ThreadControl::GetInst() {
86 static ThreadControl inst;
90 ThreadControl::~ThreadControl() {
94 int ThreadControl::BlockThreads() {
98 if (!ChangeSigaction())
107 int ThreadControl::UnblockThreads() {
118 bool ThreadControl::IsBlocked() const {
122 int ThreadControl::GetCount() {
123 return GetTasks().size();
126 bool ThreadControl::ChangeSigaction() {
127 struct sigaction act;
128 memset(&act, '\0', sizeof(struct sigaction));
129 sigemptyset(&act.sa_mask);
130 act.sa_flags = SA_RESTART | SA_SIGINFO;
131 act.sa_handler = SignalHandler;
133 if (sigaction(SIGRTINT, &act, &old_action_) != 0) {
134 _E("sigaction() is failed. errno(%d)", errno);
141 void ThreadControl::InterruptThreads() {
142 pid_t pid = getpid();
143 auto tasks = GetTasks();
144 count_ = GetThreadCountWithoutGmain(tasks);
145 _D("tasks count: %d", count_);
146 for (auto& tid : tasks) {
148 _D("Send signal to thread(%d)", tid);
149 if (tgkill(pid, tid, SIGRTINT) != 0) {
150 _E("tgkill() is failed. tid(%d), errno(%d)", tid, errno);
157 void ThreadControl::ContinueThreads() {
158 std::unique_lock<std::mutex> lock(mutex_);
159 count_ = GetThreadCountWithoutGmain(GetTasks());
160 _D("tasks count: %d", count_);
165 void ThreadControl::WaitThreads() {
166 for (int i = 1000; count_ && i; --i)
170 void ThreadControl::RestoreSigaction() {
171 if (sigaction(SIGRTINT, &old_action_, nullptr) != 0)
172 _E("sigaction() is failed. errno(%d)", errno);
175 void ThreadControl::SignalHandler(int signo) {
177 auto& inst = ThreadControl::GetInst();
178 std::unique_lock<std::mutex> lock(inst.mutex_);
180 if (inst.cond_.wait_for(lock, std::chrono::seconds(5),
181 [&] { return inst.done_; }))
188 } // namespace launchpad