sc_timer_service.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * Timer Service Implementation for SCTUnit
  3. */
  4. #include "sc_timer_service.h"
  5. #include <stdlib.h>
  6. /**
  7. * Implementation of a timer service that uses _virtual_ time to raise time events.
  8. * It is solely meant for use with sctunit.
  9. */
  10. void sc_timer_service_init(
  11. sc_unit_timer_service_t * ts,
  12. sc_raise_time_event_fp raise_event_func,
  13. sc_run_cycle_fp run_cycle_func,
  14. sc_boolean event_driven,
  15. sc_integer cycle_period,
  16. void* handle
  17. )
  18. {
  19. ts->raise_event_func = raise_event_func;
  20. ts->tasks = 0;
  21. ts->run_cycle_func = run_cycle_func;
  22. ts->event_driven = event_driven;
  23. ts->cycle_period = cycle_period;
  24. ts->handle = handle;
  25. ts->current_time_ms = 0;
  26. if(!ts->event_driven) {
  27. sc_timer_t run_cycle;
  28. sc_timer_init(
  29. &run_cycle,
  30. ts->cycle_period,
  31. true,
  32. 0);
  33. run_cycle.isRunCycle = true;
  34. run_cycle.priority = -1;
  35. insert_timer(ts, run_cycle);
  36. }
  37. }
  38. void sc_timer_init(
  39. sc_timer_t * t,
  40. sc_integer time_ms,
  41. sc_boolean periodic,
  42. sc_eventid evid
  43. )
  44. {
  45. t->rel_time_ms = time_ms;
  46. t->abs_time_ms = 0;
  47. t->periodic = periodic;
  48. t->pt_evid = evid;
  49. t->priority = 0;
  50. t->isRunCycle = false;
  51. }
  52. void sc_timer_service_proceed_time(sc_unit_timer_service_t * ts, sc_integer time_ms)
  53. {
  54. sc_integer stop_time_ms = ts->current_time_ms + time_ms;
  55. sc_boolean processed_timer = false;
  56. do {
  57. // first assume we won't process a timer
  58. processed_timer = false;
  59. // and then check if there is a timer to process
  60. if( ts->tasks > 0) {
  61. if(ts->tasks->timer.abs_time_ms <= stop_time_ms) {
  62. sc_timer_task_t * next_task = pop_task(ts);
  63. sc_timer_t next = next_task->timer;
  64. free(next_task);
  65. // shift time to the timer absolute time
  66. ts->current_time_ms = next.abs_time_ms;
  67. // reschedule periodic timer
  68. if(next.periodic) {
  69. insert_timer(ts, next);
  70. }
  71. // process timer ...
  72. if(next.isRunCycle) {
  73. ts->run_cycle_func(ts->handle);
  74. } else {
  75. ts->raise_event_func(ts->handle, next.pt_evid);
  76. }
  77. processed_timer = true;
  78. }
  79. }
  80. } while ( processed_timer );
  81. // As a postcondition the current time is the time after proceeding the specified period.
  82. ts->current_time_ms = stop_time_ms;
  83. }
  84. void sc_timer_service_proceed_cycles(sc_unit_timer_service_t * ts, sc_integer cycles)
  85. {
  86. sc_integer elapsed_cycles = 0;
  87. while(elapsed_cycles < cycles) {
  88. if(ts->tasks == 0) {
  89. return;
  90. }
  91. sc_timer_task_t * next_task = pop_task(ts);
  92. sc_timer_t next = next_task->timer;
  93. free(next_task);
  94. ts->current_time_ms = next.abs_time_ms;
  95. // Repeat the event?
  96. if(next.periodic) {
  97. insert_timer(ts, next);
  98. }
  99. // Process event
  100. if(next.isRunCycle) {
  101. ts->run_cycle_func(ts->handle);
  102. elapsed_cycles++;
  103. } else {
  104. ts->raise_event_func(ts->handle, next.pt_evid);
  105. }
  106. }
  107. }
  108. sc_timer_t sc_timer_service_proceed(sc_unit_timer_service_t * ts)
  109. {
  110. sc_timer_task_t * next_task = pop_task(ts);
  111. sc_timer_t next = next_task->timer;
  112. free(next_task);
  113. ts->current_time_ms = next.abs_time_ms;
  114. // Repeat the event?
  115. if(next.periodic) {
  116. insert_timer(ts, next);
  117. }
  118. return next;
  119. }
  120. void delete_task(sc_unit_timer_service_t * ts, sc_timer_task_t * task)
  121. {
  122. if(!task) {
  123. return;
  124. }
  125. if(ts->tasks == task) {
  126. ts->tasks = ts->tasks->next;
  127. } else {
  128. sc_timer_task_t * this = ts->tasks->next;
  129. sc_timer_task_t * last = ts->tasks;
  130. while(this) {
  131. if(this == task) {
  132. last->next = this->next;
  133. }
  134. else {
  135. last = last->next;
  136. }
  137. this = this->next;
  138. }
  139. }
  140. free(task);
  141. }
  142. sc_timer_task_t * find_time_event(sc_unit_timer_service_t * ts, sc_eventid evid)
  143. {
  144. sc_timer_task_t * this = ts->tasks;
  145. while(this && this->timer.pt_evid != evid) {
  146. this = this->next;
  147. }
  148. return this;
  149. }
  150. void insert_timer(sc_unit_timer_service_t * ts, sc_timer_t te)
  151. {
  152. sc_timer_task_t * head = ts->tasks;
  153. sc_timer_task_t * new = (sc_timer_task_t *) malloc(sizeof(sc_timer_task_t));
  154. te.abs_time_ms = ts->current_time_ms + te.rel_time_ms;
  155. new->timer = te;
  156. new->next = 0;
  157. if(head == 0) {
  158. ts->tasks = new;
  159. return;
  160. }
  161. // Check if we should put it in as first element
  162. if(compare(&te, &(head->timer)) < 0) {
  163. new->next = head;
  164. ts->tasks = new;
  165. return;
  166. }
  167. sc_timer_task_t * last = head;
  168. head = head->next;
  169. while(head != 0) {
  170. if(compare(&te, &(head->timer)) < 0) {
  171. new->next = head;
  172. last->next = new;
  173. return;
  174. }
  175. last = head;
  176. head = head->next;
  177. }
  178. // put it in last position
  179. last->next = new;
  180. }
  181. sc_timer_task_t * pop_task(sc_unit_timer_service_t * ts) {
  182. sc_timer_task_t * head = ts->tasks;
  183. if(head != 0) {
  184. ts->tasks = head->next;
  185. }
  186. return head;
  187. }
  188. /* Returns negative when a needs to be raised before b, 0 when a<>b, positive when a after b */
  189. sc_integer compare(sc_timer_t * a, sc_timer_t * b) {
  190. // smaller time_ms needs to be raised first
  191. sc_integer result = a->abs_time_ms - b->abs_time_ms;
  192. if(result != 0) {
  193. return result;
  194. } else {
  195. // bigger priority needs to be raised first
  196. result = b->priority - a->priority;
  197. return result;
  198. }
  199. }