cliloop.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #include <errno.h>
  2. #include "putty.h"
  3. void cli_main_loop(cliloop_pw_setup_t pw_setup,
  4. cliloop_pw_check_t pw_check,
  5. cliloop_continue_t cont, void *ctx)
  6. {
  7. unsigned long now = GETTICKCOUNT();
  8. int *fdlist = NULL;
  9. size_t fdsize = 0;
  10. pollwrapper *pw = pollwrap_new();
  11. while (true) {
  12. int rwx;
  13. int ret;
  14. int fdstate;
  15. unsigned long next;
  16. pollwrap_clear(pw);
  17. if (!pw_setup(ctx, pw))
  18. break; /* our client signalled emergency exit */
  19. /* Count the currently active fds. */
  20. size_t nfds = 0;
  21. for (int fd = first_fd(&fdstate, &rwx); fd >= 0;
  22. fd = next_fd(&fdstate, &rwx))
  23. nfds++;
  24. /* Expand the fdlist buffer if necessary. */
  25. sgrowarray(fdlist, fdsize, nfds);
  26. /*
  27. * Add all currently open uxsel fds to pw, and store them in
  28. * fdlist as well.
  29. */
  30. size_t fdcount = 0;
  31. for (int fd = first_fd(&fdstate, &rwx); fd >= 0;
  32. fd = next_fd(&fdstate, &rwx)) {
  33. fdlist[fdcount++] = fd;
  34. pollwrap_add_fd_rwx(pw, fd, rwx);
  35. }
  36. if (toplevel_callback_pending()) {
  37. ret = pollwrap_poll_instant(pw);
  38. } else if (run_timers(now, &next)) {
  39. do {
  40. unsigned long then;
  41. long ticks;
  42. then = now;
  43. now = GETTICKCOUNT();
  44. if (now - then > next - then)
  45. ticks = 0;
  46. else
  47. ticks = next - now;
  48. bool overflow = false;
  49. if (ticks > INT_MAX) {
  50. ticks = INT_MAX;
  51. overflow = true;
  52. }
  53. ret = pollwrap_poll_timeout(pw, ticks);
  54. if (ret == 0 && !overflow)
  55. now = next;
  56. else
  57. now = GETTICKCOUNT();
  58. } while (ret < 0 && errno == EINTR);
  59. } else {
  60. ret = pollwrap_poll_endless(pw);
  61. }
  62. if (ret < 0 && errno == EINTR)
  63. continue;
  64. if (ret < 0) {
  65. perror("poll");
  66. exit(1);
  67. }
  68. bool found_fd = (ret > 0);
  69. for (size_t i = 0; i < fdcount; i++) {
  70. int fd = fdlist[i];
  71. int rwx = pollwrap_get_fd_rwx(pw, fd);
  72. /*
  73. * We must process exceptional notifications before
  74. * ordinary readability ones, or we may go straight
  75. * past the urgent marker.
  76. */
  77. if (rwx & SELECT_X)
  78. select_result(fd, SELECT_X);
  79. if (rwx & SELECT_R)
  80. select_result(fd, SELECT_R);
  81. if (rwx & SELECT_W)
  82. select_result(fd, SELECT_W);
  83. }
  84. pw_check(ctx, pw);
  85. bool ran_callback = run_toplevel_callbacks();
  86. if (!cont(ctx, found_fd, ran_callback))
  87. break;
  88. }
  89. pollwrap_free(pw);
  90. sfree(fdlist);
  91. }
  92. bool cliloop_no_pw_setup(void *ctx, pollwrapper *pw) { return true; }
  93. void cliloop_no_pw_check(void *ctx, pollwrapper *pw) {}
  94. bool cliloop_always_continue(void *ctx, bool fd, bool cb) { return true; }
  95. /*
  96. * Any application using this main loop doesn't need to do anything
  97. * when uxsel adds or removes an fd, because we synchronously re-check
  98. * the current list every time we go round the main loop above.
  99. */
  100. uxsel_id *uxsel_input_add(int fd, int rwx) { return NULL; }
  101. void uxsel_input_remove(uxsel_id *id) { }