handle-wait.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. */
  8. /*
  9. * TODO: currently this system can't cope with more than
  10. * MAXIMUM_WAIT_OBJECTS (= 64) handles at a time. It enforces that by
  11. * assertion, so we'll at least find out if that assumption is ever
  12. * violated.
  13. *
  14. * It should be OK for the moment. As of 2021-05-24, the only uses of
  15. * this system are by the ConPTY backend (just once, to watch for its
  16. * subprocess terminating); by Pageant (for the event that the
  17. * WM_COPYDATA subthread uses to signal the main thread); and by
  18. * named-pipe-server.c (once per named-pipe server, of which there is
  19. * one in Pageant and one in connection-sharing upstreams). So the
  20. * total number of handles has a pretty small upper bound.
  21. *
  22. * But sooner or later, I'm sure we'll find a reason why we really
  23. * need to watch a squillion handles at once. When that happens, I
  24. * can't see any alternative to setting up some kind of tree of
  25. * subthreads in this module, each one condensing 64 of our handles
  26. * into one, by doing its own WaitForMultipleObjects and setting an
  27. * event object to indicate that one of them did something. It'll be
  28. * horribly ugly.
  29. */
  30. #include "putty.h"
  31. struct HandleWait {
  32. HANDLE handle;
  33. handle_wait_callback_fn_t callback;
  34. void *callback_ctx;
  35. int index; /* sort key for tree234 */
  36. };
  37. struct HandleWaitListInner {
  38. HandleWait *hws[MAXIMUM_WAIT_OBJECTS];
  39. HANDLE handles[MAXIMUM_WAIT_OBJECTS];
  40. struct HandleWaitList hwl;
  41. };
  42. static int handlewait_cmp(void *av, void *bv)
  43. {
  44. HandleWait *a = (HandleWait *)av, *b = (HandleWait *)bv;
  45. if (a->index < b->index)
  46. return -1;
  47. if (a->index > b->index)
  48. return +1;
  49. return 0;
  50. }
  51. #ifndef WINSCP
  52. static tree234 *handlewaits_tree_real;
  53. #endif
  54. static inline tree234 *ensure_handlewaits_tree_exists(struct callback_set * callback_set)
  55. {
  56. if (!callback_set->handlewaits_tree_real)
  57. callback_set->handlewaits_tree_real = newtree234(handlewait_cmp);
  58. return callback_set->handlewaits_tree_real;
  59. }
  60. static int allocate_index(struct callback_set * callback_set)
  61. {
  62. tree234 *t = ensure_handlewaits_tree_exists(callback_set);
  63. search234_state st[1];
  64. search234_start(st, t);
  65. while (st->element) {
  66. HandleWait *hw = (HandleWait *)st->element;
  67. if (st->index < hw->index) {
  68. /* There are unused index slots to the left of this element */
  69. search234_step(st, -1);
  70. } else {
  71. assert(st->index == hw->index);
  72. search234_step(st, +1);
  73. }
  74. }
  75. return st->index;
  76. }
  77. HandleWait *add_handle_wait(struct callback_set * callback_set, HANDLE h, handle_wait_callback_fn_t callback,
  78. void *callback_ctx)
  79. {
  80. HandleWait *hw = snew(HandleWait);
  81. hw->handle = h;
  82. hw->callback = callback;
  83. hw->callback_ctx = callback_ctx;
  84. { // WINSCP
  85. tree234 *t = ensure_handlewaits_tree_exists(callback_set);
  86. hw->index = allocate_index(callback_set);
  87. { // WINSCP
  88. HandleWait *added = add234(t, hw);
  89. assert(added == hw);
  90. return hw;
  91. } // WINSCP
  92. } // WINSCP
  93. }
  94. void delete_handle_wait(struct callback_set * callback_set, HandleWait *hw)
  95. {
  96. tree234 *t = ensure_handlewaits_tree_exists(callback_set);
  97. HandleWait *deleted = del234(t, hw);
  98. assert(deleted == hw);
  99. sfree(hw);
  100. }
  101. HandleWaitList *get_handle_wait_list(struct callback_set * callback_set)
  102. {
  103. tree234 *t = ensure_handlewaits_tree_exists(callback_set);
  104. struct HandleWaitListInner *hwli = snew(struct HandleWaitListInner);
  105. size_t n = 0;
  106. HandleWait *hw;
  107. int i; // WINSCP
  108. for (i = 0; (hw = index234(t, i)) != NULL; i++) {
  109. assert(n < MAXIMUM_WAIT_OBJECTS);
  110. hwli->hws[n] = hw;
  111. hwli->hwl.handles[n] = hw->handle;
  112. n++;
  113. }
  114. hwli->hwl.nhandles = n;
  115. return &hwli->hwl;
  116. }
  117. bool handle_wait_activate(struct callback_set * callback_set, HandleWaitList *hwl, int index)
  118. {
  119. struct HandleWaitListInner *hwli =
  120. container_of(hwl, struct HandleWaitListInner, hwl);
  121. assert(0 <= index);
  122. assert(index < hwli->hwl.nhandles);
  123. { // WINSCP
  124. HandleWait *hw = hwli->hws[index];
  125. return hw->callback(callback_set, hw->callback_ctx);
  126. } // WINSCP
  127. }
  128. void handle_wait_list_free(HandleWaitList *hwl)
  129. {
  130. struct HandleWaitListInner *hwli =
  131. container_of(hwl, struct HandleWaitListInner, hwl);
  132. sfree(hwli);
  133. }