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-process-pool/process_pool.hh"
19 #include <dlog-redirect-stdout.h>
24 #include <sys/types.h>
33 #include "launchpad-process-pool/launchpad_args.hh"
34 #include "launchpad-process-pool/log_private.hh"
36 namespace fs = std::filesystem;
41 constexpr const char kProcessPool[] = "process-pool";
43 std::vector<int> GetDlogFds() {
46 fs::path proc_path("/proc/self/fd");
47 for (const auto& entry : fs::directory_iterator(proc_path)) {
48 if (!isdigit(entry.path().filename().string()[0]))
51 int fd = std::stoi(entry.path().filename().string());
52 if (dlog_is_log_fd(fd))
55 } catch (const fs::filesystem_error& e) {
56 _E("Exception occurs. error(%s)", e.what());
64 ProcessPool::ProcessPool(std::string name, int num_processes,
65 IEvent* event_listener = nullptr)
67 name_(std::move(name)),
68 num_processes_(num_processes),
69 event_listener_(event_listener) {
73 ProcessPool::~ProcessPool() {
77 bool ProcessPool::IsPrepared() const {
78 return !queue_.empty();
81 pid_t ProcessPool::Execute(const tizen_base::Parcel& parcel) {
86 auto process = std::move(queue_.front());
88 process->Send(parcel);
89 return process->GetPid();
92 void ProcessPool::Dispose() {
93 while (!queue_.empty()) {
94 auto process = std::move(queue_.front());
97 _D("Kill process(%d)", process->GetPid());
103 ProcessPool::Process::Process(pid_t pid, int fd)
104 : pid_(pid), socket_(new Socket(fd)) {
107 pid_t ProcessPool::Process::GetPid() const {
111 int ProcessPool::Process::Send(const tizen_base::Parcel& parcel) {
112 _W("Send execution request. process ID: %d", pid_);
113 size_t data_size = parcel.GetDataSize();
114 int ret = socket_->Write(static_cast<void*>(&data_size), sizeof(data_size));
116 _E("Write() is failed. error(%d)", ret);
120 return socket_->Write(parcel.GetData(), parcel.GetDataSize());
123 void ProcessPool::Process::Kill() {
125 if (kill(pid_, SIGKILL) == -1) {
126 _E("Failed to send kill signal to the process. pid(%d), errno(%d)",
131 void ProcessPool::OnExecution() {
132 _D("Candidate Process");
133 char** args = LaunchpadArgs::GetInst().GetArgs();
134 size_t length = strlen(args[0]);
135 memset(args[0], '\0', length);
136 snprintf(args[0], length, "/usr/bin/%s <%s>", kProcessPool, name_.c_str());
139 std::vector<int> except_fds = GetDlogFds();
140 except_fds.push_back(pipe_fd_[0]);
141 Util::CloseAllFds(except_fds);
142 int ret = WaitForRequest(std::make_unique<Socket>(pipe_fd_[0]));
146 void ProcessPool::PrepareProcess() {
147 int current_process_count = static_cast<int>(queue_.size());
148 for (int i = current_process_count; i < num_processes_; ++i) {
151 if (pipe(pipe_fd_) == -1) {
152 _E("Failed to create pipe. errno(%d)", errno);
156 if (fcntl(pipe_fd_[0], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
157 _E("Failed to set pipe size. errno(%d)", errno);
159 if (fcntl(pipe_fd_[1], F_SETPIPE_SZ, Socket::kSocketMaxBufferSize) == -1)
160 _E("Failed to set pipe size. errno(%d)", errno);
162 pid_t pid = Executor::Execute();
164 _E("Failed to fork process. errno(%d)", errno);
171 queue_.push(std::make_shared<Process>(pid, pipe_fd_[1]));
175 int ProcessPool::WaitForRequest(std::unique_ptr<Socket> socket) {
176 tizen_base::Parcel parcel;
179 size_t data_size = 0;
180 ret = socket->Read(static_cast<void*>(&data_size), sizeof(data_size));
182 _E("Failed to read from socket. error(%d)", ret);
186 std::vector<uint8_t> data(data_size);
187 ret = socket->Read(data.data(), data.size());
189 _E("Failed to read from socket. error(%d)", ret);
193 parcel.Write(data.data(), data.size());
196 if (event_listener_ != nullptr)
197 event_listener_->OnRequestReceived(&parcel);
202 void ProcessPool::SetTimer() {
206 timer_ = g_timeout_add(1000, OnTimeout, this);
209 void ProcessPool::UnsetTimer() {
211 g_source_remove(timer_);
216 gboolean ProcessPool::OnTimeout(gpointer user_data) {
217 auto* process_pool = static_cast<ProcessPool*>(user_data);
218 process_pool->PrepareProcess();
219 process_pool->timer_ = 0;
220 return G_SOURCE_REMOVE;
223 } // namespace launchpad