diff --git a/callback.c b/callback.c index 3273002a..10f923d0 100644 --- a/callback.c +++ b/callback.c @@ -97,8 +97,10 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) cb->next = NULL; } -void run_toplevel_callbacks(void) +int run_toplevel_callbacks(void) { + int done_something = FALSE; + if (cbhead) { /* * Transfer the head callback into cbcurr to indicate that @@ -117,7 +119,10 @@ void run_toplevel_callbacks(void) cbcurr->fn(cbcurr->ctx); sfree(cbcurr); cbcurr = NULL; + + done_something = TRUE; } + return done_something; } int toplevel_callback_pending(void) diff --git a/putty.h b/putty.h index a8cfcf27..7555aede 100644 --- a/putty.h +++ b/putty.h @@ -1595,10 +1595,15 @@ unsigned long timing_last_clock(void); * actually running it (e.g. so as to put a zero timeout on a select() * call) then it can call toplevel_callback_pending(), which will * return true if at least one callback is in the queue. + * + * run_toplevel_callbacks() returns TRUE if it ran any actual code. + * This can be used as a means of speculatively terminating a select + * loop, as in PSFTP, for example - if a callback has run then perhaps + * it might have done whatever the loop's caller was waiting for. */ typedef void (*toplevel_callback_fn_t)(void *ctx); void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx); -void run_toplevel_callbacks(void); +int run_toplevel_callbacks(void); int toplevel_callback_pending(void); void delete_callbacks_for_context(void *ctx); diff --git a/unix/uxsftp.c b/unix/uxsftp.c index 718a29c9..eb1329cf 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -459,6 +459,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) int fd, fdstate, rwx, ret, maxfd; unsigned long now = GETTICKCOUNT(); unsigned long next; + int done_something = FALSE; fdlist = NULL; fdcount = fdsize = 0; @@ -509,7 +510,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) tv.tv_usec = 0; ret = select(maxfd, &rset, &wset, &xset, &tv); if (ret == 0) - run_toplevel_callbacks(); + done_something |= run_toplevel_callbacks(); } else if (run_timers(now, &next)) { do { unsigned long then; @@ -535,7 +536,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok) ret = select(maxfd, &rset, &wset, &xset, NULL); } while (ret < 0 && errno == EINTR); } - } while (ret == 0); + } while (ret == 0 && !done_something); if (ret < 0) { perror("select");