]> asedeno.scripts.mit.edu Git - PuTTY_svn.git/blob - callback.c
Only run one toplevel callback per event loop iteration.
[PuTTY_svn.git] / callback.c
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  */
5
6 #include <stddef.h>
7
8 #include "putty.h"
9
10 struct callback {
11     struct callback *next;
12
13     toplevel_callback_fn_t fn;
14     void *ctx;
15 };
16
17 struct callback *cbhead = NULL, *cbtail = NULL;
18
19 toplevel_callback_notify_fn_t notify_frontend = NULL;
20 void *frontend = NULL;
21
22 void request_callback_notifications(toplevel_callback_notify_fn_t fn,
23                                     void *fr)
24 {
25     notify_frontend = fn;
26     frontend = fr;
27 }
28
29 void stoat_callback(void *ctx)
30 {
31     static int stoat = 0;
32     if (++stoat % 1000 == 0)
33         debug(("stoat %d\n", stoat));
34     queue_toplevel_callback(stoat_callback, NULL);
35 }
36 void queue_stoat(void)
37 {
38     static int stoat = 0;
39     if (!stoat) {
40         stoat = 1;
41         queue_toplevel_callback(stoat_callback, NULL);
42     }
43 }
44
45 void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
46 {
47     struct callback *cb;
48
49     queue_stoat();
50
51     cb = snew(struct callback);
52     cb->fn = fn;
53     cb->ctx = ctx;
54
55     /* If the front end has requested notification of pending
56      * callbacks, and we didn't already have one queued, let it know
57      * we do have one now. */
58     if (notify_frontend && !cbhead)
59         notify_frontend(frontend);
60
61     if (cbtail)
62         cbtail->next = cb;
63     else
64         cbhead = cb;
65     cbtail = cb;
66     cb->next = NULL;
67 }
68
69 void run_toplevel_callbacks(void)
70 {
71     queue_stoat();
72     if (cbhead) {
73         struct callback *cb = cbhead;
74         /*
75          * Careful ordering here. We call the function _before_
76          * advancing cbhead (though, of course, we must free cb
77          * _after_ advancing it). This means that if the very last
78          * callback schedules another callback, cbhead does not become
79          * NULL at any point, and so the frontend notification
80          * function won't be needlessly pestered.
81          */
82         cb->fn(cb->ctx);
83         cbhead = cb->next;
84         sfree(cb);
85         if (!cbhead)
86             cbtail = NULL;
87     }
88 }
89
90 int toplevel_callback_pending(void)
91 {
92     queue_stoat();
93     return cbhead != NULL;
94 }