mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 01:18:00 +00:00
9f4bd6c552
Enthusiastic copy-paste: in commit 17c57e1078
I added the same
precautionary call to ensure_handlewaits_tree_exists() everywhere,
even in functions that didn't actually need to use the tree.
144 lines
4.2 KiB
C
144 lines
4.2 KiB
C
/*
|
|
* handle-wait.c: Manage a collection of HANDLEs to wait for (in a
|
|
* WaitFor{Single,Multiple}Objects sense), each with a callback to be
|
|
* called when it's activated. Tracks the list, and provides an API to
|
|
* event loops that let them get a list of things to wait for and a
|
|
* way to call back to here when one of them does something.
|
|
*/
|
|
|
|
/*
|
|
* TODO: currently this system can't cope with more than
|
|
* MAXIMUM_WAIT_OBJECTS (= 64) handles at a time. It enforces that by
|
|
* assertion, so we'll at least find out if that assumption is ever
|
|
* violated.
|
|
*
|
|
* It should be OK for the moment. As of 2021-05-24, the only uses of
|
|
* this system are by the ConPTY backend (just once, to watch for its
|
|
* subprocess terminating); by Pageant (for the event that the
|
|
* WM_COPYDATA subthread uses to signal the main thread); and by
|
|
* named-pipe-server.c (once per named-pipe server, of which there is
|
|
* one in Pageant and one in connection-sharing upstreams). So the
|
|
* total number of handles has a pretty small upper bound.
|
|
*
|
|
* But sooner or later, I'm sure we'll find a reason why we really
|
|
* need to watch a squillion handles at once. When that happens, I
|
|
* can't see any alternative to setting up some kind of tree of
|
|
* subthreads in this module, each one condensing 64 of our handles
|
|
* into one, by doing its own WaitForMultipleObjects and setting an
|
|
* event object to indicate that one of them did something. It'll be
|
|
* horribly ugly.
|
|
*/
|
|
|
|
#include "putty.h"
|
|
|
|
struct HandleWait {
|
|
HANDLE handle;
|
|
handle_wait_callback_fn_t callback;
|
|
void *callback_ctx;
|
|
|
|
int index; /* sort key for tree234 */
|
|
};
|
|
|
|
struct HandleWaitListInner {
|
|
HandleWait *hws[MAXIMUM_WAIT_OBJECTS];
|
|
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
|
|
|
struct HandleWaitList hwl;
|
|
};
|
|
|
|
static int handlewait_cmp(void *av, void *bv)
|
|
{
|
|
HandleWait *a = (HandleWait *)av, *b = (HandleWait *)bv;
|
|
if (a->index < b->index)
|
|
return -1;
|
|
if (a->index > b->index)
|
|
return +1;
|
|
return 0;
|
|
}
|
|
|
|
static tree234 *handlewaits_tree_real;
|
|
|
|
static inline tree234 *ensure_handlewaits_tree_exists(void)
|
|
{
|
|
if (!handlewaits_tree_real)
|
|
handlewaits_tree_real = newtree234(handlewait_cmp);
|
|
return handlewaits_tree_real;
|
|
}
|
|
|
|
static int allocate_index(void)
|
|
{
|
|
tree234 *t = ensure_handlewaits_tree_exists();
|
|
search234_state st[1];
|
|
|
|
search234_start(st, t);
|
|
while (st->element) {
|
|
HandleWait *hw = (HandleWait *)st->element;
|
|
if (st->index < hw->index) {
|
|
/* There are unused index slots to the left of this element */
|
|
search234_step(st, -1);
|
|
} else {
|
|
assert(st->index == hw->index);
|
|
search234_step(st, +1);
|
|
}
|
|
}
|
|
|
|
return st->index;
|
|
}
|
|
|
|
HandleWait *add_handle_wait(HANDLE h, handle_wait_callback_fn_t callback,
|
|
void *callback_ctx)
|
|
{
|
|
HandleWait *hw = snew(HandleWait);
|
|
hw->handle = h;
|
|
hw->callback = callback;
|
|
hw->callback_ctx = callback_ctx;
|
|
|
|
tree234 *t = ensure_handlewaits_tree_exists();
|
|
hw->index = allocate_index();
|
|
HandleWait *added = add234(t, hw);
|
|
assert(added == hw);
|
|
|
|
return hw;
|
|
}
|
|
|
|
void delete_handle_wait(HandleWait *hw)
|
|
{
|
|
tree234 *t = ensure_handlewaits_tree_exists();
|
|
HandleWait *deleted = del234(t, hw);
|
|
assert(deleted == hw);
|
|
sfree(hw);
|
|
}
|
|
|
|
HandleWaitList *get_handle_wait_list(void)
|
|
{
|
|
tree234 *t = ensure_handlewaits_tree_exists();
|
|
struct HandleWaitListInner *hwli = snew(struct HandleWaitListInner);
|
|
size_t n = 0;
|
|
HandleWait *hw;
|
|
for (int i = 0; (hw = index234(t, i)) != NULL; i++) {
|
|
assert(n < MAXIMUM_WAIT_OBJECTS);
|
|
hwli->hws[n] = hw;
|
|
hwli->hwl.handles[n] = hw->handle;
|
|
n++;
|
|
}
|
|
hwli->hwl.nhandles = n;
|
|
return &hwli->hwl;
|
|
}
|
|
|
|
void handle_wait_activate(HandleWaitList *hwl, int index)
|
|
{
|
|
struct HandleWaitListInner *hwli =
|
|
container_of(hwl, struct HandleWaitListInner, hwl);
|
|
assert(0 <= index);
|
|
assert(index < hwli->hwl.nhandles);
|
|
HandleWait *hw = hwli->hws[index];
|
|
hw->callback(hw->callback_ctx);
|
|
}
|
|
|
|
void handle_wait_list_free(HandleWaitList *hwl)
|
|
{
|
|
struct HandleWaitListInner *hwli =
|
|
container_of(hwl, struct HandleWaitListInner, hwl);
|
|
sfree(hwli);
|
|
}
|