handle_base.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * Copyright (c) 2018 SignalWire, Inc
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in all
  12. * copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. #pragma once
  23. KS_BEGIN_EXTERN_C
  24. /* Define our base handle structure, this is used to generically provide features
  25. * across all client handle types */
  26. struct swclt_handle_base {
  27. /* Just so we don't have to have another address on dereference
  28. * manually define the same entries used in ks_handle_base_t */
  29. ks_handle_t handle;
  30. ks_pool_t *pool;
  31. /* This is the current handle state */
  32. SWCLT_HSTATE state;
  33. /* The last state we transitioned from */
  34. SWCLT_HSTATE last_state;
  35. /* Set to the state the handle is requesting a service for, this is different
  36. * then the swclt_hstate_change_t system, that system is for reporting, this one
  37. * is used by the reporting handle itself when it wants to transition state */
  38. volatile SWCLT_HSTATE pending_state_change_service;
  39. volatile swclt_hstate_state_change_handler_cb_t pending_state_change_handler_cb;
  40. /* Lightweight lock for managing the callback array */
  41. ks_spinlock_t lock;
  42. /* Service callback, if set makes the handle available for service event from
  43. * the managers thread */
  44. swclt_hstate_service_cb_t service_cb;
  45. /* This is set by the handle when they want service, its used to contextualize
  46. * the next requested service absolute timestamp, so that we do not service the handle
  47. * sooner then it needs, nor do we service handles which have not requested
  48. * a service time */
  49. ks_time_t next_service_time_stamp_ms;
  50. /* If we fail to service, this is the delay in ms for the next attempt */
  51. ks_time_t retry_service_delay_ms;
  52. /* When non null, this implies a state change is pending, and it contains
  53. * the information needed to articulate why and what for the state change
  54. * Note: You cannot layer state change requests, multiple layered requests to
  55. * change state will be ignored. */
  56. swclt_hstate_change_t *pending_state_change_notification;
  57. /* State change gets raised by the handle anytime its state changes. The
  58. * definition of a state change is relative to the type as the states are
  59. * generic. These contextes allow for a one to many relationship between
  60. * handles listening for a state change, and a handle reporting a
  61. * state change. */
  62. swclt_hstate_listener_t *state_listeners;
  63. uint32_t c_state_listeners;
  64. };
  65. #define SWCLT_HANDLE_ALLOC_TEMPLATE_S_TAG(pool, file, line, tag, handle_type, handle_ptr, context_type, initial_hstate, describe_method, deinit_method, init_method) \
  66. ks_status_t status; \
  67. context_type *context; \
  68. \
  69. if ((status = __ks_handle_alloc_ex(pool, handle_type, sizeof(context_type), \
  70. (ks_handle_base_t **)&context, handle_ptr, \
  71. (ks_handle_describe_cb_t)describe_method, \
  72. (ks_handle_deinit_cb_t)deinit_method, \
  73. file, line, tag))) { \
  74. if (status == KS_STATUS_HANDLE_NO_MORE_SLOTS) { \
  75. abort(); \
  76. } \
  77. return status; \
  78. } \
  79. \
  80. ((swclt_handle_base_t *)context)->state = initial_hstate; \
  81. ((swclt_handle_base_t *)context)->last_state = initial_hstate; \
  82. \
  83. if (status = init_method(context)) { \
  84. deinit_method(context); \
  85. ks_handle_destroy(handle_ptr); \
  86. return status; \
  87. } \
  88. \
  89. ks_handle_set_ready(*handle_ptr); \
  90. return status;
  91. #define SWCLT_HANDLE_ALLOC_TEMPLATE_M_TAG(pool, file, line, tag, handle_type, handle_ptr, context_type, initial_hstate, describe_method, deinit_method, init_method, ...) \
  92. ks_status_t status; \
  93. context_type *context; \
  94. \
  95. if ((status = __ks_handle_alloc_ex(pool, handle_type, sizeof(context_type), (ks_handle_base_t **)&context, handle_ptr, \
  96. (ks_handle_describe_cb_t)describe_method, (ks_handle_deinit_cb_t)deinit_method, \
  97. file, line, tag))) { \
  98. if (status == KS_STATUS_HANDLE_NO_MORE_SLOTS) { \
  99. abort(); \
  100. } \
  101. return status; \
  102. } \
  103. \
  104. ((swclt_handle_base_t *)context)->state = initial_hstate; \
  105. ((swclt_handle_base_t *)context)->last_state = initial_hstate; \
  106. \
  107. if (status = init_method(context, __VA_ARGS__)) { \
  108. deinit_method(context); \
  109. ks_handle_destroy(handle_ptr); \
  110. return status; \
  111. } \
  112. \
  113. ks_handle_set_ready(*handle_ptr); \
  114. return status;
  115. #define SWCLT_HANDLE_ALLOC_TEMPLATE_S(pool, handle_type, handle_ptr, context_type, initial_hstate, describe_method, deinit_method, init_method) \
  116. ks_status_t status; \
  117. context_type *context; \
  118. \
  119. if ((status = ks_handle_alloc_ex(pool, handle_type, sizeof(context_type), \
  120. &context, handle_ptr, \
  121. (ks_handle_describe_cb_t)describe_method, \
  122. (ks_handle_deinit_cb_t)deinit_method))) { \
  123. if (status == KS_STATUS_HANDLE_NO_MORE_SLOTS) { \
  124. abort(); \
  125. } \
  126. return status; \
  127. } \
  128. \
  129. ((swclt_handle_base_t *)context)->state = initial_hstate; \
  130. ((swclt_handle_base_t *)context)->last_state = initial_hstate; \
  131. \
  132. if (status = init_method(context)) { \
  133. deinit_method(context); \
  134. ks_handle_destroy(handle_ptr); \
  135. return status; \
  136. } \
  137. \
  138. ks_handle_set_ready(*handle_ptr); \
  139. return status;
  140. #define SWCLT_HANDLE_ALLOC_TEMPLATE_M(pool, handle_type, handle_ptr, context_type, initial_hstate, describe_method, deinit_method, init_method, ...) \
  141. ks_status_t status; \
  142. context_type *context; \
  143. \
  144. if ((status = ks_handle_alloc_ex(pool, handle_type, sizeof(context_type), &context, handle_ptr, \
  145. (ks_handle_describe_cb_t)describe_method, (ks_handle_deinit_cb_t)deinit_method))) { \
  146. if (status == KS_STATUS_HANDLE_NO_MORE_SLOTS) { \
  147. abort(); \
  148. } \
  149. return status; \
  150. } \
  151. \
  152. ((swclt_handle_base_t *)context)->state = initial_hstate; \
  153. ((swclt_handle_base_t *)context)->last_state = initial_hstate; \
  154. \
  155. if (status = init_method(context, __VA_ARGS__)) { \
  156. deinit_method(context); \
  157. ks_handle_destroy(handle_ptr); \
  158. return status; \
  159. } \
  160. \
  161. ks_handle_set_ready(*handle_ptr); \
  162. return status;
  163. KS_END_EXTERN_C