bundle *launchpad_loader_get_bundle(void);
+/**
+ * @brief Blocks all sub threads of the loader.
+ * @remarks This function has to be called in the main thread.
+ *
+ * @return @c on success,
+ * otherwise a negative error value
+ *
+ * @see #launchpad_loader_unblock_threads()
+ */
+int launchpad_loader_block_threads(void);
+
+/**
+ * @brief Unblocks all sub threads of the loader.
+ * @remarks This function has to be called in the main thread.
+ *
+ * @return @c on success,
+ * otherwise a negative error value
+ * @see #launchpad_loader_block_threads()
+ */
+int launchpad_loader_unblock_threads(void);
+
#ifdef __cplusplus
}
#endif
#endif
#define AUL_PR_NAME 16
+#define SIGRTINT (SIGRTMIN + 2)
+
+typedef struct thread_handler_s {
+ struct sigaction old;
+ GMutex mutex;
+ GCond cond;
+ gint count;
+ gint num;
+ bool blocked;
+ bool done;
+} thread_handler_t;
static loader_lifecycle_callback_s *__loader_callbacks;
static loader_adapter_s *__loader_adapter;
static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
static int __loader_id;
static bool __loop_quit;
+static thread_handler_t __thread_handler;
static void __at_exit_to_release_bundle(void)
{
{
return _set_priority(prio);
}
+
+static void __signal_handler(int signo)
+{
+ _D("Block thread");
+ g_mutex_lock(&__thread_handler.mutex);
+ g_atomic_int_set(&__thread_handler.count,
+ g_atomic_int_get(&__thread_handler.count) - 1);
+ while (!__thread_handler.done)
+ g_cond_wait(&__thread_handler.cond, &__thread_handler.mutex);
+ g_mutex_unlock(&__thread_handler.mutex);
+ g_atomic_int_inc(&__thread_handler.count);
+ _D("Unblock thread");
+}
+
+API int launchpad_loader_block_threads(void)
+{
+ struct sigaction act;
+ struct dirent *dentry;
+ DIR *dp;
+ pid_t pid = getpid();
+ pid_t tid;
+ gint i;
+
+ if (__thread_handler.blocked) {
+ _D("Already blocked");
+ return 0;
+ }
+
+ g_mutex_init(&__thread_handler.mutex);
+ g_cond_init(&__thread_handler.cond);
+
+ memset(&act, '\0', sizeof(act));
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ act.sa_handler = __signal_handler;
+
+ if (sigaction(SIGRTINT, &act, &__thread_handler.old) != 0) {
+ _E("sigaction() is failed. errno(%d)", errno);
+ return -1;
+ }
+
+ __thread_handler.done = false;
+ __thread_handler.count = 0;
+ __thread_handler.num = 0;
+
+ dp = opendir("/proc/self/task");
+ if (dp == NULL) {
+ _E("opendir() is failed. errno(%d)", errno);
+ sigaction(SIGRTINT, &__thread_handler.old, NULL);
+ return -1;
+ }
+
+ while ((dentry = readdir(dp)) != NULL) {
+ if (!isdigit(dentry->d_name[0]))
+ continue;
+
+ tid = atoi(dentry->d_name);
+ if (tid != pid) {
+ _D("Send signal to thread(%d)", tid);
+ if (tgkill(pid, tid, SIGRTINT) != 0) {
+ _E("tgkill() is failed. errno(%d)", errno);
+ } else {
+ g_atomic_int_inc(&__thread_handler.count);
+ __thread_handler.num++;
+ }
+ }
+ }
+ closedir(dp);
+
+ for (i = 1000; g_atomic_int_get(&__thread_handler.count) && i; --i)
+ usleep(2000);
+
+ __thread_handler.blocked = true;
+
+ return 0;
+}
+
+API int launchpad_loader_unblock_threads(void)
+{
+ gint i;
+
+ if (!__thread_handler.blocked)
+ return 0;
+
+ g_mutex_lock(&__thread_handler.mutex);
+ __thread_handler.done = true;
+ g_cond_broadcast(&__thread_handler.cond);
+ g_mutex_unlock(&__thread_handler.mutex);
+
+ for (i = 1000; g_atomic_int_get(&__thread_handler.count) != __thread_handler.num && i; --i)
+ usleep(2000);
+
+ sigaction(SIGRTINT, &__thread_handler.old, NULL);
+ g_mutex_clear(&__thread_handler.mutex);
+ g_cond_clear(&__thread_handler.cond);
+ __thread_handler.blocked = false;
+
+ return 0;
+}