diff options
-rw-r--r-- | common/Makefile | 1 | ||||
-rw-r--r-- | common/hush.c | 6 | ||||
-rw-r--r-- | common/poller.c | 9 | ||||
-rw-r--r-- | common/slice.c | 32 | ||||
-rw-r--r-- | common/startup.c | 3 | ||||
-rw-r--r-- | common/workqueue.c | 58 | ||||
-rw-r--r-- | include/slice.h | 5 | ||||
-rw-r--r-- | include/work.h | 29 |
8 files changed, 143 insertions, 0 deletions
diff --git a/common/Makefile b/common/Makefile index 58594d9782..99f1977b4b 100644 --- a/common/Makefile +++ b/common/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ELF) += elf.o obj-y += restart.o obj-y += poweroff.o obj-y += slice.o +obj-y += workqueue.o obj-$(CONFIG_MACHINE_ID) += machine_id.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o obj-y += version.o diff --git a/common/hush.c b/common/hush.c index c24b2c7cd2..ec0d5129b7 100644 --- a/common/hush.c +++ b/common/hush.c @@ -121,6 +121,7 @@ #include <libbb.h> #include <password.h> #include <glob.h> +#include <slice.h> #include <getopt.h> #include <libfile.h> #include <libbb.h> @@ -460,7 +461,12 @@ static void get_user_input(struct in_str *i) else prompt = CONFIG_PROMPT_HUSH_PS2; + command_slice_release(); + n = readline(prompt, console_buffer, CONFIG_CBSIZE); + + command_slice_acquire(); + if (n == -1 ) { i->interrupt = 1; n = 0; diff --git a/common/poller.c b/common/poller.c index 95f828b439..7b1b92714c 100644 --- a/common/poller.c +++ b/common/poller.c @@ -12,6 +12,8 @@ #include <param.h> #include <poller.h> #include <clock.h> +#include <work.h> +#include <slice.h> static LIST_HEAD(poller_list); static int poller_active; @@ -110,15 +112,22 @@ int poller_async_unregister(struct poller_async *pa) void poller_call(void) { struct poller_struct *poller, *tmp; + bool run_workqueues = !slice_acquired(&command_slice); if (poller_active) return; + command_slice_acquire(); + + if (run_workqueues) + wq_do_all_works(); + poller_active = 1; list_for_each_entry_safe(poller, tmp, &poller_list, list) poller->func(poller); + command_slice_release(); poller_active = 0; } diff --git a/common/slice.c b/common/slice.c index 085d67604f..9d7e0d16cf 100644 --- a/common/slice.c +++ b/common/slice.c @@ -3,6 +3,7 @@ #define pr_fmt(fmt) "slice: " fmt #include <common.h> +#include <init.h> #include <slice.h> /* @@ -231,6 +232,37 @@ void slice_exit(struct slice *slice) free(slice->name); } +struct slice command_slice; + +/** + * command_slice_acquire - acquire the command slice + * + * The command slice is acquired by default. It is only released + * at certain points we know it's safe to execute code in the + * background, like when the shell is waiting for input. + */ +void command_slice_acquire(void) +{ + slice_acquire(&command_slice); +} + +/** + * command_slice_release - release the command slice + */ +void command_slice_release(void) +{ + slice_release(&command_slice); +} + +static int command_slice_init(void) +{ + slice_init(&command_slice, "command"); + slice_acquire(&command_slice); + return 0; +} + +pure_initcall(command_slice_init); + #if defined CONFIG_CMD_SLICE #include <command.h> diff --git a/common/startup.c b/common/startup.c index 1c58e41288..075863d22e 100644 --- a/common/startup.c +++ b/common/startup.c @@ -34,6 +34,7 @@ #include <debug_ll.h> #include <fs.h> #include <errno.h> +#include <slice.h> #include <linux/stat.h> #include <envfs.h> #include <magicvar.h> @@ -272,8 +273,10 @@ enum autoboot_state do_autoboot_countdown(void) break; } + command_slice_release(); ret = console_countdown(global_autoboot_timeout, flags, abortkeys, &outkey); + command_slice_acquire(); if (ret == 0) autoboot_state = AUTOBOOT_BOOT; diff --git a/common/workqueue.c b/common/workqueue.c new file mode 100644 index 0000000000..6fdd4e42ea --- /dev/null +++ b/common/workqueue.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <common.h> +#include <work.h> + +static void wq_do_pending_work(struct work_queue *wq) +{ + struct work_struct *work, *tmp; + + list_for_each_entry_safe(work, tmp, &wq->work, list) { + list_del(&work->list); + wq->fn(work); + } +} + +void wq_cancel_work(struct work_queue *wq) +{ + struct work_struct *work, *tmp; + + list_for_each_entry_safe(work, tmp, &wq->work, list) { + list_del(&work->list); + wq->cancel(work); + } +} + +static LIST_HEAD(work_queues); + +/** + * wq_do_all_works - do all pending work + * + * This calls all pending work functions + */ +void wq_do_all_works(void) +{ + struct work_queue *wq; + + list_for_each_entry(wq, &work_queues, list) + wq_do_pending_work(wq); +} + +/** + * wq_register - register a new work queue + * @wq: The work queue + */ +void wq_register(struct work_queue *wq) +{ + INIT_LIST_HEAD(&wq->work); + list_add_tail(&wq->list, &work_queues); +} + +/** + * wq_unregister - unregister a work queue + * @wq: The work queue + */ +void wq_unregister(struct work_queue *wq) +{ + wq_cancel_work(wq); + list_del(&wq->list); +} diff --git a/include/slice.h b/include/slice.h index 5538fc434a..fd753e194b 100644 --- a/include/slice.h +++ b/include/slice.h @@ -28,4 +28,9 @@ void slice_exit(struct slice *slice); void slice_debug_acquired(struct slice *slice); +extern struct slice command_slice; + +void command_slice_acquire(void); +void command_slice_release(void); + #endif /* __SLICE_H */ diff --git a/include/work.h b/include/work.h new file mode 100644 index 0000000000..e428e821ea --- /dev/null +++ b/include/work.h @@ -0,0 +1,29 @@ +#ifndef __WORK_H +#define __WORK_H + +#include <linux/list.h> + +struct work_struct { + struct list_head list; +}; + +struct work_queue { + void (*fn)(struct work_struct *work); + void (*cancel)(struct work_struct *work); + + struct list_head list; + struct list_head work; +}; + +static inline void wq_queue_work(struct work_queue *wq, struct work_struct *work) +{ + list_add_tail(&work->list, &wq->work); +} + +void wq_register(struct work_queue *wq); +void wq_unregister(struct work_queue *wq); + +void wq_do_all_works(void); +void wq_cancel_work(struct work_queue *wq); + +#endif /* __WORK_H */ |