lwp_runtime.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /*
  2. * Copyright (c) 2006-2024, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-11-11 Shell moved lwp_startup() from lwp.c;
  9. * added lwp_teardown()
  10. */
  11. #define DBG_TAG "lwp"
  12. #define DBG_LVL DBG_INFO
  13. #include <rtdbg.h>
  14. #include "lwp_internal.h"
  15. #include <rthw.h>
  16. #include <rtthread.h>
  17. #include <dfs_file.h>
  18. #include <dfs_mnt.h>
  19. #include <dfs_fs.h>
  20. /**
  21. * lwp_runtime:
  22. * Runtime environment provide by init process including boot scripts,
  23. * poweroff, shutdown, reboot, service management etc. In the kernel, lwp will
  24. * provide the underlying software bootstrap and cleanup for the init proc.
  25. *
  26. */
  27. rt_weak int lwp_startup_debug_request(void)
  28. {
  29. return 0;
  30. }
  31. #define LATENCY_TIMES (3)
  32. #define LATENCY_IN_MSEC (128)
  33. #define LWP_CONSOLE_PATH "CONSOLE=/dev/console"
  34. const char *init_search_path[] = {
  35. "/sbin/init",
  36. "/bin/init",
  37. };
  38. /**
  39. * Startup process 1 and do the essential works
  40. */
  41. static int lwp_startup(void)
  42. {
  43. int error;
  44. const char *init_path;
  45. char *argv[] = {0, "&"};
  46. char *envp[] = {LWP_CONSOLE_PATH, 0};
  47. #ifdef LWP_DEBUG_INIT
  48. int command;
  49. int countdown = LATENCY_TIMES;
  50. while (countdown)
  51. {
  52. command = lwp_startup_debug_request();
  53. if (command)
  54. {
  55. return 0;
  56. }
  57. rt_kprintf("Press any key to stop init process startup ... %d\n", countdown);
  58. countdown -= 1;
  59. rt_thread_mdelay(LATENCY_IN_MSEC);
  60. }
  61. rt_kprintf("Starting init ...\n");
  62. #endif /* LWP_DEBUG_INIT */
  63. for (size_t i = 0; i < sizeof(init_search_path)/sizeof(init_search_path[0]); i++)
  64. {
  65. struct stat s;
  66. init_path = init_search_path[i];
  67. error = stat(init_path, &s);
  68. if (error == 0)
  69. {
  70. argv[0] = (void *)init_path;
  71. error = lwp_execve((void *)init_path, 0, sizeof(argv)/sizeof(argv[0]), argv, envp);
  72. if (error < 0)
  73. {
  74. LOG_W("%s: failed to setup runtime environment\b"
  75. "\tlwp_execve() failed with code %d", __func__, error);
  76. }
  77. else if (error != 1)
  78. {
  79. LOG_W("%s: pid 1 is already allocated", __func__);
  80. error = -EBUSY;
  81. }
  82. else
  83. {
  84. rt_lwp_t p = lwp_from_pid_locked(1);
  85. p->sig_protected = 1;
  86. error = 0;
  87. }
  88. break;
  89. }
  90. }
  91. if (error)
  92. {
  93. LOG_D("%s: failed to setup runtime environment\b"
  94. "\tinit program not found", __func__);
  95. }
  96. return error;
  97. }
  98. INIT_APP_EXPORT(lwp_startup);
  99. /* don't use heap for safety */
  100. static struct rt_work _teardown_work;
  101. #define INIT_PID 1
  102. static void _teardown_entry(struct rt_work *work, void *work_data)
  103. {
  104. int error;
  105. void (*cb_on_reboot)(void) = work_data;
  106. /* cleanup of process */
  107. do
  108. {
  109. error = lwp_pid_wait_for_empty(RT_KILLABLE, RT_WAITING_FOREVER);
  110. }
  111. while (error);
  112. LOG_I("All processes exited");
  113. cb_on_reboot();
  114. return;
  115. }
  116. static int _get_parent_pid(struct rt_lwp *lwp)
  117. {
  118. return lwp->parent ? lwp->parent->pid : 0;
  119. }
  120. /* reverse operation of lwp_startup() */
  121. sysret_t lwp_teardown(struct rt_lwp *lwp, void (*cb)(void))
  122. {
  123. struct rt_work *work;
  124. if (lwp->pid != INIT_PID && _get_parent_pid(lwp) != INIT_PID)
  125. {
  126. /* The calling process has insufficient privilege */
  127. return -EPERM;
  128. }
  129. work = &_teardown_work;
  130. rt_work_init(work, _teardown_entry, cb);
  131. #define SOME_DELAY (RT_TICK_PER_SECOND / 10) /* allow idle to cleanup resource */
  132. rt_work_submit(work, SOME_DELAY);
  133. lwp_exit(lwp, LWP_CREATE_STAT_EXIT(EXIT_SUCCESS));
  134. /* never return */
  135. RT_ASSERT(0);
  136. return 0;
  137. }