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:
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user