ASynchronizer.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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 struct Message
  24. #define ArrayList_NAME Messages
  25. #include "util/ArrayList.h"
  26. struct ASynchronizer_pvt
  27. {
  28. struct ASynchronizer pub;
  29. struct Allocator* alloc;
  30. struct EventBase* base;
  31. struct Log* log;
  32. struct Allocator* cycleAlloc;
  33. struct ArrayList_Messages* msgsToA;
  34. struct ArrayList_Messages* msgsToB;
  35. struct Allocator* timeoutAlloc;
  36. int dryCycles;
  37. Identity
  38. };
  39. static void timeoutTrigger(void* vASynchronizer)
  40. {
  41. struct ASynchronizer_pvt* as = Identity_check((struct ASynchronizer_pvt*) vASynchronizer);
  42. if (!as->cycleAlloc) {
  43. if (as->dryCycles++ < MAX_DRY_CYCLES || !as->timeoutAlloc) { return; }
  44. Allocator_free(as->timeoutAlloc);
  45. as->timeoutAlloc = NULL;
  46. as->dryCycles = 0;
  47. return;
  48. }
  49. struct ArrayList_Messages* msgsToA = as->msgsToA;
  50. struct ArrayList_Messages* msgsToB = as->msgsToB;
  51. struct Allocator* cycleAlloc = as->cycleAlloc;
  52. as->msgsToA = NULL;
  53. as->msgsToB = NULL;
  54. as->cycleAlloc = NULL;
  55. if (msgsToA) {
  56. for (int i = 0; i < msgsToA->length; i++) {
  57. struct Message* msg = ArrayList_Messages_get(msgsToA, i);
  58. Iface_send(&as->pub.ifA, msg);
  59. }
  60. }
  61. if (msgsToB) {
  62. for (int i = 0; i < msgsToB->length; i++) {
  63. struct Message* msg = ArrayList_Messages_get(msgsToB, i);
  64. Iface_send(&as->pub.ifB, msg);
  65. }
  66. }
  67. Allocator_free(cycleAlloc);
  68. }
  69. static void checkTimeout(struct ASynchronizer_pvt* as)
  70. {
  71. if (as->timeoutAlloc) { return; }
  72. as->timeoutAlloc = Allocator_child(as->alloc);
  73. Timeout_setInterval(timeoutTrigger, as, 1, as->base, as->timeoutAlloc);
  74. }
  75. static Iface_DEFUN fromA(struct Message* msg, struct Iface* ifA)
  76. {
  77. struct ASynchronizer_pvt* as = Identity_containerOf(ifA, struct ASynchronizer_pvt, pub.ifA);
  78. if (!as->cycleAlloc) { as->cycleAlloc = Allocator_child(as->alloc); }
  79. if (!as->msgsToB) { as->msgsToB = ArrayList_Messages_new(as->cycleAlloc); }
  80. Allocator_adopt(as->cycleAlloc, msg->alloc);
  81. ArrayList_Messages_add(as->msgsToB, msg);
  82. checkTimeout(as);
  83. return NULL;
  84. }
  85. static Iface_DEFUN fromB(struct Message* msg, struct Iface* ifB)
  86. {
  87. struct ASynchronizer_pvt* as = Identity_containerOf(ifB, struct ASynchronizer_pvt, pub.ifB);
  88. if (!as->cycleAlloc) { as->cycleAlloc = Allocator_child(as->alloc); }
  89. if (!as->msgsToA) { as->msgsToA = ArrayList_Messages_new(as->cycleAlloc); }
  90. Allocator_adopt(as->cycleAlloc, msg->alloc);
  91. ArrayList_Messages_add(as->msgsToA, msg);
  92. checkTimeout(as);
  93. return NULL;
  94. }
  95. struct ASynchronizer* ASynchronizer_new(struct Allocator* alloc,
  96. struct EventBase* base,
  97. struct Log* log)
  98. {
  99. struct ASynchronizer_pvt* ctx = Allocator_calloc(alloc, sizeof(struct ASynchronizer_pvt), 1);
  100. Identity_set(ctx);
  101. ctx->alloc = alloc;
  102. ctx->base = base;
  103. ctx->log = log;
  104. ctx->pub.ifA.send = fromA;
  105. ctx->pub.ifB.send = fromB;
  106. return &ctx->pub;
  107. }