callback.c 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * Facility for queueing callback functions to be run from the
  3. * top-level event loop after the current top-level activity finishes.
  4. */
  5. #include <stddef.h>
  6. #include "putty.h"
  7. struct callback {
  8. struct callback *next;
  9. toplevel_callback_fn_t fn;
  10. void *ctx;
  11. };
  12. struct callback *cbhead = NULL, *cbtail = NULL;
  13. toplevel_callback_notify_fn_t notify_frontend = NULL;
  14. void *frontend = NULL;
  15. void request_callback_notifications(toplevel_callback_notify_fn_t fn,
  16. void *fr)
  17. {
  18. MPEXT_PUTTY_SECTION_ENTER;
  19. notify_frontend = fn;
  20. frontend = fr;
  21. MPEXT_PUTTY_SECTION_LEAVE;
  22. }
  23. void queue_toplevel_callback(toplevel_callback_fn_t fn, void *ctx)
  24. {
  25. struct callback *cb;
  26. MPEXT_PUTTY_SECTION_ENTER;
  27. cb = snew(struct callback);
  28. cb->fn = fn;
  29. cb->ctx = ctx;
  30. /* If the front end has requested notification of pending
  31. * callbacks, and we didn't already have one queued, let it know
  32. * we do have one now. */
  33. if (notify_frontend && !cbhead)
  34. notify_frontend(frontend);
  35. if (cbtail)
  36. cbtail->next = cb;
  37. else
  38. cbhead = cb;
  39. cbtail = cb;
  40. cb->next = NULL;
  41. MPEXT_PUTTY_SECTION_LEAVE;
  42. }
  43. void run_toplevel_callbacks(void)
  44. {
  45. MPEXT_PUTTY_SECTION_ENTER;
  46. if (cbhead) {
  47. struct callback *cb = cbhead;
  48. #ifdef MPEXT
  49. toplevel_callback_fn_t fn = cb->fn;
  50. void * ctx = cb->ctx;
  51. cbhead = cb->next;
  52. if (!cbhead)
  53. cbtail = NULL;
  54. cbhead = cb->next;
  55. sfree(cb);
  56. MPEXT_PUTTY_SECTION_LEAVE;
  57. fn(ctx);
  58. #else
  59. /*
  60. * Careful ordering here. We call the function _before_
  61. * advancing cbhead (though, of course, we must free cb
  62. * _after_ advancing it). This means that if the very last
  63. * callback schedules another callback, cbhead does not become
  64. * NULL at any point, and so the frontend notification
  65. * function won't be needlessly pestered.
  66. */
  67. cb->fn(cb->ctx);
  68. cbhead = cb->next;
  69. sfree(cb);
  70. if (!cbhead)
  71. cbtail = NULL;
  72. #endif
  73. }
  74. #ifdef MPEXT
  75. else
  76. {
  77. MPEXT_PUTTY_SECTION_LEAVE;
  78. }
  79. #endif
  80. }
  81. int toplevel_callback_pending(void)
  82. {
  83. // MP does not have to be guarded
  84. return cbhead != NULL;
  85. }