lwp_session.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-11-17 xqyjlj the first version
  9. * 2023-11-29 Shell Add direct reference of sess for group
  10. */
  11. #include "lwp.h"
  12. #include "lwp_internal.h"
  13. #include "lwp_syscall.h"
  14. #include "terminal/terminal.h"
  15. #define DBG_TAG "lwp.session"
  16. #define DBG_LVL DBG_WARNING
  17. #include <rtdbg.h>
  18. rt_session_t lwp_session_find(pid_t sid)
  19. {
  20. rt_base_t level;
  21. rt_session_t session = RT_NULL;
  22. rt_list_t *node = RT_NULL;
  23. struct rt_object_information *information = RT_NULL;
  24. information = rt_object_get_information(RT_Object_Class_Session);
  25. /* parameter check */
  26. if ((sid < 0) || (information == RT_NULL))
  27. {
  28. return RT_NULL;
  29. }
  30. if (sid == 0)
  31. {
  32. sid = lwp_getpid();
  33. }
  34. /* enter critical */
  35. level = rt_spin_lock_irqsave(&(information->spinlock));
  36. /* try to find session */
  37. rt_list_for_each(node, &(information->object_list))
  38. {
  39. session = (rt_session_t)rt_list_entry(node, struct rt_object, list);
  40. if (session->sid == sid)
  41. {
  42. rt_spin_unlock_irqrestore(&(information->spinlock), level);
  43. return session;
  44. }
  45. }
  46. rt_spin_unlock_irqrestore(&(information->spinlock), level);
  47. return RT_NULL;
  48. }
  49. rt_session_t lwp_session_create(rt_lwp_t leader)
  50. {
  51. rt_session_t session = RT_NULL;
  52. /* parameter check */
  53. if (leader == RT_NULL)
  54. {
  55. return RT_NULL;
  56. }
  57. session = rt_malloc(sizeof(struct rt_session));
  58. if (session != RT_NULL)
  59. {
  60. rt_object_init(&(session->object), RT_Object_Class_Session, "session");
  61. rt_list_init(&(session->processgroup));
  62. rt_mutex_init(&(session->mutex), "session", RT_IPC_FLAG_PRIO);
  63. session->leader = leader;
  64. session->sid = leader->pid;
  65. lwp_pgrp_update_children_info(leader->pgrp, session->sid, leader->pgid);
  66. session->foreground_pgid = session->sid;
  67. session->ctty = RT_NULL;
  68. }
  69. return session;
  70. }
  71. int lwp_session_delete(rt_session_t session)
  72. {
  73. int retry = 1;
  74. lwp_tty_t ctty;
  75. /* parameter check */
  76. if (session == RT_NULL)
  77. {
  78. return -EINVAL;
  79. }
  80. /* clear children sid */
  81. lwp_session_update_children_info(session, 0);
  82. while (retry)
  83. {
  84. retry = 0;
  85. ctty = session->ctty;
  86. SESS_LOCK_NESTED(session);
  87. if (session->ctty == ctty)
  88. {
  89. if (ctty)
  90. {
  91. SESS_UNLOCK(session);
  92. /**
  93. * Note: it's safe to release the session lock now. Even if someone
  94. * race to acquire the tty, it's safe under protection of tty_lock()
  95. * and the check inside
  96. */
  97. tty_lock(ctty);
  98. tty_rel_sess(ctty, session);
  99. session->ctty = RT_NULL;
  100. }
  101. else
  102. {
  103. SESS_UNLOCK(session);
  104. }
  105. }
  106. else
  107. {
  108. SESS_UNLOCK(session);
  109. retry = 1;
  110. }
  111. }
  112. rt_object_detach(&(session->object));
  113. rt_mutex_detach(&(session->mutex));
  114. rt_free(session);
  115. return 0;
  116. }
  117. int lwp_session_insert(rt_session_t session, rt_processgroup_t group)
  118. {
  119. /* parameter check */
  120. if (session == RT_NULL || group == RT_NULL)
  121. {
  122. return -EINVAL;
  123. }
  124. SESS_LOCK_NESTED(session);
  125. PGRP_LOCK_NESTED(group);
  126. group->sid = session->sid;
  127. group->session = session;
  128. lwp_pgrp_update_children_info(group, session->sid, group->pgid);
  129. rt_list_insert_after(&(session->processgroup), &(group->pgrp_list_node));
  130. PGRP_UNLOCK(group);
  131. SESS_UNLOCK(session);
  132. return 0;
  133. }
  134. int lwp_session_remove(rt_session_t session, rt_processgroup_t group)
  135. {
  136. rt_bool_t is_empty = RT_FALSE;
  137. /* parameter check */
  138. if (session == RT_NULL || group == RT_NULL)
  139. {
  140. return -EINVAL;
  141. }
  142. SESS_LOCK_NESTED(session);
  143. PGRP_LOCK_NESTED(group);
  144. rt_list_remove(&(group->pgrp_list_node));
  145. /* clear children sid */
  146. lwp_pgrp_update_children_info(group, 0, group->pgid);
  147. group->sid = 0;
  148. group->session = RT_NULL;
  149. PGRP_UNLOCK(group);
  150. is_empty = rt_list_isempty(&(session->processgroup));
  151. SESS_UNLOCK(session);
  152. if (is_empty)
  153. {
  154. lwp_session_delete(session);
  155. return 1;
  156. }
  157. return 0;
  158. }
  159. int lwp_session_move(rt_session_t session, rt_processgroup_t group)
  160. {
  161. rt_session_t prev_session;
  162. /* parameter check */
  163. if (session == RT_NULL || group == RT_NULL)
  164. {
  165. return -EINVAL;
  166. }
  167. if (lwp_sid_get_bysession(session) == lwp_sid_get_bypgrp(group))
  168. {
  169. return 0;
  170. }
  171. SESS_LOCK(session);
  172. prev_session = group->session;
  173. if (prev_session)
  174. {
  175. SESS_LOCK(prev_session);
  176. lwp_session_remove(prev_session, group);
  177. SESS_UNLOCK(prev_session);
  178. }
  179. lwp_session_insert(session, group);
  180. SESS_UNLOCK(session);
  181. return 0;
  182. }
  183. int lwp_session_update_children_info(rt_session_t session, pid_t sid)
  184. {
  185. rt_list_t *node = RT_NULL;
  186. rt_processgroup_t group = RT_NULL;
  187. if (session == RT_NULL)
  188. {
  189. return -EINVAL;
  190. }
  191. SESS_LOCK_NESTED(session);
  192. rt_list_for_each(node, &(session->processgroup))
  193. {
  194. group = (rt_processgroup_t)rt_list_entry(node, struct rt_processgroup, pgrp_list_node);
  195. PGRP_LOCK_NESTED(group);
  196. if (sid != -1)
  197. {
  198. group->sid = sid;
  199. group->session = session;
  200. lwp_pgrp_update_children_info(group, sid, group->pgid);
  201. }
  202. PGRP_UNLOCK(group);
  203. }
  204. SESS_UNLOCK(session);
  205. return 0;
  206. }
  207. int lwp_session_set_foreground(rt_session_t session, pid_t pgid)
  208. {
  209. rt_processgroup_t group = RT_NULL;
  210. rt_list_t *node = RT_NULL;
  211. rt_bool_t is_contains = RT_FALSE;
  212. /* parameter check */
  213. if (session == RT_NULL || pgid <= 0)
  214. {
  215. return -EINVAL;
  216. }
  217. SESS_LOCK(session);
  218. rt_list_for_each(node, &(session->processgroup))
  219. {
  220. group = (rt_processgroup_t)rt_list_entry(node, struct rt_processgroup, pgrp_list_node);
  221. PGRP_LOCK(group);
  222. if (group->pgid == pgid)
  223. {
  224. is_contains = RT_TRUE;
  225. }
  226. PGRP_UNLOCK(group);
  227. }
  228. if (is_contains)
  229. {
  230. session->foreground_pgid = pgid;
  231. // TODO: maybe notify tty
  232. }
  233. SESS_UNLOCK(session);
  234. return is_contains ? 0 : -EINVAL;
  235. }
  236. /**
  237. * setsid() creates a new session if the calling process is not a process group leader.
  238. * The calling process is the leader of the new session (i.e., its session ID is made the same as its process ID).
  239. * The calling process also becomes the process group leader of a new process group in the session
  240. * (i.e., its process group ID is made the same as its process ID).
  241. */
  242. sysret_t sys_setsid(void)
  243. {
  244. rt_lwp_t process;
  245. pid_t pid;
  246. rt_processgroup_t group;
  247. rt_session_t session;
  248. sysret_t err = 0;
  249. process = lwp_self();
  250. pid = lwp_to_pid(process);
  251. /**
  252. * if the calling process is already a process group leader.
  253. */
  254. if (lwp_pgrp_find(pid))
  255. {
  256. err = -EPERM;
  257. goto exit;
  258. }
  259. group = lwp_pgrp_create(process);
  260. if (group)
  261. {
  262. lwp_pgrp_move(group, process);
  263. session = lwp_session_create(process);
  264. if (session)
  265. {
  266. lwp_session_move(session, group);
  267. }
  268. else
  269. {
  270. lwp_pgrp_delete(group);
  271. }
  272. err = lwp_sid_get_bysession(session);
  273. }
  274. else
  275. {
  276. err = -ENOMEM;
  277. }
  278. exit:
  279. return err;
  280. }
  281. /**
  282. * getsid() returns the session ID of the process with process ID pid.
  283. * If pid is 0, getsid() returns the session ID of the calling process.
  284. */
  285. sysret_t sys_getsid(pid_t pid)
  286. {
  287. rt_lwp_t process, self_process;
  288. pid_t sid;
  289. lwp_pid_lock_take();
  290. process = lwp_from_pid_locked(pid);
  291. lwp_pid_lock_release();
  292. if (process == RT_NULL)
  293. {
  294. return -ESRCH;
  295. }
  296. self_process = lwp_self();
  297. sid = lwp_sid_get_byprocess(process);
  298. if (sid != lwp_sid_get_byprocess(self_process))
  299. {
  300. /**
  301. * A process with process ID pid exists, but it is not in the same session as the calling process,
  302. * and the implementation considers this an error.
  303. *
  304. * Note: Linux does not return EPERM.
  305. */
  306. return -EPERM;
  307. }
  308. return sid;
  309. }
  310. #ifdef RT_USING_FINSH
  311. #include "finsh.h"
  312. long list_session(void)
  313. {
  314. int count = 0, index;
  315. rt_session_t *sessions;
  316. rt_session_t session;
  317. rt_thread_t thread;
  318. char name[RT_NAME_MAX];
  319. rt_kprintf("SID leader process\n");
  320. rt_kprintf("---- ----------------\n");
  321. count = rt_object_get_length(RT_Object_Class_Session);
  322. if (count > 0)
  323. {
  324. /* get pointers */
  325. sessions = (rt_session_t *)rt_calloc(count, sizeof(rt_session_t));
  326. if (sessions)
  327. {
  328. index = rt_object_get_pointers(RT_Object_Class_Session, (rt_object_t *)sessions, count);
  329. if (index > 0)
  330. {
  331. for (index = 0; index < count; index++)
  332. {
  333. struct rt_session se;
  334. session = sessions[index];
  335. SESS_LOCK(session);
  336. rt_memcpy(&se, session, sizeof(struct rt_session));
  337. SESS_UNLOCK(session);
  338. if (se.leader && se.leader)
  339. {
  340. thread = rt_list_entry(se.leader->t_grp.prev, struct rt_thread, sibling);
  341. rt_strncpy(name, thread->parent.name, RT_NAME_MAX);
  342. }
  343. else
  344. {
  345. rt_strncpy(name, "nil", RT_NAME_MAX);
  346. }
  347. rt_kprintf("%4d %-*.*s\n", se.sid, RT_NAME_MAX, RT_NAME_MAX, name);
  348. }
  349. }
  350. rt_free(sessions);
  351. }
  352. }
  353. return 0;
  354. }
  355. MSH_CMD_EXPORT(list_session, list session);
  356. #endif