mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-05-30 02:57:51 +08:00
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 <smokewood@qq.com>
This commit is contained in:
@@ -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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
static struct dfs_mnt *_root_mnt = RT_NULL;
|
static struct dfs_mnt *_root_mnt = RT_NULL;
|
||||||
|
|
||||||
|
RT_OBJECT_HOOKLIST_DEFINE(dfs_mnt_umnt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* mnt tree structure
|
* mnt tree structure
|
||||||
*
|
*
|
||||||
@@ -257,6 +259,8 @@ int dfs_mnt_unref(struct dfs_mnt* mnt)
|
|||||||
if (mnt->flags & MNT_IS_UMOUNT)
|
if (mnt->flags & MNT_IS_UMOUNT)
|
||||||
{
|
{
|
||||||
mnt->fs_ops->umount(mnt);
|
mnt->fs_ops->umount(mnt);
|
||||||
|
|
||||||
|
RT_OBJECT_HOOKLIST_CALL(dfs_mnt_umnt, (mnt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free full path */
|
/* free full path */
|
||||||
|
|||||||
@@ -11,6 +11,15 @@
|
|||||||
#ifndef __LIBC_MUSL_H__
|
#ifndef __LIBC_MUSL_H__
|
||||||
#define __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 */
|
/* from internal/futex.h */
|
||||||
|
|
||||||
#define FUTEX_WAIT 0
|
#define FUTEX_WAIT 0
|
||||||
|
|||||||
@@ -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 */
|
/* complete the job control related bussiness on process exit */
|
||||||
void lwp_jobctrl_on_exit(struct rt_lwp *lwp);
|
void lwp_jobctrl_on_exit(struct rt_lwp *lwp);
|
||||||
|
|
||||||
|
sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void));
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -69,13 +69,30 @@ static int lwp_pid_ary_alloced = 0;
|
|||||||
static struct lwp_avl_struct *lwp_pid_root = RT_NULL;
|
static struct lwp_avl_struct *lwp_pid_root = RT_NULL;
|
||||||
static pid_t current_pid = 0;
|
static pid_t current_pid = 0;
|
||||||
static struct rt_mutex pid_mtx;
|
static struct rt_mutex pid_mtx;
|
||||||
|
static struct rt_wqueue _pid_emptyq;
|
||||||
|
|
||||||
int lwp_pid_init(void)
|
int lwp_pid_init(void)
|
||||||
{
|
{
|
||||||
|
rt_wqueue_init(&_pid_emptyq);
|
||||||
rt_mutex_init(&pid_mtx, "pidmtx", RT_IPC_FLAG_PRIO);
|
rt_mutex_init(&pid_mtx, "pidmtx", RT_IPC_FLAG_PRIO);
|
||||||
return 0;
|
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)
|
void lwp_pid_lock_take(void)
|
||||||
{
|
{
|
||||||
LWP_DEF_RETURN_CODE(rc);
|
LWP_DEF_RETURN_CODE(rc);
|
||||||
@@ -211,7 +228,15 @@ void lwp_pid_put(struct rt_lwp *lwp)
|
|||||||
|
|
||||||
lwp_pid_lock_take();
|
lwp_pid_lock_take();
|
||||||
lwp_pid_put_locked(lwp->pid);
|
lwp_pid_put_locked(lwp->pid);
|
||||||
|
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();
|
lwp_pid_lock_release();
|
||||||
|
}
|
||||||
|
|
||||||
/* reset pid field */
|
/* reset pid field */
|
||||||
lwp->pid = 0;
|
lwp->pid = 0;
|
||||||
@@ -1539,6 +1564,7 @@ static void _notify_parent(rt_lwp_t lwp)
|
|||||||
|
|
||||||
static void _resr_cleanup(struct rt_lwp *lwp)
|
static void _resr_cleanup(struct rt_lwp *lwp)
|
||||||
{
|
{
|
||||||
|
int need_cleanup_pid = RT_FALSE;
|
||||||
lwp_jobctrl_on_exit(lwp);
|
lwp_jobctrl_on_exit(lwp);
|
||||||
|
|
||||||
LWP_LOCK(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.
|
* 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
|
* Otherwise, its parent had setup a flag to mask out recycling event
|
||||||
*/
|
*/
|
||||||
lwp_pid_put(lwp);
|
need_cleanup_pid = RT_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
LWP_LOCK(lwp);
|
LWP_LOCK(lwp);
|
||||||
@@ -1628,6 +1654,11 @@ static void _resr_cleanup(struct rt_lwp *lwp)
|
|||||||
{
|
{
|
||||||
LWP_UNLOCK(lwp);
|
LWP_UNLOCK(lwp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (need_cleanup_pid)
|
||||||
|
{
|
||||||
|
lwp_pid_put(lwp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _lwp_setaffinity(int tid, int cpu)
|
static int _lwp_setaffinity(int tid, int cpu)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ struct rt_lwp;
|
|||||||
|
|
||||||
struct lwp_avl_struct *lwp_get_pid_ary(void);
|
struct lwp_avl_struct *lwp_get_pid_ary(void);
|
||||||
int lwp_pid_init(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);
|
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_put(struct rt_lwp *lwp);
|
||||||
void lwp_pid_lock_take(void);
|
void lwp_pid_lock_take(void);
|
||||||
|
|||||||
@@ -109,3 +109,53 @@ static int lwp_startup(void)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
INIT_APP_EXPORT(lwp_startup);
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6171,16 +6171,27 @@ sysret_t sys_chown(const char *pathname, uid_t owner, gid_t group)
|
|||||||
return (ret < 0 ? GET_ERRNO() : ret);
|
return (ret < 0 ? GET_ERRNO() : ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <sys/reboot.h>
|
#ifndef LWP_USING_RUNTIME
|
||||||
sysret_t sys_reboot(int magic, int magic2, int type)
|
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;
|
sysret_t rc;
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
/* TODO add software poweroff protocols */
|
/* Hardware reset */
|
||||||
case RB_AUTOBOOT:
|
case RB_AUTOBOOT:
|
||||||
|
rc = lwp_teardown(lwp_self(), rt_hw_cpu_reset);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Stop system and switch power off */
|
||||||
case RB_POWER_OFF:
|
case RB_POWER_OFF:
|
||||||
rt_hw_cpu_reset();
|
rc = lwp_teardown(lwp_self(), rt_hw_cpu_shutdown);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
rc = -ENOSYS;
|
rc = -ENOSYS;
|
||||||
|
|||||||
Reference in New Issue
Block a user