diff options
| author | Shell <[email protected]> | 2024-11-12 17:47:51 +0800 |
|---|---|---|
| committer | Rbb666 <[email protected]> | 2025-01-06 19:34:16 +0800 |
| commit | 944f3d05b508d5eaeaabd8f5d2964847c80dbc3e (patch) | |
| tree | 88e5495e34196d59c5a15b2459769e82bda73c3e | |
| parent | 972931c991e432a1030205959f4be4351a5710d6 (diff) | |
feat: add system reboot and process teardown support
The patch introduces support for system reboot functionality and process teardown,
allowing for a clean shutdown and unmounting of the root filesystem. This is
necessary for ensuring a proper system shutdown process, especially when dealing
with resource cleanup and ensuring that all processes have exited before system
shutdown.
Changes:
- Added `lwp_teardown()` function to handle process cleanup and system teardown.
- Introduced `lwp_pid_wait_for_empty()` to wait for process ID table emptiness
before proceeding with shutdown.
- Updated `dfs_mnt_unref()` to trigger callbacks when unmounting a filesystem.
- Added new reboot types (`RB_AUTOBOOT`, `RB_POWER_OFF`) and implemented their
corresponding actions, including cleanup of processes and unmounting root
filesystem.
- Extended `sys_reboot()` to handle reboot and power off types with appropriate
callbacks for process and filesystem teardown.
- Introduced callback mechanism for root filesystem unmount notifications.
Signed-off-by: Shell <[email protected]>
| -rw-r--r-- | components/dfs/dfs_v2/include/dfs_mnt.h | 3 | ||||
| -rw-r--r-- | components/dfs/dfs_v2/src/dfs_mnt.c | 4 | ||||
| -rw-r--r-- | components/lwp/libc_musl.h | 9 | ||||
| -rw-r--r-- | components/lwp/lwp.h | 2 | ||||
| -rw-r--r-- | components/lwp/lwp_pid.c | 35 | ||||
| -rw-r--r-- | components/lwp/lwp_pid.h | 2 | ||||
| -rw-r--r-- | components/lwp/lwp_runtime.c | 50 | ||||
| -rw-r--r-- | components/lwp/lwp_syscall.c | 19 |
8 files changed, 117 insertions, 7 deletions
diff --git a/components/dfs/dfs_v2/include/dfs_mnt.h b/components/dfs/dfs_v2/include/dfs_mnt.h index 207c9b6bfd..05a7458e92 100644 --- a/components/dfs/dfs_v2/include/dfs_mnt.h +++ b/components/dfs/dfs_v2/include/dfs_mnt.h @@ -64,6 +64,9 @@ rt_bool_t dfs_mnt_has_child_mnt(struct dfs_mnt *mnt, const char* fullpath); int dfs_mnt_foreach(struct dfs_mnt* (*func)(struct dfs_mnt *mnt, void *parameter), void *parameter); +typedef void (*dfs_mnt_umnt_cb_t)(struct dfs_mnt *mnt); +RT_OBJECT_HOOKLIST_DECLARE(dfs_mnt_umnt_cb_t, dfs_mnt_umnt); + #ifdef __cplusplus } #endif diff --git a/components/dfs/dfs_v2/src/dfs_mnt.c b/components/dfs/dfs_v2/src/dfs_mnt.c index 4ad73c6dee..dfae5d12ee 100644 --- a/components/dfs/dfs_v2/src/dfs_mnt.c +++ b/components/dfs/dfs_v2/src/dfs_mnt.c @@ -21,6 +21,8 @@ static struct dfs_mnt *_root_mnt = RT_NULL; +RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt); + /* * mnt tree structure * @@ -257,6 +259,8 @@ int dfs_mnt_unref(struct dfs_mnt* mnt) if (mnt->flags & MNT_IS_UMOUNT) { mnt->fs_ops->umount(mnt); + + RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt)); } /* free full path */ diff --git a/components/lwp/libc_musl.h b/components/lwp/libc_musl.h index fbc2ad5cb4..586fd4961d 100644 --- a/components/lwp/libc_musl.h +++ b/components/lwp/libc_musl.h @@ -11,6 +11,15 @@ #ifndef __LIBC_MUSL_H__ #define __LIBC_MUSL_H__ +/* from reboot.h */ +#define RB_AUTOBOOT 0x01234567 +#define RB_HALT_SYSTEM 0xcdef0123 +#define RB_ENABLE_CAD 0x89abcdef +#define RB_DISABLE_CAD 0 +#define RB_POWER_OFF 0x4321fedc +#define RB_SW_SUSPEND 0xd000fce2 +#define RB_KEXEC 0x45584543 + /* from internal/futex.h */ #define FUTEX_WAIT 0 diff --git a/components/lwp/lwp.h b/components/lwp/lwp.h index 24b4150270..2c95deea74 100644 --- a/components/lwp/lwp.h +++ b/components/lwp/lwp.h @@ -340,6 +340,8 @@ int lwp_session_set_foreground(rt_session_t session, pid_t pgid); /* complete the job control related bussiness on process exit */ void lwp_jobctrl_on_exit(struct rt_lwp *lwp); +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)); + #ifdef __cplusplus } #endif diff --git a/components/lwp/lwp_pid.c b/components/lwp/lwp_pid.c index f127c591c0..e45554434d 100644 --- a/components/lwp/lwp_pid.c +++ b/components/lwp/lwp_pid.c @@ -69,13 +69,30 @@ static int lwp_pid_ary_alloced = 0; static struct lwp_avl_struct *lwp_pid_root = RT_NULL; static pid_t current_pid = 0; static struct rt_mutex pid_mtx; +static struct rt_wqueue _pid_emptyq; int lwp_pid_init(void) { + rt_wqueue_init(&_pid_emptyq); rt_mutex_init(&pid_mtx, "pidmtx", RT_IPC_FLAG_PRIO); return 0; } +int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to) +{ + int error; + + if (wait_flags == RT_INTERRUPTIBLE) + { + error = rt_wqueue_wait_interruptible(&_pid_emptyq, 0, to); + } + else + { + error = rt_wqueue_wait_killable(&_pid_emptyq, 0, to); + } + return error; +} + void lwp_pid_lock_take(void) { LWP_DEF_RETURN_CODE(rc); @@ -211,7 +228,15 @@ void lwp_pid_put(struct rt_lwp *lwp) lwp_pid_lock_take(); lwp_pid_put_locked(lwp->pid); - lwp_pid_lock_release(); + if (lwp_pid_root == AVL_EMPTY) + { + rt_wqueue_wakeup_all(&_pid_emptyq, RT_NULL); + /* refuse any new pid allocation now */ + } + else + { + lwp_pid_lock_release(); + } /* reset pid field */ lwp->pid = 0; @@ -1539,6 +1564,7 @@ static void _notify_parent(rt_lwp_t lwp) static void _resr_cleanup(struct rt_lwp *lwp) { + int need_cleanup_pid = RT_FALSE; lwp_jobctrl_on_exit(lwp); LWP_LOCK(lwp); @@ -1608,7 +1634,7 @@ static void _resr_cleanup(struct rt_lwp *lwp) * if process is orphan, it doesn't have parent to do the recycling. * Otherwise, its parent had setup a flag to mask out recycling event */ - lwp_pid_put(lwp); + need_cleanup_pid = RT_TRUE; } LWP_LOCK(lwp); @@ -1628,6 +1654,11 @@ static void _resr_cleanup(struct rt_lwp *lwp) { LWP_UNLOCK(lwp); } + + if (need_cleanup_pid) + { + lwp_pid_put(lwp); + } } static int _lwp_setaffinity(int tid, int cpu) diff --git a/components/lwp/lwp_pid.h b/components/lwp/lwp_pid.h index ae9d712422..826f7a9105 100644 --- a/components/lwp/lwp_pid.h +++ b/components/lwp/lwp_pid.h @@ -26,7 +26,7 @@ struct rt_lwp; struct lwp_avl_struct *lwp_get_pid_ary(void); int lwp_pid_init(void); - +int lwp_pid_wait_for_empty(int wait_flags, rt_tick_t to); int lwp_pid_for_each(int (*cb)(pid_t pid, void *data), void *data); void lwp_pid_put(struct rt_lwp *lwp); void lwp_pid_lock_take(void); diff --git a/components/lwp/lwp_runtime.c b/components/lwp/lwp_runtime.c index ebd6986f5b..34174d63c3 100644 --- a/components/lwp/lwp_runtime.c +++ b/components/lwp/lwp_runtime.c @@ -109,3 +109,53 @@ static int lwp_startup(void) return error; } INIT_APP_EXPORT(lwp_startup); + +/* don't use heap for safety */ +static struct rt_work _teardown_work; + +#define INIT_PID 1 +static void _teardown_entry(struct rt_work *work, void *work_data) +{ + int error; + void (*cb_on_reboot)(void) = work_data; + + /* cleanup of process */ + do + { + error = lwp_pid_wait_for_empty(RT_KILLABLE, RT_WAITING_FOREVER); + } + while (error); + LOG_I("All processes exited"); + + cb_on_reboot(); + return; +} + +static int _get_parent_pid(struct rt_lwp *lwp) +{ + return lwp->parent ? lwp->parent->pid : 0; +} + +/* reverse operation of lwp_startup() */ +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)) +{ + struct rt_work *work; + + if (lwp->pid != INIT_PID && _get_parent_pid(lwp) != INIT_PID) + { + /* The calling process has insufficient privilege */ + return -EPERM; + } + + work = &_teardown_work; + rt_work_init(work, _teardown_entry, cb); + +#define SOME_DELAY (RT_TICK_PER_SECOND / 10) /* allow idle to cleanup resource */ + rt_work_submit(work, SOME_DELAY); + + lwp_exit(lwp, LWP_CREATE_STAT_EXIT(EXIT_SUCCESS)); + + /* never return */ + RT_ASSERT(0); + return 0; +} diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c index 07d2697958..22aa85a779 100644 --- a/components/lwp/lwp_syscall.c +++ b/components/lwp/lwp_syscall.c @@ -6171,16 +6171,27 @@ sysret_t sys_chown(const char *pathname, uid_t owner, gid_t group) return (ret < 0 ? GET_ERRNO() : ret); } -#include <sys/reboot.h> -sysret_t sys_reboot(int magic, int magic2, int type) +#ifndef LWP_USING_RUNTIME +sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void)) +{ + /* if no LWP_USING_RUNTIME configured */ + return -ENOSYS; +} +#endif + +sysret_t sys_reboot(int magic, int magic2, int type, void *arg) { sysret_t rc; switch (type) { - /* TODO add software poweroff protocols */ + /* Hardware reset */ case RB_AUTOBOOT: + rc = lwp_teardown(lwp_self(), rt_hw_cpu_reset); + break; + + /* Stop system and switch power off */ case RB_POWER_OFF: - rt_hw_cpu_reset(); + rc = lwp_teardown(lwp_self(), rt_hw_cpu_shutdown); break; default: rc = -ENOSYS; |
