Refactor launchpad worker 08/289708/7
authorHwankyu Jhun <h.jhun@samsung.com>
Mon, 13 Mar 2023 23:29:31 +0000 (23:29 +0000)
committerHwanKyu Jhun <h.jhun@samsung.com>
Tue, 14 Mar 2023 06:49:16 +0000 (06:49 +0000)
The launchpad worker is implemented using C++ language.

Change-Id: Ida9775036924f4e148ba5896433634fa20f52d5f
Signed-off-by: Hwankyu Jhun <h.jhun@samsung.com>
src/launchpad-process-pool/launchpad.cc
src/launchpad-process-pool/launchpad_signal.cc
src/launchpad-process-pool/launchpad_worker.cc [deleted file]
src/launchpad-process-pool/launchpad_worker.h [deleted file]
src/launchpad-process-pool/worker.cc [new file with mode: 0644]
src/launchpad-process-pool/worker.hh [new file with mode: 0644]

index 9917e05..92d24f6 100644 (file)
@@ -39,6 +39,7 @@
 #include <vconf.h>
 
 #include <algorithm>
+#include <string>
 
 #include "launchpad-process-pool/debug.hh"
 #include "launchpad-process-pool/launcher_info.hh"
@@ -48,7 +49,6 @@
 #include "launchpad-process-pool/launchpad_io_channel.h"
 #include "launchpad-process-pool/launchpad_memory_monitor.h"
 #include "launchpad-process-pool/launchpad_signal.h"
-#include "launchpad-process-pool/launchpad_worker.h"
 #include "launchpad-process-pool/loader_info.hh"
 #include "launchpad-process-pool/slot_info.h"
 #include "lib/common/inc/key.h"
@@ -60,6 +60,7 @@
 
 #include "launchpad-process-pool/dbus.hh"
 #include "launchpad-process-pool/log.hh"
+#include "launchpad-process-pool/worker.hh"
 
 #define AUL_PR_NAME 16
 #define EXEC_CANDIDATE_EXPIRED 5
@@ -201,6 +202,22 @@ typedef int (*request_handler)(request_h request);
 
 namespace {
 
+class CleanupInfo : public launchpad::Worker::Job {
+ public:
+  CleanupInfo(std::string appid, pid_t pid)
+      : appid_(std::move(appid)), pid_(pid) {}
+
+  void Do() override {
+    _W("security_manager_cleanup_app() ++");
+    security_manager_cleanup_app(appid_.c_str(), getuid(), pid_);
+    _W("security_manager_cleanup_app() --");
+  }
+
+ private:
+  std::string appid_;
+  pid_t pid_;
+};
+
 int __sys_hwacc;
 std::unique_ptr<launchpad::LoaderInfoManager> loader_info_manager;
 std::unique_ptr<launchpad::LoaderInfoManager> app_defined_loader_info_manager;
@@ -220,8 +237,8 @@ io_channel_h __logger_channel;
 io_channel_h __label_monitor_channel;
 io_channel_h __launchpad_channel;
 int __client_fd = -1;
-worker_h __cleaner;
 launchpad::AsanAppChecker __asan_app_checker;
+std::unique_ptr<launchpad::Worker> cleaner;
 
 }  // namespace
 
@@ -1623,71 +1640,16 @@ static bool __handle_hydra_event(int fd, io_condition_e cond, void* data) {
   return true;
 }
 
-static void __destroy_cleanup_info(struct cleanup_info_s* info) {
-  if (!info)
-    return;
-
-  free(info->appid);
-  free(info);
-}
-
-static struct cleanup_info_s* __create_cleanup_info(const char* appid,
-                                                    int pid) {
-  struct cleanup_info_s* info;
-
-  info = static_cast<cleanup_info_s*>(malloc(sizeof(struct cleanup_info_s)));
-  if (!info) {
-    _E("Out of memory");
-    return nullptr;
-  }
-
-  info->appid = strdup(appid);
-  if (!info->appid) {
-    _E("strdup(%s) is failed", appid);
-    __destroy_cleanup_info(info);
-    return nullptr;
-  }
-
-  info->pid = pid;
-
-  return info;
-}
-
-static bool __cleanup_app_cb(void* user_data) {
-  struct cleanup_info_s* info = (struct cleanup_info_s*)user_data;
-
-  _W("security_manager_cleanup_app() ++");
-  security_manager_cleanup_app(info->appid, getuid(), info->pid);
-  _W("security_manager_cleanup_app() --");
-  __destroy_cleanup_info(info);
-  return false;
-}
-
 static void __handle_sigchild(int pid, void* user_data) {
-  candidate_process_context_t* cpc;
-  struct cleanup_info_s* info;
-  char* appid;
-  int ret = -1;
-
-  appid = static_cast<char*>(
+  char* appid = static_cast<char*>(
       g_hash_table_lookup(__pid_table, GINT_TO_POINTER(pid)));
   if (appid) {
-    info = __create_cleanup_info(appid, pid);
-    if (info)
-      ret = _worker_add_job(__cleaner, __cleanup_app_cb, info);
-
-    if (ret != 0) {
-      __destroy_cleanup_info(info);
-      _W("security_manager_cleanup_app() ++");
-      security_manager_cleanup_app(appid, getuid(), pid);
-      _W("security_manager_cleanup_app() --");
-    }
-
+    cleaner->Add(std::make_shared<CleanupInfo>(appid, pid));
     g_hash_table_remove(__pid_table, GINT_TO_POINTER(pid));
   }
 
   launchpad::Log::Print("[SIGCHLD]", "pid(%7d)", pid);
-  cpc = __find_slot_from_pid(pid);
+  candidate_process_context_t* cpc = __find_slot_from_pid(pid);
   if (cpc != nullptr) {
     cpc->pid = CANDIDATE_NONE;
     __dispose_candidate_process(cpc);
@@ -3420,23 +3382,19 @@ static int __before_loop(int argc, char** argv) {
     return -1;
   }
 
-  ret = _worker_create("cleaner+", &__cleaner);
-  if (ret < 0)
-    return ret;
-
   __register_vconf_events();
   __init_app_defined_loader_monitor();
+  cleaner.reset(new launchpad::Worker("cleaner+"));
   launchpad::Log::Init();
   _print_hwc_log("%s(%d): END", __FUNCTION__, __LINE__);
-
   return 0;
 }
 
 static void __after_loop(void) {
   launchpad::Log::Finish();
+  cleaner.reset();
   _memory_monitor_fini();
   __unregister_vconf_events();
-  _worker_destroy(__cleaner);
   if (__pid_table)
     g_hash_table_destroy(__pid_table);
 
index d08313b..13b6a0a 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <filesystem>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "launchpad-process-pool/launchpad_io_channel.h"
-#include "launchpad-process-pool/launchpad_worker.h"
 #include "lib/common/inc/launchpad_common.h"
 #include "lib/common/inc/launchpad_proc.h"
 #include "lib/common/inc/launchpad_socket.h"
 #include "lib/common/inc/log_private.h"
 
 #include "launchpad-process-pool/dbus.hh"
+#include "launchpad-process-pool/log_private.hh"
+#include "launchpad-process-pool/worker.hh"
+
+namespace fs = std::filesystem;
 
 namespace {
 
 constexpr const char HYDRA_SIGCHLD_SOCK[] = ".hydra-sigchld-sock";
 
+class GarbageCollector : public launchpad::Worker::Job {
+ public:
+  explicit GarbageCollector(pid_t pid) : pid_(pid) {}
+
+  void Do() override {
+    _W("pid: %d", pid_);
+    _delete_sock_path(pid_, getuid());
+    DeleteUnusedFiles();
+    SocketGarbadgeCollector();
+  }
+
+ private:
+  void SocketGarbadgeCollector() {
+    std::string path = "/run/aul/apps/" + std::to_string(getuid());
+    for (const auto &entry : fs::directory_iterator(path)) {
+      if (!isdigit(entry.path().filename().string()[0]))
+        continue;
+
+      std::string proc_path = "/proc/" + entry.path().filename().string();
+      if (access(proc_path.c_str(), F_OK) < 0) {
+        _delete_sock_path(atoi(entry.path().filename().string().c_str()),
+            getuid());
+      }
+    }
+  }
+
+  void DeleteUnusedFiles() {
+    std::vector<std::string> files = {
+        "clr-debug-pipe-" + std::to_string(pid_) + "-",
+        "dotnet-diagnostic-" + std::to_string(pid_) + "-"
+    };
+
+    fs::path tmp_path = "/tmp";
+    for (const auto &entry : fs::directory_iterator(tmp_path)) {
+      if (entry.is_directory() || entry.path().filename().string()[0] == '.')
+        continue;
+
+      bool found = false;
+      for (const auto &file : files) {
+        if (entry.path().filename().string().find(file) == 0) {
+          fs::remove(entry.path());
+          _W("Removed file: %s", entry.path().c_str());
+          found = true;
+          break;
+        }
+      }
+
+      if (!found)
+        continue;
+    }
+  }
+
+ private:
+  pid_t pid_;
+};
+
 pid_t __pid;
 sigset_t __mask;
 sigset_t __old_mask;
@@ -52,79 +113,16 @@ io_channel_h __hydra_sigchld_channel;
 signal_sigchld_cb __callback;
 void* __user_data;
 
-worker_h recycle_bin;
+std::unique_ptr<launchpad::Worker> recycle_bin;
 
 }  // namespace
 
 static gboolean __hydra_sigchld_recovery_cb(gpointer data);
 static gboolean __sigchld_recovery_cb(gpointer data);
 
-static void __socket_garbage_collector(void) {
-  DIR* dp;
-  struct dirent* dentry = nullptr;
-  char path[PATH_MAX];
-
-  snprintf(path, sizeof(path), "/run/aul/apps/%d", getuid());
-  dp = opendir(path);
-  if (!dp)
-    return;
-
-  while ((dentry = readdir(dp)) != nullptr) {
-    if (!isdigit(dentry->d_name[0]))
-      continue;
-
-    snprintf(path, sizeof(path), "/proc/%s", dentry->d_name);
-    if (access(path, F_OK) < 0)
-      _delete_sock_path(atoi(dentry->d_name), getuid());
-  }
-  closedir(dp);
-}
-
-static void __delete_unused_files(pid_t pid) {
-  std::vector<std::string> files = {
-    "clr-debug-pipe-" + std::to_string(pid) + "-",
-    "dotnet-diagnostic-" + std::to_string(pid) + "-"
-  };
-
-  DIR* dp = opendir("/tmp");
-  if (dp == nullptr) {
-    _E("opendir() is failed");
-    return;
-  }
-
-  struct dirent* dentry = nullptr;
-  while ((dentry = readdir(dp)) != nullptr) {
-    if (dentry->d_name[0] == '.')
-      continue;
-
-    if (dentry->d_name[0] != 'c' && dentry->d_name[0] != 'd')
-      continue;
-
-    for (size_t i = 0; i < files.size(); ++i) {
-      if (files[i].compare(0, files[i].length(), dentry->d_name, 0,
-              files[i].length()) == 0) {
-        std::string path = std::string("/tmp/") + dentry->d_name;
-        unlink(path.c_str());
-        _W("unlink(%s)", path.c_str());
-      }
-    }
-  }
-  closedir(dp);
-}
-
-static bool __garbage_collector(void *user_data) {
-  pid_t pid = GPOINTER_TO_INT(
-      reinterpret_cast<unsigned long>(user_data) & UINT32_MAX);
-  _W("pid(%d)", pid);
-  _delete_sock_path(pid, getuid());
-  __delete_unused_files(pid);
-  __socket_garbage_collector();
-  return false;
-}
-
 static void __sigchld_action(int pid) {
   launchpad::DBus::SendAppDeadSignal(pid);
-  _worker_add_job(recycle_bin, __garbage_collector, GINT_TO_POINTER(pid));
+  recycle_bin->Add(std::make_shared<GarbageCollector>(pid));
 }
 
 static int __check_permission(int pid) {
@@ -429,12 +427,7 @@ int _signal_init(void) {
     }
   }
 
-  ret = _worker_create("RecycleBin+", &recycle_bin);
-  if (ret < 0) {
-    _E("_worker_create() is failed");
-    return ret;
-  }
-
+  recycle_bin.reset(new launchpad::Worker("RecycleBin+"));
   return 0;
 }
 
@@ -447,9 +440,7 @@ void _signal_fini(void) {
 #endif
 
   _D("SIGNAL_FINI");
-  if (getpid() == __pid)
-    _worker_destroy(recycle_bin);
-
+  recycle_bin.reset();
   _signal_set_sigchld_cb(nullptr, nullptr);
   __hydra_sigchld_fini();
   __sigchld_fini();
diff --git a/src/launchpad-process-pool/launchpad_worker.cc b/src/launchpad-process-pool/launchpad_worker.cc
deleted file mode 100644 (file)
index 4729e48..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "launchpad-process-pool/launchpad_worker.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <glib.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "lib/common/inc/log_private.h"
-
-struct job_s {
-  worker_job_cb callback;
-  void* user_data;
-};
-
-struct worker_s {
-  char* name;
-  GThread* thread;
-  GMutex mutex;
-  GCond cond;
-  GQueue* queue;
-};
-
-int _worker_add_job(worker_h worker, worker_job_cb callback, void* user_data) {
-  struct job_s* job;
-
-  if (!worker || !callback) {
-    _E("Invalid parameter");
-    return -EINVAL;
-  }
-
-  job = static_cast<job_s*>(malloc(sizeof(job_s)));
-  if (!job) {
-    _E("Out of memory");
-    return -ENOMEM;
-  }
-
-  job->callback = callback;
-  job->user_data = user_data;
-
-  g_mutex_lock(&worker->mutex);
-  g_queue_push_tail(worker->queue, job);
-  g_cond_signal(&worker->cond);
-  g_mutex_unlock(&worker->mutex);
-
-  return 0;
-}
-
-static int __set_comm(const char* name) {
-  int fd;
-  ssize_t bytes_written;
-  char path[PATH_MAX];
-  pid_t tid = syscall(__NR_gettid);
-
-  _I("[%s] TID(%d)", name, tid);
-  snprintf(path, sizeof(path), "/proc/%d/comm", tid);
-  fd = open(path, O_WRONLY);
-  if (fd < 0) {
-    _E("Failed to open %s. error(%d)", path, errno);
-    return -1;
-  }
-
-  bytes_written = write(fd, name, strlen(name) + 1);
-  if (bytes_written < 0) {
-    _E("Failed to write name(%s)", name);
-    close(fd);
-    return -1;
-  }
-
-  close(fd);
-  return 0;
-}
-
-static gpointer __worker_thread_cb(gpointer data) {
-  struct worker_s* worker = (struct worker_s*)data;
-  struct job_s* job;
-  bool done = false;
-
-  __set_comm(worker->name);
-  do {
-    g_mutex_lock(&worker->mutex);
-    if (g_queue_is_empty(worker->queue))
-      g_cond_wait(&worker->cond, &worker->mutex);
-
-    job = (struct job_s*)g_queue_pop_head(worker->queue);
-    g_mutex_unlock(&worker->mutex);
-    done = job->callback(job->user_data);
-    free(job);
-  } while (!done);
-
-  return NULL;
-}
-
-int _worker_create(const char* name, worker_h* worker) {
-  struct worker_s* handle;
-
-  if (name == NULL || worker == NULL) {
-    _E("Invalid parameter");
-    return -EINVAL;
-  }
-
-  handle = static_cast<worker_s*>(calloc(1, sizeof(worker_s)));
-  if (handle == NULL) {
-    _E("calloc() is failed");
-    return -ENOMEM;
-  }
-
-  g_mutex_init(&handle->mutex);
-  g_cond_init(&handle->cond);
-
-  handle->name = strdup(name);
-  if (!handle->name) {
-    _E("strdup() is failed");
-    _worker_destroy(handle);
-    return -ENOMEM;
-  }
-
-  handle->queue = g_queue_new();
-  if (!handle->queue) {
-    _E("g_queue_new() is failed");
-    _worker_destroy(handle);
-    return -ENOMEM;
-  }
-
-  handle->thread = g_thread_new(name, __worker_thread_cb, handle);
-  if (!handle->thread) {
-    _E("g_thread_new() is failed");
-    _worker_destroy(handle);
-    return -ENOMEM;
-  }
-
-  *worker = handle;
-  return 0;
-}
-
-static bool __worker_done_cb(void* user_data) {
-  _W("Done");
-  return true;
-}
-
-void _worker_destroy(worker_h worker) {
-  if (worker == NULL)
-    return;
-
-  if (worker->thread) {
-    _worker_add_job(worker, __worker_done_cb, NULL);
-    g_thread_join(worker->thread);
-  }
-
-  if (worker->queue)
-    g_queue_free_full(worker->queue, (GDestroyNotify)free);
-
-  if (worker->name)
-    free(worker->name);
-
-  g_cond_clear(&worker->cond);
-  g_mutex_clear(&worker->mutex);
-  free(worker);
-}
diff --git a/src/launchpad-process-pool/launchpad_worker.h b/src/launchpad-process-pool/launchpad_worker.h
deleted file mode 100644 (file)
index 0276545..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __LAUNCHPAD_WORKER_H__
-#define __LAUNCHPAD_WORKER_H__
-
-#include <stdbool.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct worker_s *worker_h;
-
-typedef bool (*worker_job_cb)(void *user_data);
-
-int _worker_add_job(worker_h worker, worker_job_cb callback, void *user_data);
-
-int _worker_create(const char *name, worker_h *worker);
-
-void _worker_destroy(worker_h worker);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __LAUNCHPAD_WORKER_H__ */
diff --git a/src/launchpad-process-pool/worker.cc b/src/launchpad-process-pool/worker.cc
new file mode 100644 (file)
index 0000000..28e3596
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "launchpad-process-pool/worker.hh"
+
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include <exception.hh>
+
+#include "launchpad-process-pool/log_private.hh"
+
+namespace launchpad {
+namespace {
+
+const pid_t current_pid = getpid();
+
+class Ender : public Worker::Job {
+ public:
+  bool IsDone() override { return true; }
+};
+
+}  // namespace
+
+Worker::Worker(std::string name) : name_(std::move(name)) {
+  thread_ = std::thread([&]() -> void { RunThread(); });
+}
+
+Worker::~Worker() {
+  if (getpid() == current_pid) {
+    Add(std::make_shared<Ender>());
+    thread_.join();
+  }
+}
+
+void Worker::Add(std::shared_ptr<Worker::Job >job) {
+  queue_.Push(std::move(job));
+}
+
+void Worker::SetComm() {
+  const std::string path = "/proc/" + std::to_string(gettid()) + "/comm";
+  std::ofstream comm_file;
+  comm_file.open(path);
+  if (!comm_file.is_open()) {
+    _E("Failed to open %s", path.c_str());
+    return;
+  }
+
+  comm_file << name_;
+  comm_file.close();
+}
+
+void Worker::RunThread() {
+  _W("BEGIN");
+  SetComm();
+  while (true) {
+    auto job = queue_.WaitAndPop();
+    job->Do();
+    if (job->IsDone())
+      break;
+  }
+  _W("END");
+}
+
+}  // namespace launchpad
diff --git a/src/launchpad-process-pool/worker.hh b/src/launchpad-process-pool/worker.hh
new file mode 100644 (file)
index 0000000..ed12083
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef LAUNCHPAD_PROCESS_POOL_WORKER_HH_
+#define LAUNCHPAD_PROCESS_POOL_WORKER_HH_
+
+#include <memory>
+#include <string>
+#include <thread>
+#include <utility>
+
+#include <shared-queue.hpp>
+
+namespace launchpad {
+
+class Worker {
+ public:
+  class Job {
+   public:
+    virtual ~Job() = default;
+    virtual void Do() {}
+    virtual bool IsDone() { return false; }
+  };
+
+  explicit Worker(std::string name);
+  virtual ~Worker();
+
+  void Add(std::shared_ptr<Worker::Job> job);
+
+ private:
+  void SetComm();
+  void RunThread();
+
+ private:
+  std::string name_;
+  std::thread thread_;
+  tizen_base::SharedQueue<std::shared_ptr<Job>> queue_;
+};
+
+}  // namespace launchpad
+
+#endif  // LAUNCHPAD_PROCESS_POOL_WORKER_HH_