tsnetwork_sleep.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. #include <assert.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "elasticarray.h"
  5. #include "events.h"
  6. #include "warnp.h"
  7. #include "tsnetwork.h"
  8. #include "tsnetwork_internal.h"
  9. /* Sleepers. */
  10. struct sleeper {
  11. network_callback * callback;
  12. void * cookie;
  13. void * event_cookie;
  14. };
  15. ELASTICARRAY_DECL(SLEEPERS, sleepers, struct sleeper *);
  16. static SLEEPERS sleepers = NULL;
  17. /* Callback from network_sleep when timer expires. */
  18. static int
  19. callback_timer(void * cookie)
  20. {
  21. struct sleeper * sp = cookie;
  22. /* This callback is no longer pending. */
  23. sp->event_cookie = NULL;
  24. /* Do callback. */
  25. return ((sp->callback)(sp->cookie, NETWORK_STATUS_TIMEOUT));
  26. }
  27. /**
  28. * network_sleep(timeo, callback, cookie):
  29. * Register a callback to be performed by network_select once the specified
  30. * timeout has expired. Return a handle which can be passed to
  31. * network_desleep().
  32. */
  33. int
  34. network_sleep(struct timeval * timeo,
  35. network_callback * callback, void * cookie)
  36. {
  37. struct sleeper s;
  38. struct sleeper * sp = NULL; /* Silence bogus compiler warnings. */
  39. size_t h;
  40. /* Initialize array if required. */
  41. if (sleepers == NULL) {
  42. if ((sleepers = sleepers_init(0)) == NULL)
  43. goto err0;
  44. }
  45. /* Construct sleeper record. */
  46. s.callback = callback;
  47. s.cookie = cookie;
  48. s.event_cookie = NULL;
  49. /* Search for empty space. */
  50. for (h = 0; h < sleepers_getsize(sleepers); h++) {
  51. sp = *sleepers_get(sleepers, h);
  52. if (sp->event_cookie == NULL) {
  53. /* Use this one. */
  54. memcpy(sp, &s, sizeof(struct sleeper));
  55. break;
  56. }
  57. }
  58. /* If we didn't find an empty space, add a new sleeper. */
  59. if (h == sleepers_getsize(sleepers)) {
  60. /* Don't have too many sleepers... */
  61. if (h == 1024) {
  62. warn0("Too many sleepers");
  63. goto err0;
  64. }
  65. /* Allocate a record. */
  66. if ((sp = malloc(sizeof(struct sleeper))) == NULL)
  67. goto err0;
  68. /* Copy data in. */
  69. memcpy(sp, &s, sizeof(struct sleeper));
  70. /* Append the record. */
  71. if (sleepers_append(sleepers, &sp, 1))
  72. goto err1;
  73. } else {
  74. /*-
  75. * If (h != sleepers_getsize()), then sp was set in the
  76. * earlier 'for' loop, but compilers don't realize it.
  77. */
  78. assert(sp != NULL);
  79. }
  80. /* Register the timer event. */
  81. if ((sp->event_cookie =
  82. events_timer_register(callback_timer, sp, timeo)) == NULL)
  83. goto err0;
  84. /* Success! */
  85. return ((int)h);
  86. err1:
  87. free(sp);
  88. err0:
  89. /* Failure! */
  90. return (-1);
  91. }
  92. /**
  93. * network_desleep(handle):
  94. * Deregister the callback associated with the provided handle. The
  95. * callback will be called with a status of NETWORK_STATUS_CANCEL.
  96. */
  97. int
  98. network_desleep(int handle)
  99. {
  100. struct sleeper * sp;
  101. /* Sanity-check the handle. */
  102. if ((handle >= (int)sleepers_getsize(sleepers)) || (handle < 0)) {
  103. warn0("Invalid sleeper handle: %d", handle);
  104. goto err0;
  105. }
  106. /* Grab the relevant sleeper record. */
  107. sp = *sleepers_get(sleepers, (size_t)handle);
  108. /* If there is no timer, return silently. */
  109. if (sp->event_cookie == NULL)
  110. return (0);
  111. /* Cancel the timer. */
  112. events_timer_cancel(sp->event_cookie);
  113. sp->event_cookie = NULL;
  114. /* Invoke the callback. */
  115. return ((sp->callback)(sp->cookie, NETWORK_STATUS_CANCEL));
  116. err0:
  117. /* Failure! */
  118. return (-1);
  119. }
  120. /**
  121. * network_sleep_fini(void):
  122. * Free resources allocated.
  123. */
  124. void
  125. network_sleep_fini(void)
  126. {
  127. struct sleeper * sp;
  128. size_t i;
  129. /* Nothing to do if we're uninitialized. */
  130. if (sleepers == NULL)
  131. return;
  132. /* Free records. */
  133. for (i = 0; i < sleepers_getsize(sleepers); i++) {
  134. sp = *sleepers_get(sleepers, i);
  135. /* If this sleep is no longer in progress, free the record. */
  136. if (sp->event_cookie == NULL)
  137. free(sp);
  138. }
  139. /* Free the sleepers array. */
  140. sleepers_free(sleepers);
  141. }