+
+static int shrinker_thread(void *arg)
+{
+ while (!kthread_should_stop()) {
+ struct timespec to;
+ int v;
+
+ clock_gettime(CLOCK_MONOTONIC, &to);
+ to.tv_sec += 1;
+ __set_current_state(TASK_INTERRUPTIBLE);
+ errno = 0;
+ while ((v = READ_ONCE(current->state)) != TASK_RUNNING &&
+ errno != ETIMEDOUT)
+ futex(¤t->state, FUTEX_WAIT_BITSET|FUTEX_PRIVATE_FLAG,
+ v, &to, NULL, (uint32_t)~0);
+ if (kthread_should_stop())
+ break;
+ if (v != TASK_RUNNING)
+ __set_current_state(TASK_RUNNING);
+ run_shrinkers(GFP_KERNEL, false);
+ }
+
+ return 0;
+}
+
+struct task_struct *shrinker_task;
+
+__attribute__((constructor(103)))
+static void shrinker_thread_init(void)
+{
+ shrinker_task = kthread_run(shrinker_thread, NULL, "shrinkers");
+ BUG_ON(IS_ERR(shrinker_task));
+}
+
+__attribute__((destructor(103)))
+static void shrinker_thread_exit(void)
+{
+ int ret = kthread_stop(shrinker_task);
+ BUG_ON(ret);
+
+ shrinker_task = NULL;
+}