| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | /* * 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;}#ifndef WINSCPstatic tree234 *handlewaits_tree_real;#endifstatic inline tree234 *ensure_handlewaits_tree_exists(struct callback_set * callback_set){    if (!callback_set->handlewaits_tree_real)        callback_set->handlewaits_tree_real = newtree234(handlewait_cmp);    return callback_set->handlewaits_tree_real;}static int allocate_index(struct callback_set * callback_set){    tree234 *t = ensure_handlewaits_tree_exists(callback_set);    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(struct callback_set * callback_set, 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;    { // WINSCP    tree234 *t = ensure_handlewaits_tree_exists(callback_set);    hw->index = allocate_index(callback_set);    { // WINSCP    HandleWait *added = add234(t, hw);    assert(added == hw);    return hw;    } // WINSCP    } // WINSCP}void delete_handle_wait(struct callback_set * callback_set, HandleWait *hw){    tree234 *t = ensure_handlewaits_tree_exists(callback_set);    HandleWait *deleted = del234(t, hw);    assert(deleted == hw);    sfree(hw);}HandleWaitList *get_handle_wait_list(struct callback_set * callback_set){    tree234 *t = ensure_handlewaits_tree_exists(callback_set);    struct HandleWaitListInner *hwli = snew(struct HandleWaitListInner);    size_t n = 0;    HandleWait *hw;    int i; // WINSCP    for (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;}bool handle_wait_activate(struct callback_set * callback_set, HandleWaitList *hwl, int index){    struct HandleWaitListInner *hwli =        container_of(hwl, struct HandleWaitListInner, hwl);    assert(0 <= index);    assert(index < hwli->hwl.nhandles);    { // WINSCP    HandleWait *hw = hwli->hws[index];    return hw->callback(callback_set, hw->callback_ctx);    } // WINSCP}void handle_wait_list_free(HandleWaitList *hwl){    struct HandleWaitListInner *hwli =        container_of(hwl, struct HandleWaitListInner, hwl);    sfree(hwli);}
 |