PacketPassFifoQueue.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /**
  2. * @file PacketPassFifoQueue.c
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <stdlib.h>
  30. #include <misc/debug.h>
  31. #include <misc/offset.h>
  32. #include "PacketPassFifoQueue.h"
  33. static void schedule (PacketPassFifoQueue *o)
  34. {
  35. ASSERT(!o->freeing)
  36. ASSERT(!o->sending_flow)
  37. ASSERT(!LinkedList1_IsEmpty(&o->waiting_flows_list))
  38. ASSERT(!BPending_IsSet(&o->schedule_job))
  39. // get first waiting flow
  40. PacketPassFifoQueueFlow *flow = UPPER_OBJECT(LinkedList1_GetFirst(&o->waiting_flows_list), PacketPassFifoQueueFlow, waiting_flows_list_node);
  41. ASSERT(flow->queue == o)
  42. ASSERT(flow->is_waiting)
  43. // remove it from queue
  44. LinkedList1_Remove(&o->waiting_flows_list, &flow->waiting_flows_list_node);
  45. flow->is_waiting = 0;
  46. // send
  47. PacketPassInterface_Sender_Send(o->output, flow->waiting_data, flow->waiting_len);
  48. o->sending_flow = flow;
  49. }
  50. static void schedule_job_handler (PacketPassFifoQueue *o)
  51. {
  52. DebugObject_Access(&o->d_obj);
  53. ASSERT(!o->freeing)
  54. ASSERT(!o->sending_flow)
  55. if (!LinkedList1_IsEmpty(&o->waiting_flows_list)) {
  56. schedule(o);
  57. }
  58. }
  59. static void input_handler_send (PacketPassFifoQueueFlow *o, uint8_t *data, int data_len)
  60. {
  61. PacketPassFifoQueue *queue = o->queue;
  62. DebugObject_Access(&o->d_obj);
  63. ASSERT(!o->is_waiting)
  64. ASSERT(o != queue->sending_flow)
  65. ASSERT(!queue->freeing)
  66. // queue flow
  67. o->waiting_data = data;
  68. o->waiting_len = data_len;
  69. LinkedList1_Append(&queue->waiting_flows_list, &o->waiting_flows_list_node);
  70. o->is_waiting = 1;
  71. // schedule
  72. if (!queue->sending_flow && !BPending_IsSet(&queue->schedule_job)) {
  73. schedule(queue);
  74. }
  75. }
  76. static void output_handler_done (PacketPassFifoQueue *o)
  77. {
  78. DebugObject_Access(&o->d_obj);
  79. ASSERT(o->sending_flow)
  80. ASSERT(!BPending_IsSet(&o->schedule_job))
  81. ASSERT(!o->freeing)
  82. ASSERT(!o->sending_flow->is_waiting)
  83. PacketPassFifoQueueFlow *flow = o->sending_flow;
  84. // set no sending flow
  85. o->sending_flow = NULL;
  86. // schedule schedule job
  87. BPending_Set(&o->schedule_job);
  88. // done input
  89. PacketPassInterface_Done(&flow->input);
  90. // call busy handler if set
  91. if (flow->handler_busy) {
  92. // handler is one-shot, unset it before calling
  93. PacketPassFifoQueue_handler_busy handler = flow->handler_busy;
  94. flow->handler_busy = NULL;
  95. // call handler
  96. handler(flow->user);
  97. return;
  98. }
  99. }
  100. void PacketPassFifoQueue_Init (PacketPassFifoQueue *o, PacketPassInterface *output, BPendingGroup *pg)
  101. {
  102. // init arguments
  103. o->output = output;
  104. o->pg = pg;
  105. // init output
  106. PacketPassInterface_Sender_Init(output, (PacketPassInterface_handler_done)output_handler_done, o);
  107. // init waiting flows list
  108. LinkedList1_Init(&o->waiting_flows_list);
  109. // set no sending flow
  110. o->sending_flow = NULL;
  111. // init schedule job
  112. BPending_Init(&o->schedule_job, pg, (BPending_handler)schedule_job_handler, o);
  113. // set not freeing
  114. o->freeing = 0;
  115. DebugCounter_Init(&o->d_flows_ctr);
  116. DebugObject_Init(&o->d_obj);
  117. }
  118. void PacketPassFifoQueue_Free (PacketPassFifoQueue *o)
  119. {
  120. DebugObject_Free(&o->d_obj);
  121. DebugCounter_Free(&o->d_flows_ctr);
  122. ASSERT(LinkedList1_IsEmpty(&o->waiting_flows_list))
  123. ASSERT(!o->sending_flow)
  124. // free schedule job
  125. BPending_Free(&o->schedule_job);
  126. }
  127. void PacketPassFifoQueue_PrepareFree (PacketPassFifoQueue *o)
  128. {
  129. DebugObject_Access(&o->d_obj);
  130. // set freeing
  131. o->freeing = 1;
  132. }
  133. void PacketPassFifoQueueFlow_Init (PacketPassFifoQueueFlow *o, PacketPassFifoQueue *queue)
  134. {
  135. DebugObject_Access(&queue->d_obj);
  136. ASSERT(!queue->freeing)
  137. // init arguments
  138. o->queue = queue;
  139. // init input
  140. PacketPassInterface_Init(&o->input, PacketPassInterface_GetMTU(queue->output), (PacketPassInterface_handler_send)input_handler_send, o, queue->pg);
  141. // set not waiting
  142. o->is_waiting = 0;
  143. // set no busy handler
  144. o->handler_busy = NULL;
  145. DebugCounter_Increment(&queue->d_flows_ctr);
  146. DebugObject_Init(&o->d_obj);
  147. }
  148. void PacketPassFifoQueueFlow_Free (PacketPassFifoQueueFlow *o)
  149. {
  150. PacketPassFifoQueue *queue = o->queue;
  151. DebugObject_Free(&o->d_obj);
  152. DebugCounter_Decrement(&queue->d_flows_ctr);
  153. ASSERT(queue->freeing || o != queue->sending_flow)
  154. // remove from sending flow
  155. if (o == queue->sending_flow) {
  156. queue->sending_flow = NULL;
  157. }
  158. // remove from waiting flows list
  159. if (o->is_waiting) {
  160. LinkedList1_Remove(&queue->waiting_flows_list, &o->waiting_flows_list_node);
  161. }
  162. // free input
  163. PacketPassInterface_Free(&o->input);
  164. }
  165. void PacketPassFifoQueueFlow_AssertFree (PacketPassFifoQueueFlow *o)
  166. {
  167. PacketPassFifoQueue *queue = o->queue;
  168. DebugObject_Access(&o->d_obj);
  169. ASSERT(queue->freeing || o != queue->sending_flow)
  170. }
  171. int PacketPassFifoQueueFlow_IsBusy (PacketPassFifoQueueFlow *o)
  172. {
  173. PacketPassFifoQueue *queue = o->queue;
  174. DebugObject_Access(&o->d_obj);
  175. ASSERT(!queue->freeing)
  176. return (o == queue->sending_flow);
  177. }
  178. void PacketPassFifoQueueFlow_SetBusyHandler (PacketPassFifoQueueFlow *o, PacketPassFifoQueue_handler_busy handler_busy, void *user)
  179. {
  180. PacketPassFifoQueue *queue = o->queue;
  181. DebugObject_Access(&o->d_obj);
  182. ASSERT(!queue->freeing)
  183. ASSERT(o == queue->sending_flow)
  184. // set (or unset) busy handler
  185. o->handler_busy = handler_busy;
  186. o->user = user;
  187. }
  188. PacketPassInterface * PacketPassFifoQueueFlow_GetInput (PacketPassFifoQueueFlow *o)
  189. {
  190. DebugObject_Access(&o->d_obj);
  191. return &o->input;
  192. }