pubsub.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /* Copyright (c) 2016-2017, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file pubsub.c
  5. *
  6. * \brief DOCDOC
  7. */
  8. #include "orconfig.h"
  9. #include "pubsub.h"
  10. #include "container.h"
  11. /** Helper: insert <b>s</b> into <b>topic's</b> list of subscribers, keeping
  12. * them sorted in priority order. */
  13. static void
  14. subscriber_insert(pubsub_topic_t *topic, pubsub_subscriber_t *s)
  15. {
  16. int i;
  17. smartlist_t *sl = topic->subscribers;
  18. for (i = 0; i < smartlist_len(sl); ++i) {
  19. pubsub_subscriber_t *other = smartlist_get(sl, i);
  20. if (s->priority < other->priority) {
  21. break;
  22. }
  23. }
  24. smartlist_insert(sl, i, s);
  25. }
  26. /**
  27. * Add a new subscriber to <b>topic</b>, where (when an event is triggered),
  28. * we'll notify the function <b>fn</b> by passing it <b>subscriber_data</b>.
  29. * Return a handle to the subscribe which can later be passed to
  30. * pubsub_unsubscribe_().
  31. *
  32. * Functions are called in priority order, from lowest to highest.
  33. *
  34. * See pubsub.h for <b>subscribe_flags</b>.
  35. */
  36. const pubsub_subscriber_t *
  37. pubsub_subscribe_(pubsub_topic_t *topic,
  38. pubsub_subscriber_fn_t fn,
  39. void *subscriber_data,
  40. unsigned subscribe_flags,
  41. unsigned priority)
  42. {
  43. tor_assert(! topic->locked);
  44. if (subscribe_flags & SUBSCRIBE_ATSTART) {
  45. tor_assert(topic->n_events_fired == 0);
  46. }
  47. pubsub_subscriber_t *r = tor_malloc_zero(sizeof(*r));
  48. r->priority = priority;
  49. r->subscriber_flags = subscribe_flags;
  50. r->fn = fn;
  51. r->subscriber_data = subscriber_data;
  52. if (topic->subscribers == NULL) {
  53. topic->subscribers = smartlist_new();
  54. }
  55. subscriber_insert(topic, r);
  56. return r;
  57. }
  58. /**
  59. * Remove the subscriber <b>s</b> from <b>topic</b>. After calling this
  60. * function, <b>s</b> may no longer be used.
  61. */
  62. int
  63. pubsub_unsubscribe_(pubsub_topic_t *topic,
  64. const pubsub_subscriber_t *s)
  65. {
  66. tor_assert(! topic->locked);
  67. smartlist_t *sl = topic->subscribers;
  68. if (sl == NULL)
  69. return -1;
  70. int i = smartlist_pos(sl, s);
  71. if (i == -1)
  72. return -1;
  73. pubsub_subscriber_t *tmp = smartlist_get(sl, i);
  74. tor_assert(tmp == s);
  75. smartlist_del_keeporder(sl, i);
  76. tor_free(tmp);
  77. return 0;
  78. }
  79. /**
  80. * For every subscriber s in <b>topic</b>, invoke notify_fn on s and
  81. * event_data. Return 0 if there were no nonzero return values, and -1 if
  82. * there were any.
  83. */
  84. int
  85. pubsub_notify_(pubsub_topic_t *topic, pubsub_notify_fn_t notify_fn,
  86. void *event_data, unsigned notify_flags)
  87. {
  88. tor_assert(! topic->locked);
  89. (void) notify_flags;
  90. smartlist_t *sl = topic->subscribers;
  91. int n_bad = 0;
  92. ++topic->n_events_fired;
  93. if (sl == NULL)
  94. return -1;
  95. topic->locked = 1;
  96. SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
  97. int r = notify_fn(s, event_data);
  98. if (r != 0)
  99. ++n_bad;
  100. } SMARTLIST_FOREACH_END(s);
  101. topic->locked = 0;
  102. return (n_bad == 0) ? 0 : -1;
  103. }
  104. /**
  105. * Release all storage held by <b>topic</b>.
  106. */
  107. void
  108. pubsub_clear_(pubsub_topic_t *topic)
  109. {
  110. tor_assert(! topic->locked);
  111. smartlist_t *sl = topic->subscribers;
  112. if (sl == NULL)
  113. return;
  114. SMARTLIST_FOREACH_BEGIN(sl, pubsub_subscriber_t *, s) {
  115. tor_free(s);
  116. } SMARTLIST_FOREACH_END(s);
  117. smartlist_free(sl);
  118. topic->subscribers = NULL;
  119. topic->n_events_fired = 0;
  120. }