From: Yu Watanabe Date: Mon, 28 Jul 2025 20:13:30 +0000 (+0900) Subject: ptyfwd,run: make pty_forward_drain() trigger defer event to call shovel() X-Git-Tag: v258-rc2~38^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dce66b06880980c46896c7dbcde89491c704fed9;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/run/run.c b/src/run/run.c index 69d0490e57d..99aad5df776 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -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; } diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index bc312f17019..2b1154f5fa1 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -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) { diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index eb6d2807c08..1983a1cd16f 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -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);