ptyfwd,run: make pty_forward_drain() trigger defer event to call shovel()

drained() checks PTYForward.master_readable flag, but it may be
tentatively unset due to a tentative error like EAGAIN in the previous
IO event. Let's try to call shovel() one more time, which re-read the
master and call drained() at the end. Otherwise, we may lost some data.
This commit is contained in:
Yu Watanabe
2025-07-30 01:15:29 +09:00
parent 446431f5c9
commit dce66b0688
3 changed files with 21 additions and 16 deletions
+16 -7
View File
@@ -1818,17 +1818,24 @@ static int run_context_check_started(RunContext *c) {
}
static void run_context_check_done(RunContext *c) {
int r;
assert(c);
bool done = STRPTR_IN_SET(c->active_state, "inactive", "failed") &&
!c->start_job && /* our start job */
!c->job; /* any other job */
if (!STRPTR_IN_SET(c->active_state, "inactive", "failed") ||
c->start_job || /* our start job */
c->job) /* any other job */
return;
if (done && c->forward) /* If the service is gone, it's time to drain the output */
done = pty_forward_drain(c->forward);
if (!c->forward)
return (void) sd_event_exit(c->event, EXIT_SUCCESS);
if (done)
(void) sd_event_exit(c->event, EXIT_SUCCESS);
/* If the service is gone, it's time to drain the output */
r = pty_forward_drain(c->forward);
if (r < 0) {
log_error_errno(r, "Failed to drain PTY forwarder: %m");
return (void) sd_event_exit(c->event, EXIT_FAILURE);
}
}
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
@@ -1983,6 +1990,8 @@ static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
}
c->forward = pty_forward_free(c->forward);
run_context_check_done(c);
return 0;
}
+4 -8
View File
@@ -1135,18 +1135,14 @@ void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler cb, v
f->hotkey_userdata = userdata;
}
bool pty_forward_drain(PTYForward *f) {
int pty_forward_drain(PTYForward *f) {
assert(f);
/* Starts draining the forwarder. Specifically:
*
* - Returns true if there are no unprocessed bytes from the pty, false otherwise
*
* - Makes sure the handler function is called the next time the number of unprocessed bytes hits zero
*/
/* Starts draining the forwarder. This makes sure the handler function is called the next time the
* number of unprocessed bytes hits zero. */
f->drain = true;
return drained(f);
return pty_forward_add_defer(f);
}
int pty_forward_set_priority(PTYForward *f, int64_t priority) {
+1 -1
View File
@@ -34,7 +34,7 @@ bool pty_forward_vhangup_honored(const PTYForward *f);
void pty_forward_set_hangup_handler(PTYForward *f, PTYForwardHangupHandler handler, void *userdata);
void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler handler, void *userdata);
bool pty_forward_drain(PTYForward *f);
int pty_forward_drain(PTYForward *f);
int pty_forward_set_priority(PTYForward *f, int64_t priority);