Magisk/native/jni/core/thread.cpp

98 lines
2.8 KiB
C++
Raw Normal View History

2021-08-24 09:39:54 +00:00
// Cached thread pool implementation
#include <utils.hpp>
2021-09-20 11:42:06 +00:00
#include <daemon.hpp>
2021-08-24 09:39:54 +00:00
using namespace std;
#define THREAD_IDLE_MAX_SEC 60
#define CORE_POOL_SIZE 3
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
2021-10-17 11:24:25 +00:00
static pthread_cond_t send_task = PTHREAD_COND_INITIALIZER_MONOTONIC_NP;
static pthread_cond_t recv_task = PTHREAD_COND_INITIALIZER_MONOTONIC_NP;
2021-08-24 09:39:54 +00:00
// The following variables should be guarded by lock
static int idle_threads = 0;
static int total_threads = 0;
2021-08-24 09:39:54 +00:00
static function<void()> pending_task;
2021-10-17 11:24:25 +00:00
static void operator+=(timespec &a, const timespec &b) {
2021-08-24 09:39:54 +00:00
a.tv_sec += b.tv_sec;
2021-10-17 11:24:25 +00:00
a.tv_nsec += b.tv_nsec;
if (a.tv_nsec >= 1000000000L) {
2021-08-24 09:39:54 +00:00
a.tv_sec++;
2021-10-17 11:24:25 +00:00
a.tv_nsec -= 1000000000L;
2021-08-24 09:39:54 +00:00
}
}
2021-10-17 11:24:25 +00:00
static void reset_pool() {
clear_poll();
pthread_mutex_unlock(&lock);
pthread_mutex_destroy(&lock);
pthread_mutex_init(&lock, nullptr);
pthread_cond_destroy(&send_task);
send_task = PTHREAD_COND_INITIALIZER_MONOTONIC_NP;
pthread_cond_destroy(&recv_task);
recv_task = PTHREAD_COND_INITIALIZER_MONOTONIC_NP;
idle_threads = 0;
total_threads = 0;
2021-10-17 11:24:25 +00:00
pending_task = nullptr;
}
2021-08-24 09:39:54 +00:00
static void *thread_pool_loop(void * const is_core_pool) {
2021-10-17 11:24:25 +00:00
pthread_atfork(nullptr, nullptr, &reset_pool);
2021-08-24 09:39:54 +00:00
// Block all signals
sigset_t mask;
sigfillset(&mask);
for (;;) {
// Restore sigmask
pthread_sigmask(SIG_SETMASK, &mask, nullptr);
function<void()> local_task;
{
mutex_guard g(lock);
++idle_threads;
2021-08-24 09:39:54 +00:00
if (!pending_task) {
if (is_core_pool) {
pthread_cond_wait(&send_task, &lock);
} else {
2021-10-17 11:24:25 +00:00
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts += { THREAD_IDLE_MAX_SEC, 0 };
2021-08-24 09:39:54 +00:00
if (pthread_cond_timedwait(&send_task, &lock, &ts) == ETIMEDOUT) {
// Terminate thread after max idle time
--idle_threads;
--total_threads;
2021-08-24 09:39:54 +00:00
return nullptr;
}
}
}
if (pending_task) {
local_task.swap(pending_task);
pthread_cond_signal(&recv_task);
}
--idle_threads;
2021-08-24 09:39:54 +00:00
}
if (local_task)
local_task();
2021-10-17 11:24:25 +00:00
if (getpid() == gettid())
exit(0);
2021-08-24 09:39:54 +00:00
}
}
void exec_task(function<void()> &&task) {
mutex_guard g(lock);
pending_task.swap(task);
if (idle_threads == 0) {
++total_threads;
long is_core_pool = total_threads <= CORE_POOL_SIZE;
new_daemon_thread(thread_pool_loop, (void *) is_core_pool);
2021-08-24 09:39:54 +00:00
} else {
pthread_cond_signal(&send_task);
}
pthread_cond_wait(&recv_task, &lock);
2021-08-24 09:39:54 +00:00
}