mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 01:48:00 +00:00
Only run one toplevel callback per event loop iteration.
This change attempts to reinstate as a universal property something which was sporadically true of the ad-hockery that came before toplevel callbacks: that if there's a _very long_ queue of things to be done through the callback mechanism, the doing of them will be interleaved with re-checks of other event sources, which might (e.g.) cause a flag to be set which makes the next callback decide not to do anything after all. [originally from svn r10040]
This commit is contained in:
parent
043a762b5f
commit
5c4ce2fadf
34
callback.c
34
callback.c
@ -26,10 +26,28 @@ void request_callback_notifications(toplevel_callback_notify_fn_t fn,
|
|||||||
frontend = fr;
|
frontend = fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void stoat_callback(void *ctx)
|
||||||
|
{
|
||||||
|
static int stoat = 0;
|
||||||
|
if (++stoat % 1000 == 0)
|
||||||
|
debug(("stoat %d\n", stoat));
|
||||||
|
queue_toplevel_callback(stoat_callback, NULL);
|
||||||
|
}
|
||||||
|
void queue_stoat(void)
|
||||||
|
{
|
||||||
|
static int stoat = 0;
|
||||||
|
if (!stoat) {
|
||||||
|
stoat = 1;
|
||||||
|
queue_toplevel_callback(stoat_callback, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
||||||
{
|
{
|
||||||
struct callback *cb;
|
struct callback *cb;
|
||||||
|
|
||||||
|
queue_stoat();
|
||||||
|
|
||||||
cb = snew(struct callback);
|
cb = snew(struct callback);
|
||||||
cb->fn = fn;
|
cb->fn = fn;
|
||||||
cb->ctx = ctx;
|
cb->ctx = ctx;
|
||||||
@ -50,19 +68,27 @@ void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
|
|||||||
|
|
||||||
void run_toplevel_callbacks(void)
|
void run_toplevel_callbacks(void)
|
||||||
{
|
{
|
||||||
while (cbhead) {
|
queue_stoat();
|
||||||
|
if (cbhead) {
|
||||||
struct callback *cb = cbhead;
|
struct callback *cb = cbhead;
|
||||||
/*
|
/*
|
||||||
* Careful ordering here. We call the function _before_
|
* Careful ordering here. We call the function _before_
|
||||||
* advancing cbhead (though, of course, we must free cb
|
* advancing cbhead (though, of course, we must free cb
|
||||||
* _after_ advancing it). This means that if the very last
|
* _after_ advancing it). This means that if the very last
|
||||||
* callback schedules another callback, cbhead does not become
|
* callback schedules another callback, cbhead does not become
|
||||||
* NULL at any point in this while loop, and so the frontend
|
* NULL at any point, and so the frontend notification
|
||||||
* notification function won't be needlessly pestered.
|
* function won't be needlessly pestered.
|
||||||
*/
|
*/
|
||||||
cb->fn(cb->ctx);
|
cb->fn(cb->ctx);
|
||||||
cbhead = cb->next;
|
cbhead = cb->next;
|
||||||
sfree(cb);
|
sfree(cb);
|
||||||
|
if (!cbhead)
|
||||||
|
cbtail = NULL;
|
||||||
}
|
}
|
||||||
cbtail = NULL;
|
}
|
||||||
|
|
||||||
|
int toplevel_callback_pending(void)
|
||||||
|
{
|
||||||
|
queue_stoat();
|
||||||
|
return cbhead != NULL;
|
||||||
}
|
}
|
||||||
|
7
putty.h
7
putty.h
@ -1403,11 +1403,16 @@ void timer_change_notify(unsigned long next);
|
|||||||
* top-level event loop. However, if a front end doesn't have control
|
* top-level event loop. However, if a front end doesn't have control
|
||||||
* over its own event loop (e.g. because it's using GTK) then it can
|
* over its own event loop (e.g. because it's using GTK) then it can
|
||||||
* instead request notifications when a callback is available, so that
|
* instead request notifications when a callback is available, so that
|
||||||
* it knows to ask its delegate event loop to do the same thing.
|
* it knows to ask its delegate event loop to do the same thing. Also,
|
||||||
|
* if a front end needs to know whether a callback is pending without
|
||||||
|
* 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.
|
||||||
*/
|
*/
|
||||||
typedef void (*toplevel_callback_fn_t)(void *ctx);
|
typedef void (*toplevel_callback_fn_t)(void *ctx);
|
||||||
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx);
|
void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx);
|
||||||
void run_toplevel_callbacks(void);
|
void run_toplevel_callbacks(void);
|
||||||
|
int toplevel_callback_pending(void);
|
||||||
|
|
||||||
typedef void (*toplevel_callback_notify_fn_t)(void *frontend);
|
typedef void (*toplevel_callback_notify_fn_t)(void *frontend);
|
||||||
void request_callback_notifications(toplevel_callback_notify_fn_t notify,
|
void request_callback_notifications(toplevel_callback_notify_fn_t notify,
|
||||||
|
@ -1422,7 +1422,8 @@ static gint idle_toplevel_callback_func(gpointer data)
|
|||||||
run_toplevel_callbacks();
|
run_toplevel_callbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_idle_remove(inst->toplevel_callback_idle_id);
|
if (!toplevel_callback_pending())
|
||||||
|
gtk_idle_remove(inst->toplevel_callback_idle_id);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -979,6 +979,7 @@ int main(int argc, char **argv)
|
|||||||
int maxfd;
|
int maxfd;
|
||||||
int rwx;
|
int rwx;
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned long next;
|
||||||
|
|
||||||
FD_ZERO(&rset);
|
FD_ZERO(&rset);
|
||||||
FD_ZERO(&wset);
|
FD_ZERO(&wset);
|
||||||
@ -1032,12 +1033,17 @@ int main(int argc, char **argv)
|
|||||||
FD_SET_MAX(fd, maxfd, xset);
|
FD_SET_MAX(fd, maxfd, xset);
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
if (toplevel_callback_pending()) {
|
||||||
unsigned long next, then;
|
struct timeval tv;
|
||||||
long ticks;
|
tv.tv_sec = 0;
|
||||||
struct timeval tv, *ptv;
|
tv.tv_usec = 0;
|
||||||
|
ret = select(maxfd, &rset, &wset, &xset, &tv);
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
|
do {
|
||||||
|
unsigned long then;
|
||||||
|
long ticks;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
if (run_timers(now, &next)) {
|
|
||||||
then = now;
|
then = now;
|
||||||
now = GETTICKCOUNT();
|
now = GETTICKCOUNT();
|
||||||
if (now - then > next - then)
|
if (now - then > next - then)
|
||||||
@ -1046,16 +1052,15 @@ int main(int argc, char **argv)
|
|||||||
ticks = next - now;
|
ticks = next - now;
|
||||||
tv.tv_sec = ticks / 1000;
|
tv.tv_sec = ticks / 1000;
|
||||||
tv.tv_usec = ticks % 1000 * 1000;
|
tv.tv_usec = ticks % 1000 * 1000;
|
||||||
ptv = &tv;
|
ret = select(maxfd, &rset, &wset, &xset, &tv);
|
||||||
} else {
|
if (ret == 0)
|
||||||
ptv = NULL;
|
now = next;
|
||||||
}
|
else
|
||||||
ret = select(maxfd, &rset, &wset, &xset, ptv);
|
now = GETTICKCOUNT();
|
||||||
if (ret == 0)
|
} while (ret < 0 && errno == EINTR);
|
||||||
now = next;
|
} else {
|
||||||
else
|
ret = select(maxfd, &rset, &wset, &xset, NULL);
|
||||||
now = GETTICKCOUNT();
|
}
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
perror("select");
|
perror("select");
|
||||||
|
@ -444,6 +444,7 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok)
|
|||||||
int i, fdcount, fdsize, *fdlist;
|
int i, fdcount, fdsize, *fdlist;
|
||||||
int fd, fdstate, rwx, ret, maxfd;
|
int fd, fdstate, rwx, ret, maxfd;
|
||||||
unsigned long now = GETTICKCOUNT();
|
unsigned long now = GETTICKCOUNT();
|
||||||
|
unsigned long next;
|
||||||
|
|
||||||
fdlist = NULL;
|
fdlist = NULL;
|
||||||
fdcount = fdsize = 0;
|
fdcount = fdsize = 0;
|
||||||
@ -488,12 +489,19 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok)
|
|||||||
if (include_stdin)
|
if (include_stdin)
|
||||||
FD_SET_MAX(0, maxfd, rset);
|
FD_SET_MAX(0, maxfd, rset);
|
||||||
|
|
||||||
do {
|
if (toplevel_callback_pending()) {
|
||||||
unsigned long next, then;
|
struct timeval tv;
|
||||||
long ticks;
|
tv.tv_sec = 0;
|
||||||
struct timeval tv, *ptv;
|
tv.tv_usec = 0;
|
||||||
|
ret = select(maxfd, &rset, &wset, &xset, &tv);
|
||||||
|
if (ret == 0)
|
||||||
|
run_toplevel_callbacks();
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
|
do {
|
||||||
|
unsigned long then;
|
||||||
|
long ticks;
|
||||||
|
struct timeval tv;
|
||||||
|
|
||||||
if (run_timers(now, &next)) {
|
|
||||||
then = now;
|
then = now;
|
||||||
now = GETTICKCOUNT();
|
now = GETTICKCOUNT();
|
||||||
if (now - then > next - then)
|
if (now - then > next - then)
|
||||||
@ -502,16 +510,15 @@ static int ssh_sftp_do_select(int include_stdin, int no_fds_ok)
|
|||||||
ticks = next - now;
|
ticks = next - now;
|
||||||
tv.tv_sec = ticks / 1000;
|
tv.tv_sec = ticks / 1000;
|
||||||
tv.tv_usec = ticks % 1000 * 1000;
|
tv.tv_usec = ticks % 1000 * 1000;
|
||||||
ptv = &tv;
|
ret = select(maxfd, &rset, &wset, &xset, &tv);
|
||||||
} else {
|
if (ret == 0)
|
||||||
ptv = NULL;
|
now = next;
|
||||||
}
|
else
|
||||||
ret = select(maxfd, &rset, &wset, &xset, ptv);
|
now = GETTICKCOUNT();
|
||||||
if (ret == 0)
|
} while (ret < 0 && errno == EINTR);
|
||||||
now = next;
|
} else {
|
||||||
else
|
ret = select(maxfd, &rset, &wset, &xset, NULL);
|
||||||
now = GETTICKCOUNT();
|
}
|
||||||
} while (ret < 0 && errno != EINTR);
|
|
||||||
} while (ret == 0);
|
} while (ret == 0);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
@ -847,11 +847,20 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
while (1) {
|
while (1) {
|
||||||
HANDLE *handles;
|
HANDLE *handles;
|
||||||
int nhandles, n;
|
int nhandles, n;
|
||||||
|
DWORD timeout;
|
||||||
|
|
||||||
|
if (toplevel_callback_pending()) {
|
||||||
|
timeout = 0;
|
||||||
|
} else {
|
||||||
|
timeout = INFINITE;
|
||||||
|
/* The messages seem unreliable; especially if we're being tricky */
|
||||||
|
term_set_focus(term, GetForegroundWindow() == hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
handles = handle_get_events(&nhandles);
|
handles = handle_get_events(&nhandles);
|
||||||
|
|
||||||
n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, INFINITE,
|
n = MsgWaitForMultipleObjects(nhandles, handles, FALSE,
|
||||||
QS_ALLINPUT);
|
timeout, QS_ALLINPUT);
|
||||||
|
|
||||||
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
|
if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) {
|
||||||
handle_got_event(handles[n - WAIT_OBJECT_0]);
|
handle_got_event(handles[n - WAIT_OBJECT_0]);
|
||||||
@ -859,20 +868,15 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
|
|||||||
} else
|
} else
|
||||||
sfree(handles);
|
sfree(handles);
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
|
||||||
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
||||||
if (msg.message == WM_QUIT)
|
if (msg.message == WM_QUIT)
|
||||||
goto finished; /* two-level break */
|
goto finished; /* two-level break */
|
||||||
|
|
||||||
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
|
if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg)))
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
|
|
||||||
run_toplevel_callbacks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The messages seem unreliable; especially if we're being tricky */
|
run_toplevel_callbacks();
|
||||||
term_set_focus(term, GetForegroundWindow() == hwnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
finished:
|
finished:
|
||||||
|
@ -648,7 +648,9 @@ int main(int argc, char **argv)
|
|||||||
sending = TRUE;
|
sending = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (run_timers(now, &next)) {
|
if (toplevel_callback_pending()) {
|
||||||
|
ticks = 0;
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
then = now;
|
then = now;
|
||||||
now = GETTICKCOUNT();
|
now = GETTICKCOUNT();
|
||||||
if (now - then > next - then)
|
if (now - then > next - then)
|
||||||
|
@ -493,7 +493,9 @@ int do_eventsel_loop(HANDLE other_event)
|
|||||||
int skcount;
|
int skcount;
|
||||||
unsigned long now = GETTICKCOUNT();
|
unsigned long now = GETTICKCOUNT();
|
||||||
|
|
||||||
if (run_timers(now, &next)) {
|
if (toplevel_callback_pending()) {
|
||||||
|
ticks = 0;
|
||||||
|
} else if (run_timers(now, &next)) {
|
||||||
then = now;
|
then = now;
|
||||||
now = GETTICKCOUNT();
|
now = GETTICKCOUNT();
|
||||||
if (now - then > next - then)
|
if (now - then > next - then)
|
||||||
|
Loading…
Reference in New Issue
Block a user