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.
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
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
36 handle_wait_callback_fn_t callback
;
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
)
54 if (a
->index
> b
->index
)
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
);
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);
80 assert(st
->index
== hw
->index
);
81 search234_step(st
, +1);
88 HandleWait
*add_handle_wait(HANDLE h
, handle_wait_callback_fn_t callback
,
91 HandleWait
*hw
= snew(HandleWait
);
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
);
104 void delete_handle_wait(HandleWait
*hw
)
106 tree234
*t
= ensure_handlewaits_tree_exists();
107 HandleWait
*deleted
= del234(t
, hw
);
108 assert(deleted
== hw
);
112 HandleWaitList
*get_handle_wait_list(void)
114 tree234
*t
= ensure_handlewaits_tree_exists();
115 struct HandleWaitListInner
*hwli
= snew(struct HandleWaitListInner
);
118 for (int i
= 0; (hw
= index234(t
, i
)) != NULL
; i
++) {
119 assert(n
< MAXIMUM_WAIT_OBJECTS
);
121 hwli
->hwl
.handles
[n
] = hw
->handle
;
124 hwli
->hwl
.nhandles
= n
;
128 void handle_wait_activate(HandleWaitList
*hwl
, int index
)
130 struct HandleWaitListInner
*hwli
=
131 container_of(hwl
, struct HandleWaitListInner
, hwl
);
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
);