QP/C  5.9.8
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 
78  QF_bzero(&QK_attr_, (uint_fast16_t)sizeof(QK_attr_));
79 
80  QK_attr_.actPrio = (uint_fast8_t)0; /* priority of the QK idle loop */
81  QK_attr_.lockPrio = (uint_fast8_t)QF_MAX_ACTIVE; /* scheduler locked */
82 
83 #ifdef QK_INIT
84  QK_INIT(); /* port-specific initialization of the QK kernel */
85 #endif
86 }
87 
88 /****************************************************************************/
100 void QF_stop(void) {
101  QF_onCleanup(); /* application-specific cleanup callback */
102  /* nothing else to do for the preemptive QK kernel */
103 }
104 
105 /****************************************************************************/
107 static void initial_events(void); /* prototype */
108 static void initial_events(void) {
109  QK_attr_.lockPrio = (uint_fast8_t)0; /* scheduler unlocked */
110 
111  /* any active objects need to be scheduled before starting event loop? */
112  if (QK_sched_() != (uint_fast8_t)0) {
113  QK_activate_(); /* activate AOs to process all events posted so far */
114  }
115 }
116 
117 /****************************************************************************/
125 int_t QF_run(void) {
126  QF_INT_DISABLE();
127  initial_events(); /* process all events posted during initialization */
128  QF_onStartup(); /* application-specific startup callback */
129  QF_INT_ENABLE();
130 
131  /* the QK idle loop... */
132  for (;;) {
133  QK_onIdle(); /* application-specific QK on-idle callback */
134  }
135 #ifdef __GNUC__
136  return (int_t)0;
137 #endif
138 }
139 
140 /****************************************************************************/
162 void QActive_start_(QActive * const me, uint_fast8_t prio,
163  QEvt const *qSto[], uint_fast16_t qLen,
164  void *stkSto, uint_fast16_t stkSize,
165  QEvt const *ie)
166 {
168 
173  Q_REQUIRE_ID(300, (!QK_ISR_CONTEXT_())
174  && ((uint_fast8_t)0 < prio)
175  && (prio <= (uint_fast8_t)QF_MAX_ACTIVE)
176  && (stkSto == (void *)0));
177 
178  (void)stkSize; /* unused parameter */
179 
180  QEQueue_init(&me->eQueue, qSto, qLen); /* initialize the built-in queue */
181 
182  me->prio = prio; /* set the QF priority of the AO */
183  QF_add_(me); /* make QF aware of this active object */
184 
185  QHSM_INIT(&me->super, ie); /* take the top-most initial tran. (virtual) */
186  QS_FLUSH(); /* flush the trace buffer to the host */
187 
188  /* See if this AO needs to be scheduled in case QK is already running */
189  QF_CRIT_ENTRY_();
190  if (QK_sched_() != (uint_fast8_t)0) { /* activation needed? */
191  QK_activate_();
192  }
193  QF_CRIT_EXIT_();
194 }
195 
196 /****************************************************************************/
207 void QActive_stop(QActive * const me) {
209 
211  Q_REQUIRE_ID(400, (me == QF_active_[QK_attr_.actPrio]));
212 
213  QF_remove_(me); /* remove this active object from the QF */
214 
215  QF_CRIT_ENTRY_();
217  if (QK_sched_() != (uint_fast8_t)0) {
218  QK_activate_();
219  }
220  QF_CRIT_EXIT_();
221 }
222 
223 /****************************************************************************/
246  QSchedStatus stat;
248  QF_CRIT_ENTRY_();
249 
253  Q_REQUIRE_ID(600, !QK_ISR_CONTEXT_());
254 
255  /* first store the previous lock prio */
256  if (QK_attr_.lockPrio < ceiling) { /* raising the lock prio? */
257  stat = (QSchedStatus)(QK_attr_.lockPrio << 8);
258  QK_attr_.lockPrio = ceiling;
259 
260  QS_BEGIN_NOCRIT_(QS_SCHED_LOCK, (void *)0, (void *)0)
261  QS_TIME_(); /* timestamp */
262  QS_2U8_((uint8_t)stat, /* the previous lock prio */
263  (uint8_t)QK_attr_.lockPrio); /* the new lock prio */
265 
266  /* add the previous lock holder priority */
268 
270  }
271  else {
272  stat = (QSchedStatus)0xFF;
273  }
274  QF_CRIT_EXIT_();
275 
276  return stat; /* return the status to be saved in a stack variable */
277 }
278 
279 /****************************************************************************/
296  /* has the scheduler been actually locked by the last QK_schedLock()? */
297  if (stat != (QSchedStatus)0xFF) {
298  uint_fast8_t lockPrio = QK_attr_.lockPrio; /* volatilie into tmp */
299  uint_fast8_t prevPrio = (uint_fast8_t)(stat >> 8);
301  QF_CRIT_ENTRY_();
302 
307  Q_REQUIRE_ID(700, (!QK_ISR_CONTEXT_())
308  && (lockPrio > prevPrio));
309 
310  QS_BEGIN_NOCRIT_(QS_SCHED_UNLOCK, (void *)0, (void *)0)
311  QS_TIME_(); /* timestamp */
312  QS_2U8_((uint8_t)lockPrio, /* lock prio before unlocking */
313  (uint8_t)prevPrio); /* lock priority after unlocking */
315 
316  /* restore the previous lock priority and lock holder */
317  QK_attr_.lockPrio = prevPrio;
318  QK_attr_.lockHolder = (uint_fast8_t)(stat & (QSchedStatus)0xFF);
319 
320  /* find the highest-prio thread ready to run */
321  if (QK_sched_() != (uint_fast8_t)0) { /* priority found? */
322  QK_activate_(); /* activate any unlocked basic threads */
323  }
324 
325  QF_CRIT_EXIT_();
326  }
327 }
328 
329 /****************************************************************************/
344  uint_fast8_t p; /* for priority */
345 
346  /* find the highest-prio AO with non-empty event queue */
348 
349  /* is the highest-prio below the active priority? */
350  if (p <= QK_attr_.actPrio) {
351  p = (uint_fast8_t)0; /* active object not eligible */
352  }
353  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
354  p = (uint_fast8_t)0; /* active object not eligible */
355  }
356  else {
358  QK_attr_.nextPrio = p; /* next AO to run */
359  }
360  return p;
361 }
362 
363 /****************************************************************************/
373 void QK_activate_(void) {
374  uint_fast8_t pin = QK_attr_.actPrio; /* save the active priority */
375  uint_fast8_t p = QK_attr_.nextPrio; /* the next prio to run */
376  QActive *a;
377 
378  /* QS tracing or thread-local storage? */
379 #ifdef Q_SPY
380  uint_fast8_t pprev = pin;
381 #endif /* Q_SPY */
382 
383  /* QK_attr_.nextPrio must be non-zero upon entry to QK_activate_() */
384  Q_REQUIRE_ID(500, p != (uint_fast8_t)0);
385 
386  QK_attr_.nextPrio = (uint_fast8_t)0; /* clear for the next time */
387 
388  /* loop until no more ready-to-run AOs of higher prio than the initial */
389  do {
390  QEvt const *e;
391  a = QF_active_[p]; /* obtain the pointer to the AO */
392  QK_attr_.actPrio = p; /* this becomes the active priority */
393 
395  QS_TIME_(); /* timestamp */
396  QS_2U8_((uint8_t)p, /* priority of the scheduled AO */
397  (uint8_t)pprev); /* previous priority */
399 
400 #ifdef Q_SPY
401  if (p != pprev) { /* changing priorities? */
402  pprev = p; /* update previous priority */
403  }
404 #endif /* Q_SPY */
405 
406  QF_INT_ENABLE(); /* unconditionally enable interrupts */
407 
408  /* perform the run-to-completion (RTC) step...
409  * 1. retrieve the event from the AO's event queue, which by this
410  * time must be non-empty and QActive_get_() asserts it.
411  * 2. dispatch the event to the AO's state machine.
412  * 3. determine if event is garbage and collect it if so
413  */
414  e = QActive_get_(a);
415  QHSM_DISPATCH(&a->super, e);
416  QF_gc(e);
417 
418  QF_INT_DISABLE(); /* unconditionally disable interrupts */
419 
420  if (a->eQueue.frontEvt == (QEvt const *)0) { /* empty queue? */
422  }
423 
424  /* find new highest-prio AO ready to run... */
426 
427  /* is the new priority below the initial preemption threshold? */
428  if (p <= pin) {
429  p = (uint_fast8_t)0;
430  }
431  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
432  p = (uint_fast8_t)0; /* active object not eligible */
433  }
434  else {
436  }
437  } while (p != (uint_fast8_t)0);
438 
439  QK_attr_.actPrio = pin; /* restore the active priority */
440 
441 #ifdef Q_SPY
442  if (pin != (uint_fast8_t)0) { /* resuming an active object? */
443  a = QF_active_[pin]; /* the pointer to the preempted AO */
444 
446  QS_TIME_(); /* timestamp */
447  QS_2U8_((uint8_t)pin, /* priority of the resumed AO */
448  (uint8_t)pprev); /* previous priority */
450  }
451  else { /* resuming priority==0 --> idle */
452  QS_BEGIN_NOCRIT_(QS_SCHED_IDLE, (void *)0, (void *)0)
453  QS_TIME_(); /* timestamp */
454  QS_U8_((uint8_t)pprev); /* previous priority */
456  }
457 #endif /* Q_SPY */
458 }
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:708
QPSet readySet
QK ready-set of AOs.
Definition: qk.h:69
#define QF_INT_ENABLE()
Define the interrupt enabling policy.
Definition: qf_port.h:209
void QK_schedUnlock(QSchedStatus stat)
QK Scheduler unlock.
Definition: qk.c:295
#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:310
#define QK_ISR_CONTEXT_()
Internal macro that reports the execution context (ISR vs.
Definition: qk.h:124
void QF_add_(QActive *const a)
Register an active object to be managed by the framework.
Definition: qf_act.c:69
void QK_activate_(void)
QK activator activates the next active object.
Definition: qk.c:373
#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
uint_fast8_t actPrio
prio of the active AO
Definition: qk.h:62
QEvt const * QActive_get_(QActive *const me)
Get an event from the event queue of an active object.
Definition: qf_actq.c:266
void QF_remove_(QActive *const a)
Remove the active object from the framework.
Definition: qf_act.c:109
uint_fast8_t nextPrio
prio of the next AO to execute
Definition: qk.h:63
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:686
int_t QF_run(void)
Transfers control to QF to run the application.
Definition: qk.c:125
uint_fast8_t QK_sched_(void)
QK scheduler finds the highest-priority thread ready to run.
Definition: qk.c:343
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:101
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: stdint.h:28
uint_fast8_t lockPrio
lock prio (0 == no-lock)
Definition: qk.h:64
static void initial_events(void)
process all events posted during initialization
Definition: qk.c:108
#define QS_FLUSH()
Flush the QS trace data to the host.
Definition: qs.h:1015
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
Internal (package scope) QF/C interface.
uint_fast8_t lockHolder
prio of the AO holding the lock
Definition: qk.h:65
int enum_t
typedef for enumerations used for event signals
Definition: qep.h:75
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:217
QK_Attr QK_attr_
global attributes of the QK kernel
Definition: qk.c:58
Event structure.
Definition: qep.h:152
QSchedStatus QK_schedLock(uint_fast8_t ceiling)
QK Scheduler lock.
Definition: qk.c:245
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
QHsm super
inherits QHsm
Definition: qf.h:111
QSubscrList * QF_subscrList_
the subscriber list array
Definition: qf_ps.c:54
#define QHSM_DISPATCH(me_, e_)
Polymorphically dispatches an event to a HSM.
Definition: qep.h:325
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
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:162
void QF_init(void)
QF initialization.
Definition: qk.c:71
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
active object
Definition: qs.h:1058
enum_t QF_maxPubSignal_
the maximum published signal
Definition: qf_ps.c:55
uint_fast16_t QSchedStatus
QK Scheduler locking.
Definition: qk.h:102
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
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:254
scheduler was unlocked
Definition: qs.h:124
scheduler was locked
Definition: qs.h:123
Priority Set of up to 32 elements.
Definition: qpset.h:56
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
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
#define QS_TIME_()
Internal macro to output time stamp to a QS record.
Definition: qs.h:205
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:100
#define QS_END_NOCRIT_()
Internal QS macro to end a QS record without exiting critical section.
Definition: qs.h:700
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:705
int int_t
typedef for line numbers in assertions and return from QF_run()
Definition: qep.h:72
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:207
scheduler found next task to execute
Definition: qs.h:125
uint_fast8_t prio
QF priority (1..QF_MAX_ACTIVE) of this active object.
Definition: qf.h:153
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81