Skip to content

Commit d8b4ff7

Browse files
committed
fix(process): preserve process-group identity across threads
Represent PGID and SID membership once per thread group while retaining per-thread TGID links required by existing consumers. Transfer leader-owned links and session state atomically during de_thread, and serialize fork, setpgid, setsid, exit, and process-group lookup against membership changes. Make process-group signal delivery target one representative per thread group. Keep controlling-TTY publication, removal, hangup, and foreground-group changes in ordered transactions so stale owners cannot clear or signal a replacement session. Perform session teardown only for the unique last live thread. Add dunitest coverage for inherited PGID/SID across pthread creation, single process-group realtime-signal delivery, and session leadership after a nonleader exec. Signed-off-by: longjin <longjin@dragonos.org>
1 parent bc337b1 commit d8b4ff7

14 files changed

Lines changed: 462 additions & 176 deletions

File tree

kernel/src/driver/tty/tty_core.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ impl TtyCore {
138138
read_wq: EventWaitQueue::new(),
139139
write_wq: EventWaitQueue::new(),
140140
write_lock: TtySleepLock::new(),
141+
job_control_lock: TtySleepLock::new(),
141142
port: RwLock::new(None),
142143
index,
143144
vc_index: AtomicUsize::new(usize::MAX),
@@ -258,6 +259,7 @@ impl TtyCore {
258259
}
259260

260261
pub fn tty_vhangup(tty: Arc<TtyCore>) {
262+
let _job_control_guard = tty.core().job_control_lock().lock();
261263
{
262264
let mut flags = tty.core().flags_write();
263265
if flags.contains(TtyFlag::HUPPED) {
@@ -266,10 +268,7 @@ impl TtyCore {
266268
flags.insert(TtyFlag::HUPPING);
267269
}
268270

269-
let (sid, pgid) = {
270-
let ctrl = tty.core().contorl_info_irqsave();
271-
(ctrl.session.clone(), ctrl.pgid.clone())
272-
};
271+
let pgid = TtyJobCtrlManager::remove_session_tty_job_locked(&tty, None);
273272

274273
if let Some(pgrp) = pgid {
275274
let _ = crate::ipc::kill::send_signal_to_pgid(&pgrp, Signal::SIGHUP);
@@ -280,13 +279,8 @@ impl TtyCore {
280279

281280
{
282281
let mut ctrl = tty.core().contorl_info_irqsave();
283-
ctrl.session = None;
284-
ctrl.pgid = None;
285282
ctrl.pktstatus = TtyPacketStatus::empty();
286283
}
287-
if let Some(sid) = sid {
288-
TtyJobCtrlManager::session_clear_tty(sid);
289-
}
290284

291285
{
292286
let mut flags = tty.core().flags_write();
@@ -501,6 +495,8 @@ pub struct TtyCoreData {
501495
write_wq: EventWaitQueue,
502496
/// 串行化整个 tty write 调用,等价于 Linux tty->atomic_write_lock。
503497
write_lock: TtySleepLock,
498+
/// Serializes controlling-session changes with hangup.
499+
job_control_lock: TtySleepLock,
504500
/// 端口
505501
port: RwLock<Option<Arc<dyn TtyPort>>>,
506502
/// 前台进程
@@ -615,6 +611,11 @@ impl TtyCoreData {
615611
&self.write_lock
616612
}
617613

614+
#[inline]
615+
pub fn job_control_lock(&self) -> &TtySleepLock {
616+
&self.job_control_lock
617+
}
618+
618619
#[inline]
619620
pub fn contorl_info_irqsave(&self) -> SpinLockGuard<'_, TtyControlInfo> {
620621
self.ctrl.lock_irqsave()
@@ -837,7 +838,7 @@ impl TtyOperation for TtyCore {
837838
// );
838839
let r = self.core().tty_driver.driver_funcs().close(tty.clone());
839840
// 如果计数为0或者无效,表示tty已经关闭
840-
TtyJobCtrlManager::remove_session_tty(&tty);
841+
let _ = TtyJobCtrlManager::remove_session_tty(&tty);
841842
return r;
842843
}
843844
Ok(())

kernel/src/driver/tty/tty_device.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -279,22 +279,13 @@ impl IndexNode for TtyDevice {
279279
let driver = tty.core().driver();
280280
// 考虑 O_NOCTTY:显式指定则不设置控制终端;pty master 也不会成为控制终端。
281281
if !(mode.contains(FileFlags::O_NOCTTY)
282+
|| mode.is_write_only()
282283
|| (driver.tty_driver_type() == TtyDriverType::Pty
283284
&& driver.tty_driver_sub_type() == TtyDriverSubType::PtyMaster))
284285
{
285-
let pcb = ProcessManager::current_pcb();
286-
let pcb_tty = pcb.sig_info_irqsave().tty();
287-
let is_session_leader = pcb.sig_info_irqsave().is_session_leader;
288-
let tty_session_is_none = tty.core().contorl_info_irqsave().session.is_none();
289-
// Linux tty_open_proc_set_tty 语义:必须是会话首进程、尚无 controlling tty、
290-
// tty 当前未被会话占用,且本次 open 具备读权限(不是 O_WRONLY)。
291-
if is_session_leader
292-
&& pcb_tty.is_none()
293-
&& tty_session_is_none
294-
&& !mode.is_write_only()
295-
{
296-
TtyJobCtrlManager::proc_set_tty(tty);
297-
}
286+
// The helper revalidates and commits the controlling-tty state as
287+
// one membership/tty/signal transaction.
288+
TtyJobCtrlManager::proc_set_tty(tty);
298289
}
299290

300291
Ok(())

kernel/src/driver/tty/tty_job_control.rs

Lines changed: 105 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,23 @@ pub struct TtyJobCtrlManager;
1919
impl TtyJobCtrlManager {
2020
/// ### 设置当前进程的tty
2121
pub fn proc_set_tty(tty: Arc<TtyCore>) {
22-
let core = tty.core();
2322
let pcb = ProcessManager::current_pcb();
24-
25-
let mut ctrl = core.contorl_info_irqsave();
23+
let _job_control_guard = tty.core().job_control_lock().lock();
24+
let _membership_guard = crate::process::pid::pid_membership_lock();
25+
if tty
26+
.core()
27+
.flags()
28+
.intersects(super::tty_core::TtyFlag::HUPPING | super::tty_core::TtyFlag::HUPPED)
29+
{
30+
return;
31+
}
32+
let mut ctrl = tty.core().contorl_info_irqsave();
33+
let mut signal = pcb.sig_info_mut();
34+
if !signal.is_session_leader || signal.tty().is_some() || ctrl.session.is_some() {
35+
return;
36+
}
2637
ctrl.set_info_by_pcb(pcb.clone());
27-
28-
drop(ctrl);
29-
30-
let mut singal = pcb.sig_info_mut();
31-
singal.set_tty(Some(tty.clone()));
38+
signal.set_tty(Some(tty.clone()));
3239
}
3340

3441
/// ### 清除进程的tty
@@ -44,10 +51,47 @@ impl TtyJobCtrlManager {
4451
wguard.set_tty(None);
4552
}
4653

47-
pub fn remove_session_tty(tty: &Arc<TtyCore>) {
54+
pub fn remove_session_tty(tty: &Arc<TtyCore>) -> Option<Arc<Pid>> {
55+
let _job_control_guard = tty.core().job_control_lock().lock();
56+
Self::remove_session_tty_job_locked(tty, None)
57+
}
58+
59+
pub(crate) fn remove_session_tty_job_locked(
60+
tty: &Arc<TtyCore>,
61+
expected_sid: Option<&Arc<Pid>>,
62+
) -> Option<Arc<Pid>> {
63+
let _membership_guard = crate::process::pid::pid_membership_lock();
64+
Self::remove_session_tty_locked(tty, expected_sid)
65+
}
66+
67+
pub fn remove_session_tty_if_owner(
68+
tty: &Arc<TtyCore>,
69+
expected_sid: &Arc<Pid>,
70+
) -> Option<Arc<Pid>> {
71+
let _job_control_guard = tty.core().job_control_lock().lock();
72+
Self::remove_session_tty_job_locked(tty, Some(expected_sid))
73+
}
74+
75+
/// The caller must hold PID_MEMBERSHIP_LOCK.
76+
fn remove_session_tty_locked(
77+
tty: &Arc<TtyCore>,
78+
expected_sid: Option<&Arc<Pid>>,
79+
) -> Option<Arc<Pid>> {
4880
let mut ctrl = tty.core().contorl_info_irqsave();
49-
ctrl.session = None;
50-
ctrl.pgid = None;
81+
if expected_sid.is_some_and(|expected| {
82+
ctrl.session
83+
.as_ref()
84+
.is_none_or(|owner| !Arc::ptr_eq(owner, expected))
85+
}) {
86+
return None;
87+
}
88+
let sid = ctrl.session.take();
89+
let pgid = ctrl.pgid.take();
90+
drop(ctrl);
91+
if let Some(sid) = sid {
92+
Self::session_clear_tty_locked(sid);
93+
}
94+
pgid
5195
}
5296

5397
/// ### 检查tty
@@ -125,18 +169,31 @@ impl TtyJobCtrlManager {
125169
// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/tty/tty_jobctrl.c#tiocsctty
126170
fn tiocsctty(real_tty: Arc<TtyCore>, arg: usize) -> Result<usize, SystemError> {
127171
let current = ProcessManager::current_pcb();
128-
let siginfo_guard = current.sig_info_irqsave();
172+
let _job_control_guard = real_tty.core().job_control_lock().lock();
173+
let _membership_guard = crate::process::pid::pid_membership_lock();
174+
if real_tty
175+
.core()
176+
.flags()
177+
.intersects(super::tty_core::TtyFlag::HUPPING | super::tty_core::TtyFlag::HUPPED)
178+
{
179+
return Err(SystemError::EIO);
180+
}
181+
let (is_session_leader, current_tty) = {
182+
let siginfo = current.sig_info_irqsave();
183+
(siginfo.is_session_leader, siginfo.tty())
184+
};
129185

130186
// 只有会话首进程才能设置控制终端
131-
if !siginfo_guard.is_session_leader {
187+
if !is_session_leader {
132188
return Err(SystemError::EPERM);
133189
}
134190

191+
let current_session = current.task_session();
192+
135193
// 如果当前进程已经有控制终端,则返回错误(除非是同一个tty且会话相同)
136-
if let Some(current_tty) = siginfo_guard.tty() {
137-
if Arc::ptr_eq(&current_tty, &real_tty)
138-
&& current.task_session() == real_tty.core().contorl_info_irqsave().session
139-
{
194+
if let Some(current_tty) = current_tty {
195+
let tty_session = real_tty.core().contorl_info_irqsave().session.clone();
196+
if Arc::ptr_eq(&current_tty, &real_tty) && current_session == tty_session {
140197
// 如果已经是当前tty且会话相同,直接返回成功
141198
return Ok(0);
142199
} else {
@@ -145,13 +202,11 @@ impl TtyJobCtrlManager {
145202
}
146203
}
147204

148-
drop(siginfo_guard);
149-
150-
let tty_ctrl_guard = real_tty.core().contorl_info_irqsave();
205+
let mut tty_ctrl_guard = real_tty.core().contorl_info_irqsave();
151206

152207
if let Some(ref sid) = tty_ctrl_guard.session {
153208
// 如果当前进程是会话首进程,且tty的会话是当前进程的会话,则允许设置
154-
if current.task_session() == Some(sid.clone()) {
209+
if current_session == Some(sid.clone()) {
155210
// 这是正常情况:会话首进程要设置自己会话的tty为控制终端
156211
} else {
157212
// tty被其他会话占用
@@ -161,16 +216,16 @@ impl TtyJobCtrlManager {
161216
if !cred.has_capability(CAPFlags::CAP_SYS_ADMIN) {
162217
return Err(SystemError::EPERM);
163218
}
164-
Self::session_clear_tty(sid.clone());
219+
Self::session_clear_tty_locked(sid.clone());
165220
} else {
166221
return Err(SystemError::EPERM);
167222
}
168223
}
169224
}
170225

226+
tty_ctrl_guard.set_info_by_pcb(current.clone());
227+
current.sig_info_mut().set_tty(Some(real_tty.clone()));
171228
drop(tty_ctrl_guard);
172-
173-
Self::proc_set_tty(real_tty);
174229
Ok(0)
175230
}
176231

@@ -249,57 +304,31 @@ impl TtyJobCtrlManager {
249304
}
250305

251306
let current = ProcessManager::current_pcb();
252-
307+
let _job_control_guard = real_tty.core().job_control_lock().lock();
308+
let _membership_guard = crate::process::pid::pid_membership_lock();
309+
let current_session = current.task_session();
310+
let current_tty = current.sig_info_irqsave().tty();
253311
let mut ctrl = real_tty.core().contorl_info_irqsave();
254-
312+
if current_tty
313+
.as_ref()
314+
.is_none_or(|tty| !Arc::ptr_eq(tty, &real_tty))
315+
|| ctrl.session != current_session
255316
{
256-
// if current.sig_info_irqsave().tty().is_none()
257-
// || !Arc::ptr_eq(
258-
// &current.sig_info_irqsave().tty().clone().unwrap(),
259-
// &real_tty,
260-
// )
261-
// || ctrl.session != current.task_session()
262-
// {
263-
// log::debug!("sss-2");
264-
// return Err(SystemError::ENOTTY);
265-
// }
266-
267-
// 拆分判断条件以便调试
268-
let current_tty = current.sig_info_irqsave().tty();
269-
let condition1 = current_tty.is_none();
270-
271-
let condition2 = if let Some(ref tty) = current_tty {
272-
!Arc::ptr_eq(tty, &real_tty)
273-
} else {
274-
false // 如果 tty 为 None,这个条件就不用检查了
275-
};
276-
277-
let condition3 = ctrl.session != current.task_session();
278-
279-
if condition1 || condition2 || condition3 {
280-
if condition1 {
281-
log::debug!("sss-2: 失败原因 - 当前进程没有关联的 tty");
282-
} else if condition2 {
283-
log::debug!("sss-2: 失败原因 - 当前进程的 tty 与目标 tty 不匹配");
284-
} else if condition3 {
285-
log::debug!("sss-2: 失败原因 - 会话不匹配");
286-
}
287-
return Err(SystemError::ENOTTY);
288-
}
317+
return Err(SystemError::ENOTTY);
289318
}
319+
290320
let pgrp =
291321
ProcessManager::find_vpid(RawPid::new(pgrp_nr as usize)).ok_or(SystemError::ESRCH)?;
292-
293-
if Self::session_of_pgrp(&pgrp) != current.task_session() {
322+
if Self::session_of_pgrp_locked(&pgrp) != current_session {
294323
return Err(SystemError::EPERM);
295324
}
296-
297325
ctrl.pgid = Some(pgrp);
298326

299327
return Ok(0);
300328
}
301329

302-
fn session_of_pgrp(pgrp: &Arc<Pid>) -> Option<Arc<Pid>> {
330+
/// The caller must hold PID_MEMBERSHIP_LOCK.
331+
fn session_of_pgrp_locked(pgrp: &Arc<Pid>) -> Option<Arc<Pid>> {
303332
let mut p = pgrp.pid_task(PidType::PGID);
304333
if p.is_none() {
305334
// this should not be None
@@ -329,33 +358,28 @@ impl TtyJobCtrlManager {
329358
return Ok(0);
330359
}
331360

332-
let sid = pcb.task_session();
333-
let tty_pgrp = real_tty.core().contorl_info_irqsave().pgid.clone();
361+
let tty_pgrp = if let Some(sid) = pcb.task_session() {
362+
Self::remove_session_tty_if_owner(&real_tty, &sid)
363+
} else {
364+
Self::proc_clear_tty(&pcb);
365+
None
366+
};
334367

335368
if let Some(pgrp) = tty_pgrp {
336369
let _ = crate::ipc::kill::send_signal_to_pgid(&pgrp, Signal::SIGHUP);
337370
let _ = crate::ipc::kill::send_signal_to_pgid(&pgrp, Signal::SIGCONT);
338371
}
339372

340-
{
341-
let mut ctrl = real_tty.core().contorl_info_irqsave();
342-
ctrl.session = None;
343-
ctrl.pgid = None;
344-
}
345-
346-
if let Some(sid) = sid {
347-
Self::session_clear_tty(sid);
348-
} else {
349-
Self::proc_clear_tty(&pcb);
350-
}
351-
352373
Ok(0)
353374
}
354375

355-
pub fn session_clear_tty(sid: Arc<Pid>) {
356-
// 清除会话的tty
357-
for task in sid.tasks_iter(PidType::SID) {
358-
TtyJobCtrlManager::proc_clear_tty(&task);
376+
/// The caller must hold PID_MEMBERSHIP_LOCK.
377+
fn session_clear_tty_locked(sid: Arc<Pid>) {
378+
let leaders: alloc::vec::Vec<_> = sid.tasks_iter(PidType::SID).collect();
379+
for leader in leaders {
380+
for task in ProcessManager::thread_group_tasks_snapshot(leader) {
381+
TtyJobCtrlManager::proc_clear_tty(&task);
382+
}
359383
}
360384
}
361385

0 commit comments

Comments
 (0)