ASynchronizer.c 3.7 KB

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