events_immediate.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. #include <assert.h>
  2. #include <stdlib.h>
  3. #include "mpool.h"
  4. #include "queue.h"
  5. #include "events.h"
  6. #include "events_internal.h"
  7. struct eventq {
  8. struct eventrec * r;
  9. TAILQ_ENTRY(eventq) entries;
  10. int prio;
  11. };
  12. MPOOL(eventq, struct eventq, 4096);
  13. /* First nodes in the linked lists. */
  14. static TAILQ_HEAD(tailhead, eventq) heads[32] = {
  15. TAILQ_HEAD_INITIALIZER(heads[0]),
  16. TAILQ_HEAD_INITIALIZER(heads[1]),
  17. TAILQ_HEAD_INITIALIZER(heads[2]),
  18. TAILQ_HEAD_INITIALIZER(heads[3]),
  19. TAILQ_HEAD_INITIALIZER(heads[4]),
  20. TAILQ_HEAD_INITIALIZER(heads[5]),
  21. TAILQ_HEAD_INITIALIZER(heads[6]),
  22. TAILQ_HEAD_INITIALIZER(heads[7]),
  23. TAILQ_HEAD_INITIALIZER(heads[8]),
  24. TAILQ_HEAD_INITIALIZER(heads[9]),
  25. TAILQ_HEAD_INITIALIZER(heads[10]),
  26. TAILQ_HEAD_INITIALIZER(heads[11]),
  27. TAILQ_HEAD_INITIALIZER(heads[12]),
  28. TAILQ_HEAD_INITIALIZER(heads[13]),
  29. TAILQ_HEAD_INITIALIZER(heads[14]),
  30. TAILQ_HEAD_INITIALIZER(heads[15]),
  31. TAILQ_HEAD_INITIALIZER(heads[16]),
  32. TAILQ_HEAD_INITIALIZER(heads[17]),
  33. TAILQ_HEAD_INITIALIZER(heads[18]),
  34. TAILQ_HEAD_INITIALIZER(heads[19]),
  35. TAILQ_HEAD_INITIALIZER(heads[20]),
  36. TAILQ_HEAD_INITIALIZER(heads[21]),
  37. TAILQ_HEAD_INITIALIZER(heads[22]),
  38. TAILQ_HEAD_INITIALIZER(heads[23]),
  39. TAILQ_HEAD_INITIALIZER(heads[24]),
  40. TAILQ_HEAD_INITIALIZER(heads[25]),
  41. TAILQ_HEAD_INITIALIZER(heads[26]),
  42. TAILQ_HEAD_INITIALIZER(heads[27]),
  43. TAILQ_HEAD_INITIALIZER(heads[28]),
  44. TAILQ_HEAD_INITIALIZER(heads[29]),
  45. TAILQ_HEAD_INITIALIZER(heads[30]),
  46. TAILQ_HEAD_INITIALIZER(heads[31])
  47. };
  48. /* For i < minq, heads[i] == NULL. */
  49. static int minq = 32;
  50. /**
  51. * events_immediate_register(func, cookie, prio):
  52. * Register ${func}(${cookie}) to be run the next time events_run() is
  53. * invoked, after immediate events with smaller ${prio} values and before
  54. * events with larger ${prio} values. The value ${prio} must be in the range
  55. * [0, 31]. Return a cookie which can be passed to events_immediate_cancel().
  56. */
  57. void *
  58. events_immediate_register(int (* func)(void *), void * cookie, int prio)
  59. {
  60. struct eventrec * r;
  61. struct eventq * q;
  62. /* Sanity check. */
  63. assert((prio >= 0) && (prio < 32));
  64. /* Bundle into an eventrec record. */
  65. if ((r = events_mkrec(func, cookie)) == NULL)
  66. goto err0;
  67. /* Create a linked list node. */
  68. if ((q = mpool_eventq_malloc()) == NULL)
  69. goto err1;
  70. q->r = r;
  71. q->prio = prio;
  72. /* Add to the queue. */
  73. TAILQ_INSERT_TAIL(&heads[prio], q, entries);
  74. /* Update minq if necessary. */
  75. if (prio < minq)
  76. minq = prio;
  77. /* Success! */
  78. return (q);
  79. err1:
  80. events_freerec(r);
  81. err0:
  82. /* Failure! */
  83. return (NULL);
  84. }
  85. /**
  86. * events_immediate_cancel(cookie):
  87. * Cancel the immediate event for which the cookie ${cookie} was returned by
  88. * events_immediate_register().
  89. */
  90. void
  91. events_immediate_cancel(void * cookie)
  92. {
  93. struct eventq * q = cookie;
  94. int prio = q->prio;
  95. /* Remove it from the list. */
  96. TAILQ_REMOVE(&heads[prio], q, entries);
  97. /* Free the eventrec. */
  98. events_freerec(q->r);
  99. /* Return the node to the malloc pool. */
  100. mpool_eventq_free(q);
  101. }
  102. /**
  103. * events_immediate_get(void):
  104. * Remove and return an eventrec structure from the immediate event queue,
  105. * or return NULL if there are no such events. The caller is responsible for
  106. * freeing the returned memory.
  107. */
  108. struct eventrec *
  109. events_immediate_get(void)
  110. {
  111. struct eventq * q;
  112. struct eventrec * r;
  113. /* Advance past priorities which have no events. */
  114. while ((minq < 32) && (TAILQ_EMPTY(&heads[minq])))
  115. minq++;
  116. /* Are there any events? */
  117. if (minq == 32)
  118. return (NULL);
  119. /*
  120. * Remove the first node from the highest priority non-empty linked
  121. * list.
  122. */
  123. q = TAILQ_FIRST(&heads[minq]);
  124. TAILQ_REMOVE(&heads[minq], q, entries);
  125. /* Extract the eventrec. */
  126. r = q->r;
  127. /* Return the node to the malloc pool. */
  128. mpool_eventq_free(q);
  129. /* Return the eventrec. */
  130. return (r);
  131. }