aboutsummaryrefslogtreecommitdiff
path: root/tools/plink/callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/plink/callback.c')
-rw-r--r--tools/plink/callback.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/tools/plink/callback.c b/tools/plink/callback.c
new file mode 100644
index 000000000..c70dc53fb
--- /dev/null
+++ b/tools/plink/callback.c
@@ -0,0 +1,74 @@
+/*
+ * Facility for queueing callback functions to be run from the
+ * top-level event loop after the current top-level activity finishes.
+ */
+
+#include <stddef.h>
+
+#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;
+}