tty: Notify disconnections properly, and with B_SELECT_DISCONNECTED.

The tty_notify_select_event() at the end of tty_close_cookie()
checked if the other_tty's open_count was > 0 before notifying.
But in the case where the master is closing all children,
it will drop to 0 and leave things still in the select pool.
So we should notify unconditionally here.

Additionally, use B_SELECT_DISCONNECTED (i.e. POLLHUP). This matches
what Linux seems to do.

Fixes #19714.
This commit is contained in:
Augustin Cavalier
2025-09-03 18:37:47 -04:00
parent 5da70510b3
commit f7c3fa972c
+12 -11
View File
@@ -1528,11 +1528,8 @@ tty_close_cookie(tty_cookie* cookie)
requestLocker.Unlock(); requestLocker.Unlock();
// notify a select read and write event on the other tty, if we've closed this tty // notify a select event on the other tty, if we've closed this tty
if (cookie->other_tty->open_count > 0) { tty_notify_select_event(cookie->other_tty, B_SELECT_DISCONNECTED);
tty_notify_select_event(cookie->other_tty, B_SELECT_WRITE);
tty_notify_select_event(cookie->other_tty, B_SELECT_READ);
}
cookie->tty->is_exclusive = false; cookie->tty->is_exclusive = false;
} }
@@ -1998,7 +1995,7 @@ tty_select(tty_cookie* cookie, uint8 event, uint32 ref, selectsync* sync)
"%p)\n", cookie, event, ref, sync)); "%p)\n", cookie, event, ref, sync));
// we don't support all kinds of events // we don't support all kinds of events
if (event < B_SELECT_READ || event > B_SELECT_ERROR) if (event < B_SELECT_READ || (event > B_SELECT_ERROR && event != B_SELECT_DISCONNECTED))
return B_BAD_VALUE; return B_BAD_VALUE;
// if the TTY is already closed, we notify immediately // if the TTY is already closed, we notify immediately
@@ -2006,7 +2003,8 @@ tty_select(tty_cookie* cookie, uint8 event, uint32 ref, selectsync* sync)
if (!ttyReference.IsLocked()) { if (!ttyReference.IsLocked()) {
TRACE(("tty_select() done: cookie %p already closed\n", cookie)); TRACE(("tty_select() done: cookie %p already closed\n", cookie));
notify_select_event(sync, event); if (event == B_SELECT_DISCONNECTED)
notify_select_event(sync, event);
return B_OK; return B_OK;
} }
@@ -2042,10 +2040,8 @@ tty_select(tty_cookie* cookie, uint8 event, uint32 ref, selectsync* sync)
case B_SELECT_WRITE: case B_SELECT_WRITE:
{ {
// writes go to the other TTY // writes go to the other TTY
if (!otherTTY) { if (otherTTY == NULL)
notify_select_event(sync, event);
break; break;
}
// In case input is echoed, we have to check, whether we can // In case input is echoed, we have to check, whether we can
// currently can write to our TTY as well. // currently can write to our TTY as well.
@@ -2063,6 +2059,11 @@ tty_select(tty_cookie* cookie, uint8 event, uint32 ref, selectsync* sync)
break; break;
} }
case B_SELECT_DISCONNECTED:
if (otherTTY == NULL)
notify_select_event(sync, event);
break;
case B_SELECT_ERROR: case B_SELECT_ERROR:
default: default:
break; break;
@@ -2081,7 +2082,7 @@ tty_deselect(tty_cookie* cookie, uint8 event, selectsync* sync)
sync)); sync));
// we don't support all kinds of events // we don't support all kinds of events
if (event < B_SELECT_READ || event > B_SELECT_ERROR) if (event < B_SELECT_READ || (event > B_SELECT_ERROR && event != B_SELECT_DISCONNECTED))
return B_BAD_VALUE; return B_BAD_VALUE;
// lock the TTY (guards the select sync pool, among other things) // lock the TTY (guards the select sync pool, among other things)