Fix typos
[TortoiseGit.git] / src / TortoisePlink / Windows / handle-wait.c
blobd6ab6e40abdec555209ca2c7c44f1529f52ca739
1 /*
2 * handle-wait.c: Manage a collection of HANDLEs to wait for (in a
3 * WaitFor{Single,Multiple}Objects sense), each with a callback to be
4 * called when it's activated. Tracks the list, and provides an API to
5 * event loops that let them get a list of things to wait for and a
6 * way to call back to here when one of them does something.
7 */
9 /*
10 * TODO: currently this system can't cope with more than
11 * MAXIMUM_WAIT_OBJECTS (= 64) handles at a time. It enforces that by
12 * assertion, so we'll at least find out if that assumption is ever
13 * violated.
15 * It should be OK for the moment. As of 2021-05-24, the only uses of
16 * this system are by the ConPTY backend (just once, to watch for its
17 * subprocess terminating); by Pageant (for the event that the
18 * WM_COPYDATA subthread uses to signal the main thread); and by
19 * named-pipe-server.c (once per named-pipe server, of which there is
20 * one in Pageant and one in connection-sharing upstreams). So the
21 * total number of handles has a pretty small upper bound.
23 * But sooner or later, I'm sure we'll find a reason why we really
24 * need to watch a squillion handles at once. When that happens, I
25 * can't see any alternative to setting up some kind of tree of
26 * subthreads in this module, each one condensing 64 of our handles
27 * into one, by doing its own WaitForMultipleObjects and setting an
28 * event object to indicate that one of them did something. It'll be
29 * horribly ugly.
32 #include "putty.h"
34 struct HandleWait {
35 HANDLE handle;
36 handle_wait_callback_fn_t callback;
37 void *callback_ctx;
39 int index; /* sort key for tree234 */
42 struct HandleWaitListInner {
43 HandleWait *hws[MAXIMUM_WAIT_OBJECTS];
44 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
46 struct HandleWaitList hwl;
49 static int handlewait_cmp(void *av, void *bv)
51 HandleWait *a = (HandleWait *)av, *b = (HandleWait *)bv;
52 if (a->index < b->index)
53 return -1;
54 if (a->index > b->index)
55 return +1;
56 return 0;
59 static tree234 *handlewaits_tree_real;
61 static inline tree234 *ensure_handlewaits_tree_exists(void)
63 if (!handlewaits_tree_real)
64 handlewaits_tree_real = newtree234(handlewait_cmp);
65 return handlewaits_tree_real;
68 static int allocate_index(void)
70 tree234 *t = ensure_handlewaits_tree_exists();
71 search234_state st[1];
73 search234_start(st, t);
74 while (st->element) {
75 HandleWait *hw = (HandleWait *)st->element;
76 if (st->index < hw->index) {
77 /* There are unused index slots to the left of this element */
78 search234_step(st, -1);
79 } else {
80 assert(st->index == hw->index);
81 search234_step(st, +1);
85 return st->index;
88 HandleWait *add_handle_wait(HANDLE h, handle_wait_callback_fn_t callback,
89 void *callback_ctx)
91 HandleWait *hw = snew(HandleWait);
92 hw->handle = h;
93 hw->callback = callback;
94 hw->callback_ctx = callback_ctx;
96 tree234 *t = ensure_handlewaits_tree_exists();
97 hw->index = allocate_index();
98 HandleWait *added = add234(t, hw);
99 assert(added == hw);
101 return hw;
104 void delete_handle_wait(HandleWait *hw)
106 tree234 *t = ensure_handlewaits_tree_exists();
107 HandleWait *deleted = del234(t, hw);
108 assert(deleted == hw);
109 sfree(hw);
112 HandleWaitList *get_handle_wait_list(void)
114 tree234 *t = ensure_handlewaits_tree_exists();
115 struct HandleWaitListInner *hwli = snew(struct HandleWaitListInner);
116 size_t n = 0;
117 HandleWait *hw;
118 for (int i = 0; (hw = index234(t, i)) != NULL; i++) {
119 assert(n < MAXIMUM_WAIT_OBJECTS);
120 hwli->hws[n] = hw;
121 hwli->hwl.handles[n] = hw->handle;
122 n++;
124 hwli->hwl.nhandles = n;
125 return &hwli->hwl;
128 void handle_wait_activate(HandleWaitList *hwl, int index)
130 struct HandleWaitListInner *hwli =
131 container_of(hwl, struct HandleWaitListInner, hwl);
132 assert(0 <= index);
133 assert(index < hwli->hwl.nhandles);
134 HandleWait *hw = hwli->hws[index];
135 hw->callback(hw->callback_ctx);
138 void handle_wait_list_free(HandleWaitList *hwl)
140 struct HandleWaitListInner *hwli =
141 container_of(hwl, struct HandleWaitListInner, hwl);
142 sfree(hwli);