123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /*
- * Copyright (c) 2006-2024, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2024-11-11 Shell moved lwp_startup() from lwp.c;
- * added lwp_teardown()
- */
- #define DBG_TAG "lwp"
- #define DBG_LVL DBG_INFO
- #include <rtdbg.h>
- #include "lwp_internal.h"
- #include <rthw.h>
- #include <rtthread.h>
- #include <dfs_file.h>
- #include <dfs_mnt.h>
- #include <dfs_fs.h>
- /**
- * lwp_runtime:
- * Runtime environment provide by init process including boot scripts,
- * poweroff, shutdown, reboot, service management etc. In the kernel, lwp will
- * provide the underlying software bootstrap and cleanup for the init proc.
- *
- */
- rt_weak int lwp_startup_debug_request(void)
- {
- return 0;
- }
- #define LATENCY_TIMES (3)
- #define LATENCY_IN_MSEC (128)
- #define LWP_CONSOLE_PATH "CONSOLE=/dev/console"
- const char *init_search_path[] = {
- "/sbin/init",
- "/bin/init",
- };
- /**
- * Startup process 1 and do the essential works
- */
- static int lwp_startup(void)
- {
- int error;
- const char *init_path;
- char *argv[] = {0, "&"};
- char *envp[] = {LWP_CONSOLE_PATH, 0};
- #ifdef LWP_DEBUG_INIT
- int command;
- int countdown = LATENCY_TIMES;
- while (countdown)
- {
- command = lwp_startup_debug_request();
- if (command)
- {
- return 0;
- }
- rt_kprintf("Press any key to stop init process startup ... %d\n", countdown);
- countdown -= 1;
- rt_thread_mdelay(LATENCY_IN_MSEC);
- }
- rt_kprintf("Starting init ...\n");
- #endif /* LWP_DEBUG_INIT */
- for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++)
- {
- struct stat s;
- init_path = init_search_path[i];
- error = stat(init_path, &s);
- if (error == 0)
- {
- argv[0] = (void *)init_path;
- error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp);
- if (error < 0)
- {
- LOG_W("%s: failed to setup runtime environment\b"
- "\tlwp_execve() failed with code %d", __func__, error);
- }
- else if (error != 1)
- {
- LOG_W("%s: pid 1 is already allocated", __func__);
- error = -EBUSY;
- }
- else
- {
- rt_lwp_t p = lwp_from_pid_locked(1);
- p->sig_protected = 1;
- error = 0;
- }
- break;
- }
- }
- if (error)
- {
- LOG_D("%s: failed to setup runtime environment\b"
- "\tinit program not found", __func__);
- }
- 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;
- }
|