ASynchronizer.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #include "interface/Iface.h"
  16. #include "interface/ASynchronizer.h"
  17. #include "memory/Allocator.h"
  18. #include "util/Identity.h"
  19. #include "util/events/Timeout.h"
  20. #include "util/log/Log.h"
  21. #include "util/Hex.h"
  22. #define MAX_DRY_CYCLES 16
  23. #define ArrayList_TYPE Message_t
  24. #define ArrayList_NAME Messages
  25. #include "util/ArrayList.h"
  26. struct ASynchronizer_pvt
  27. {
  28. struct ASynchronizer pub;
  29. struct Allocator* alloc;
  30. EventBase_t* base;
  31. struct Log* log;
  32. struct Allocator* cycleAlloc;
  33. struct ArrayList_Messages* msgsToA;
  34. struct ArrayList_Messages* msgsToB;
  35. struct Allocator* timeoutAlloc;
  36. struct Timeout* intr;
  37. int dryCycles;
  38. Identity
  39. };
  40. static void timeoutTrigger(void* vASynchronizer)
  41. {
  42. struct ASynchronizer_pvt* as = Identity_check((struct ASynchronizer_pvt*) vASynchronizer);
  43. if (!as->cycleAlloc) {
  44. if (as->dryCycles++ < MAX_DRY_CYCLES || !as->timeoutAlloc) { return; }
  45. Allocator_free(as->timeoutAlloc);
  46. as->timeoutAlloc = NULL;
  47. as->intr = NULL;
  48. as->dryCycles = 0;
  49. return;
  50. }
  51. struct ArrayList_Messages* msgsToA = as->msgsToA;
  52. struct ArrayList_Messages* msgsToB = as->msgsToB;
  53. struct Allocator* cycleAlloc = as->cycleAlloc;
  54. as->msgsToA = NULL;
  55. as->msgsToB = NULL;
  56. as->cycleAlloc = NULL;
  57. if (msgsToA) {
  58. for (int i = 0; i < msgsToA->length; i++) {
  59. Message_t* msg = ArrayList_Messages_get(msgsToA, i);
  60. Iface_send(&as->pub.ifA, msg);
  61. }
  62. }
  63. if (msgsToB) {
  64. for (int i = 0; i < msgsToB->length; i++) {
  65. Message_t* msg = ArrayList_Messages_get(msgsToB, i);
  66. Iface_send(&as->pub.ifB, msg);
  67. }
  68. }
  69. Allocator_free(cycleAlloc);
  70. }
  71. static void checkTimeout(struct ASynchronizer_pvt* as)
  72. {
  73. // The timeout might still be present but inactive because Timeout_clearAll() was called
  74. // to setup a test, in that case lets re-arm it in order to get the message to the other side.
  75. if (as->intr && !Timeout_isActive(as->intr)) {
  76. Allocator_free(as->timeoutAlloc);
  77. as->timeoutAlloc = NULL;
  78. }
  79. if (as->timeoutAlloc) { return; }
  80. as->timeoutAlloc = Allocator_child(as->alloc);
  81. as->intr = Timeout_setInterval(timeoutTrigger, as, 1, as->base, as->timeoutAlloc);
  82. }
  83. static Iface_DEFUN fromA(Message_t* msg, struct Iface* ifA)
  84. {
  85. struct ASynchronizer_pvt* as = Identity_containerOf(ifA, struct ASynchronizer_pvt, pub.ifA);
  86. if (!as->cycleAlloc) { as->cycleAlloc = Allocator_child(as->alloc); }
  87. if (!as->msgsToB) { as->msgsToB = ArrayList_Messages_new(as->cycleAlloc); }
  88. Allocator_adopt(as->cycleAlloc, Message_getAlloc(msg));
  89. ArrayList_Messages_add(as->msgsToB, msg);
  90. checkTimeout(as);
  91. return NULL;
  92. }
  93. static Iface_DEFUN fromB(Message_t* msg, struct Iface* ifB)
  94. {
  95. struct ASynchronizer_pvt* as = Identity_containerOf(ifB, struct ASynchronizer_pvt, pub.ifB);
  96. if (!as->cycleAlloc) { as->cycleAlloc = Allocator_child(as->alloc); }
  97. if (!as->msgsToA) { as->msgsToA = ArrayList_Messages_new(as->cycleAlloc); }
  98. Allocator_adopt(as->cycleAlloc, Message_getAlloc(msg));
  99. ArrayList_Messages_add(as->msgsToA, msg);
  100. checkTimeout(as);
  101. return NULL;
  102. }
  103. struct ASynchronizer* ASynchronizer_new(struct Allocator* alloc,
  104. EventBase_t* base,
  105. struct Log* log)
  106. {
  107. struct ASynchronizer_pvt* ctx = Allocator_calloc(alloc, sizeof(struct ASynchronizer_pvt), 1);
  108. Identity_set(ctx);
  109. ctx->alloc = alloc;
  110. ctx->base = base;
  111. ctx->log = log;
  112. ctx->pub.ifA.send = fromA;
  113. ctx->pub.ifB.send = fromB;
  114. return &ctx->pub;
  115. }