QP/C  5.8.2
qk.c
Go to the documentation of this file.
1 
40 #define QP_IMPL /* this is QP implementation */
41 #include "qf_port.h" /* QF port */
42 #include "qf_pkg.h" /* QF package-scope internal interface */
43 #include "qassert.h" /* QP embedded systems-friendly assertions */
44 #ifdef Q_SPY /* QS software tracing enabled? */
45  #include "qs_port.h" /* include QS port */
46 #else
47  #include "qs_dummy.h" /* disable the QS software tracing */
48 #endif /* Q_SPY */
49 
50 /* protection against including this source file in a wrong project */
51 #ifndef qk_h
52  #error "Source file included in a project NOT based on the QK kernel"
53 #endif /* qk_h */
54 
56 
57 /* Public-scope objects *****************************************************/
58 QK_Attr QK_attr_; /* global attributes of the QK kernel */
59 
60 /****************************************************************************/
71 void QF_init(void) {
75 
76  /* clear the internal QF variables, so that the framework can start
77  * correctly even if the startup code fails to clear the uninitialized
78  * data (as is required by the C Standard).
79  */
83  QF_bzero(&QK_attr_, (uint_fast16_t)sizeof(QK_attr_));
84 
85  QK_attr_.actPrio = (uint_fast8_t)0; /* priority of the QK idle loop */
86  QK_attr_.lockPrio = (uint_fast8_t)QF_MAX_ACTIVE; /* scheduler locked */
87 
88 #ifdef QK_INIT
89  QK_INIT(); /* port-specific initialization of the QK kernel */
90 #endif
91 }
92 
93 /****************************************************************************/
105 void QF_stop(void) {
106  QF_onCleanup(); /* application-specific cleanup callback */
107  /* nothing else to do for the preemptive QK kernel */
108 }
109 
110 /****************************************************************************/
112 static void initial_events(void); /* prototype */
113 static void initial_events(void) {
114  QK_attr_.lockPrio = (uint_fast8_t)0; /* scheduler unlocked */
115 
116  /* any active objects need to be scheduled before starting event loop? */
117  if (QK_sched_() != (uint_fast8_t)0) {
118  QK_activate_(); /* activate AOs to process all events posted so far */
119  }
120 }
121 
122 /****************************************************************************/
130 int_t QF_run(void) {
131  QF_INT_DISABLE();
132  initial_events(); /* process all events posted during initialization */
133  QF_onStartup(); /* application-specific startup callback */
134  QF_INT_ENABLE();
135 
136  /* the QK idle loop... */
137  for (;;) {
138  QK_onIdle(); /* application-specific QK on-idle callback */
139  }
140 
141 #ifdef __GNUC__
142  return (int_t)0;
143 #endif
144 }
145 
146 /****************************************************************************/
169 void QActive_start_(QActive * const me, uint_fast8_t prio,
170  QEvt const *qSto[], uint_fast16_t qLen,
171  void *stkSto, uint_fast16_t stkSize,
172  QEvt const *ie)
173 {
175 
176  Q_REQUIRE_ID(500, ((uint_fast8_t)0 < prio)
177  && (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
178  && (stkSto == (void *)0)
179  && (stkSize == (uint_fast16_t)0));
180 
181  QEQueue_init(&me->eQueue, qSto, qLen); /* initialize the built-in queue */
182  me->prio = prio; /* set the current priority of the AO */
183  QF_CRIT_ENTRY_();
184  QF_add_(me); /* make QF aware of this active object */
185  QF_CRIT_EXIT_();
186 
187  QHSM_INIT(&me->super, ie); /* take the top-most initial tran. */
188  QS_FLUSH(); /* flush the trace buffer to the host */
189 
190  /* See if this AO needs to be scheduled in case QK is already running */
191  QF_CRIT_ENTRY_();
192  if (QK_sched_() != (uint_fast8_t)0) {
193  QK_activate_();
194  }
195  QF_CRIT_EXIT_();
196 }
197 
198 /****************************************************************************/
209 void QActive_stop(QActive * const me) {
211 
212  QF_CRIT_ENTRY_();
214  Q_REQUIRE_ID(600, (me == QF_active_[QK_attr_.actPrio]));
215 
216  QF_remove_(me); /* remove this active object from the QF */
217 
219  if (QK_sched_() != (uint_fast8_t)0) {
220  QK_activate_();
221  }
222  QF_CRIT_EXIT_();
223 }
224 
225 /****************************************************************************/
240  uint_fast8_t p; /* for priority */
241 
242  /* find the highest-prio AO with non-empty event queue */
244 
245  /* is the highest-prio below the active priority? */
246  if (p <= QK_attr_.actPrio) {
247  p = (uint_fast8_t)0; /* active object not eligible */
248  }
249  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
250  p = (uint_fast8_t)0; /* active object not eligible */
251  }
252  else {
254  QK_attr_.nextPrio = p; /* next AO to run */
255  }
256  return p;
257 }
258 
259 /****************************************************************************/
269 void QK_activate_(void) {
270  uint_fast8_t pin = QK_attr_.actPrio; /* save the active priority */
271  uint_fast8_t p = QK_attr_.nextPrio; /* the next prio to run */
272  QActive *a;
273 
274  /* QS tracing or thread-local storage? */
275 #ifdef Q_SPY
276  uint_fast8_t pprev = pin;
277 #endif /* Q_SPY */
278 
279  /* QK_attr_.nextPrio must be non-zero upon entry to QK_activate_() */
280  Q_REQUIRE_ID(800, p != (uint_fast8_t)0);
281 
282  QK_attr_.nextPrio = (uint_fast8_t)0; /* clear for the next time */
283 
284  /* loop until no more ready-to-run AOs of higher prio than the initial */
285  do {
286  QEvt const *e;
287  a = QF_active_[p]; /* obtain the pointer to the AO */
288  QK_attr_.actPrio = p; /* this becomes the active priority */
289 
291  QS_TIME_(); /* timestamp */
292  QS_2U8_((uint8_t)p, /* priority of the scheduled AO */
293  (uint8_t)pprev); /* previous priority */
295 
296 #ifdef Q_SPY
297  if (p != pprev) { /* changing priorities? */
298  pprev = p; /* update previous priority */
299  }
300 #endif /* Q_SPY */
301 
302  QF_INT_ENABLE(); /* unconditionally enable interrupts */
303 
304  /* perform the run-to-completion (RTC) step...
305  * 1. retrieve the event from the AO's event queue, which by this
306  * time must be non-empty and QActive_get_() asserts it.
307  * 2. dispatch the event to the AO's state machine.
308  * 3. determine if event is garbage and collect it if so
309  */
310  e = QActive_get_(a);
311  QHSM_DISPATCH(&a->super, e);
312  QF_gc(e);
313 
314  QF_INT_DISABLE(); /* unconditionally disable interrupts */
315 
316  if (a->eQueue.frontEvt == (QEvt const *)0) { /* empty queue? */
318  }
319 
320  /* find new highest-prio AO ready to run... */
322 
323  /* is the new priority below the initial preemption threshold? */
324  if (p <= pin) {
325  p = (uint_fast8_t)0;
326  }
327  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
328  p = (uint_fast8_t)0; /* active object not eligible */
329  }
330  else {
332  }
333  } while (p != (uint_fast8_t)0);
334 
335  QK_attr_.actPrio = pin; /* restore the active priority */
336 
337 #ifdef Q_SPY
338  if (pin != (uint_fast8_t)0) { /* resuming an active object? */
339  a = QF_active_[pin]; /* the pointer to the preempted AO */
340 
342  QS_TIME_(); /* timestamp */
343  QS_2U8_((uint8_t)pin, /* priority of the resumed AO */
344  (uint8_t)pprev); /* previous priority */
346  }
347  else { /* resuming priority==0 --> idle */
348  QS_BEGIN_NOCRIT_(QS_SCHED_IDLE, (void *)0, (void *)0)
349  QS_TIME_(); /* timestamp */
350  QS_U8_((uint8_t)pprev); /* previous priority */
352  }
353 #endif /* Q_SPY */
354 }
355 
356 
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:682
#define QF_INT_ENABLE()
Define the interrupt enabling policy.
Definition: qf_port.h:209
#define QF_INT_DISABLE()
Define the interrupt disabling policy.
Definition: qf_port.h:198
#define QHSM_INIT(me_, e_)
Polymorphically executes the top-most initial transition in a HSM.
Definition: qep.h:311
void QF_add_(QActive *const a)
Register an active object to be managed by the framework.
Definition: qf_act.c:69
uint_fast8_t prio
QF priority associated with the active object.
Definition: qf.h:152
void QK_activate_(void)
QK activator activates the next active object.
Definition: qk.c:269
#define QPSet_findMax(me_, n_)
Find the maximum element in the set, and assign it to n_.
Definition: qpset.h:84
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
QEvt const * QActive_get_(QActive *const me)
Get an event from the event queue of an active object.
Definition: qf_actq.c:262
void QF_remove_(QActive *const a)
Remove the active object from the framework.
Definition: qf_act.c:109
attributes of the QK kernel
Definition: qk.h:61
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.h:57
#define QS_BEGIN_NOCRIT_(rec_, objFilter_, obj_)
Internal macro to begin a QS record without entering critical section.
Definition: qs.h:660
int_t QF_run(void)
Transfers control to QF to run the application.
Definition: qk.c:130
uint_fast8_t QK_sched_(void)
QK scheduler finds the highest-priority thread ready to run.
Definition: qk.c:239
scheduler became idle
Definition: qs.h:126
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:95
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: stdint.h:28
uint_fast8_t volatile nextPrio
prio of the next AO to execute
Definition: qk.h:63
enum_t QF_maxPubSignal_
the maximum published signal
Definition: qf_ps.c:55
static void initial_events(void)
process all events posted during initialization
Definition: qk.c:113
uint_fast8_t volatile actPrio
prio of the active AO
Definition: qk.h:62
#define QS_FLUSH()
Flush the QS trace data to the host.
Definition: qs.h:1005
QTimeEvt QF_timeEvtHead_[QF_MAX_TICK_RATE]
heads of linked lists of time events, one for every clock tick rate
Definition: qf_time.c:53
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
Internal (package scope) QF/C interface.
int enum_t
typedef for enumerations used for event signals
Definition: qep.h:76
void QF_onStartup(void)
Startup QF callback.
void QF_bzero(void *const start, uint_fast16_t len)
Clear a specified region of memory to zero.
Definition: qf_act.c:159
void QF_gc(QEvt const *const e)
Recycle a dynamic event.
Definition: qf_dyn.c:211
QK_Attr QK_attr_
global attributes of the QK kernel
Definition: qk.c:58
Event structure.
Definition: qep.h:153
void QEQueue_init(QEQueue *const me, QEvt const *qSto[], uint_fast16_t const qLen)
Initialize the native QF event queue.
Definition: qf_qeq.c:70
#define QHSM_DISPATCH(me_, e_)
Polymorphically dispatches an event to a HSM.
Definition: qep.h:326
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:130
uint_fast8_t volatile lockPrio
lock prio (0 == no-lock)
Definition: qk.h:64
void QActive_start_(QActive *const me, uint_fast8_t prio, QEvt const *qSto[], uint_fast16_t qLen, void *stkSto, uint_fast16_t stkSize, QEvt const *ie)
Implementation of the active object start operation.
Definition: qk.c:169
void QF_init(void)
QF initialization.
Definition: qk.c:71
unsigned int uint_fast16_t
fast at-least 16-bit unsigned int
Definition: stdint.h:37
uint_fast8_t QF_maxPool_
of initialized event pools
Definition: qf_dyn.c:55
#define QF_MAX_ACTIVE
The maximum number of active objects in the application.
Definition: qf_port.h:58
QPSet readySet
QK ready-set of AOs.
Definition: qk.h:69
Customizable and memory-efficient assertions for embedded systems.
#define Q_REQUIRE_ID(id_, test_)
Assertion for checking preconditions with user-specified assertion-id.
Definition: qassert.h:248
Priority Set of up to 32 elements.
Definition: qpset.h:56
void QF_onCleanup(void)
Cleanup QF callback.
#define QPSet_remove(me_, n_)
Remove element n_ from the set me_, n_= 1..32.
Definition: qpset.h:78
QHsm super
inherits QHsm
Definition: qf.h:111
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:182
void QF_stop(void)
Function invoked by the application layer to stop the QF application and return control to the OS/Ker...
Definition: qk.c:105
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:674
QSubscrList * QF_subscrList_
the subscriber list array
Definition: qf_ps.c:54
scheduler resumed previous task (not idle)
Definition: qs.h:127
#define QS_U8_(data_)
Internal QS macro to output an unformatted uint8_t data element.
Definition: qs.h:679
int int_t
typedef for line numbers in assertions and return from QF_run()
Definition: qep.h:73
void const * aoObjFilter
active object for QF local filter
Definition: qs.h:1049
void QK_onIdle(void)
QK idle callback (customized in BSPs for QK)
Active Object (based on QHsm implementation)
Definition: qf.h:110
QActive * QF_active_[QF_MAX_ACTIVE+1]
array of registered active objects
Definition: qf_act.c:53
void QActive_stop(QActive *const me)
Stops execution of an active object and removes it from the framework&#39;s supervision.
Definition: qk.c:209
scheduler found next task to execute
Definition: qs.h:125
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81