/* * Facility for queueing callback functions to be run from the * top-level event loop after the current top-level activity finishes. */ #include #include "putty.h" struct callback { struct callback *next; toplevel_callback_fn_t fn; void *ctx; }; struct callback *cbhead = NULL, *cbtail = NULL; toplevel_callback_notify_fn_t notify_frontend = NULL; void *frontend = NULL; void request_callback_notifications(toplevel_callback_notify_fn_t fn, void *fr) { notify_frontend = fn; frontend = fr; } void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx) { struct callback *cb; cb = snew(struct callback); cb->fn = fn; cb->ctx = ctx; /* If the front end has requested notification of pending * callbacks, and we didn't already have one queued, let it know * we do have one now. */ if (notify_frontend && !cbhead) notify_frontend(frontend); if (cbtail) cbtail->next = cb; else cbhead = cb; cbtail = cb; cb->next = NULL; } void run_toplevel_callbacks(void) { if (cbhead) { struct callback *cb = cbhead; /* * Careful ordering here. We call the function _before_ * advancing cbhead (though, of course, we must free cb * _after_ advancing it). This means that if the very last * callback schedules another callback, cbhead does not become * NULL at any point, and so the frontend notification * function won't be needlessly pestered. */ cb->fn(cb->ctx); cbhead = cb->next; sfree(cb); if (!cbhead) cbtail = NULL; } } int toplevel_callback_pending(void) { return cbhead != NULL; }