Fix typos
[TortoiseGit.git] / src / TortoisePlink / callback.c
blob8c3696b2b841811289e5df44869f86a009e5b59e
1 /*
2 * Facility for queueing callback functions to be run from the
3 * top-level event loop after the current top-level activity finishes.
4 */
6 #include <stddef.h>
8 #include "putty.h"
10 struct callback {
11 struct callback *next;
13 toplevel_callback_fn_t fn;
14 void *ctx;
17 static struct callback *cbcurr = NULL, *cbhead = NULL, *cbtail = NULL;
19 static toplevel_callback_notify_fn_t notify_frontend = NULL;
20 static void *notify_ctx = NULL;
22 void request_callback_notifications(toplevel_callback_notify_fn_t fn,
23 void *ctx)
25 notify_frontend = fn;
26 notify_ctx = ctx;
29 static void run_idempotent_callback(void *ctx)
31 struct IdempotentCallback *ic = (struct IdempotentCallback *)ctx;
32 ic->queued = false;
33 ic->fn(ic->ctx);
36 void queue_idempotent_callback(struct IdempotentCallback *ic)
38 if (ic->queued)
39 return;
40 ic->queued = true;
41 queue_toplevel_callback(run_idempotent_callback, ic);
44 void delete_callbacks_for_context(void *ctx)
46 struct callback *newhead, *newtail;
48 newhead = newtail = NULL;
49 while (cbhead) {
50 struct callback *cb = cbhead;
51 cbhead = cbhead->next;
52 if (cb->ctx == ctx ||
53 (cb->fn == run_idempotent_callback &&
54 ((struct IdempotentCallback *)cb->ctx)->ctx == ctx)) {
55 sfree(cb);
56 } else {
57 if (!newhead)
58 newhead = cb;
59 else
60 newtail->next = cb;
62 newtail = cb;
66 cbhead = newhead;
67 cbtail = newtail;
68 if (newtail)
69 newtail->next = NULL;
72 void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
74 struct callback *cb;
76 cb = snew(struct callback);
77 cb->fn = fn;
78 cb->ctx = ctx;
81 * If the front end has requested notification of pending
82 * callbacks, and we didn't already have one queued, let it know
83 * we do have one now.
85 * If cbcurr is non-NULL, i.e. we are actually in the middle of
86 * executing a callback right now, then we count that as the queue
87 * already having been non-empty. That saves the front end getting
88 * a constant stream of needless re-notifications if the last
89 * callback keeps re-scheduling itself.
91 if (notify_frontend && !cbhead && !cbcurr)
92 notify_frontend(notify_ctx);
94 if (cbtail)
95 cbtail->next = cb;
96 else
97 cbhead = cb;
98 cbtail = cb;
99 cb->next = NULL;
102 bool run_toplevel_callbacks(void)
104 bool done_something = false;
106 if (cbhead) {
108 * Transfer the head callback into cbcurr to indicate that
109 * it's being executed. Then operations which transform the
110 * queue, like delete_callbacks_for_context, can proceed as if
111 * it's not there.
113 cbcurr = cbhead;
114 cbhead = cbhead->next;
115 if (!cbhead)
116 cbtail = NULL;
119 * Now run the callback, and then clear it out of cbcurr.
121 cbcurr->fn(cbcurr->ctx);
122 sfree(cbcurr);
123 cbcurr = NULL;
125 done_something = true;
127 return done_something;
130 bool toplevel_callback_pending(void)
132 return cbcurr != NULL || cbhead != NULL;