QP/C 6.9.0
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" /* QS port */
46  #include "qs_pkg.h" /* QS facilities for pre-defined trace records */
47 #else
48  #include "qs_dummy.h" /* disable the QS software tracing */
49 #endif /* Q_SPY */
50 
51 /* protection against including this source file in a wrong project */
52 #ifndef QK_H
53  #error "Source file included in a project NOT based on the QK kernel"
54 #endif /* QK_H */
55 
57 
58 /* Global-scope objects *****************************************************/
59 QK_PrivAttr QK_attr_; /* private attributes of the QK kernel */
60 
61 /****************************************************************************/
72 void QF_init(void) {
73  QF_maxPool_ = 0U;
75  QF_maxPubSignal_ = 0;
76 
78  QF_bzero(&QF_active_[0], sizeof(QF_active_));
79  QF_bzero(&QK_attr_, sizeof(QK_attr_));
80 
81  QK_attr_.actPrio = 0U; /* priority of the QK idle loop */
82  QK_attr_.lockPrio = QF_MAX_ACTIVE; /* scheduler locked */
83 
84 #ifdef QK_INIT
85  QK_INIT(); /* port-specific initialization of the QK kernel */
86 #endif
87 }
88 
89 /****************************************************************************/
107 void QF_stop(void) {
108  QF_onCleanup(); /* application-specific cleanup callback */
109  /* nothing else to do for the preemptive QK kernel */
110 }
111 
112 /****************************************************************************/
114 static void initial_events(void); /* prototype */
115 static void initial_events(void) {
116  QK_attr_.lockPrio = 0U; /* scheduler unlocked */
117 
118  /* any active objects need to be scheduled before starting event loop? */
119  if (QK_sched_() != 0U) {
120  QK_activate_(); /* activate AOs to process all events posted so far */
121  }
122 }
123 
124 /****************************************************************************/
133 int_t QF_run(void) {
134  QF_INT_DISABLE();
135  initial_events(); /* process all events posted during initialization */
136  QF_onStartup(); /* application-specific startup callback */
137 
138  /* produce the QS_QF_RUN trace record */
139  QS_BEGIN_NOCRIT_PRE_(QS_QF_RUN, (void *)0, (void *)0)
141 
142  QF_INT_ENABLE();
143 
144  /* the QK idle loop... */
145  for (;;) {
146  QK_onIdle(); /* application-specific QK on-idle callback */
147  }
148 #ifdef __GNUC__
149  return 0;
150 #endif
151 }
152 
153 /****************************************************************************/
175 void QActive_start_(QActive * const me, uint_fast8_t prio,
176  QEvt const * * const qSto, uint_fast16_t const qLen,
177  void * const stkSto, uint_fast16_t const stkSize,
178  void const * const par)
179 {
181 
186  Q_REQUIRE_ID(300, (!QK_ISR_CONTEXT_())
187  && (0U < prio) && (prio <= QF_MAX_ACTIVE)
188  && (stkSto == (void *)0));
189 
190  (void)stkSize; /* unused parameter */
191 
192  QEQueue_init(&me->eQueue, qSto, qLen); /* initialize the built-in queue */
193 
194  me->prio = (uint8_t)prio; /* set the QF priority of the AO */
195  QF_add_(me); /* make QF aware of this active object */
196 
197  QHSM_INIT(&me->super, par); /* top-most initial tran. */
198  QS_FLUSH(); /* flush the trace buffer to the host */
199 
200  /* See if this AO needs to be scheduled in case QK is already running */
201  QF_CRIT_ENTRY_();
202  if (QK_sched_() != 0U) { /* activation needed? */
203  QK_activate_();
204  }
205  QF_CRIT_EXIT_();
206 }
207 
208 /****************************************************************************/
231  QSchedStatus stat;
233  QF_CRIT_ENTRY_();
234 
238  Q_REQUIRE_ID(600, !QK_ISR_CONTEXT_());
239 
240  /* first store the previous lock prio */
241  if (QK_attr_.lockPrio < ceiling) { /* raising lock prio? */
242  stat = ((QSchedStatus)QK_attr_.lockPrio << 8);
243  QK_attr_.lockPrio = (uint8_t)ceiling;
244 
245  QS_BEGIN_NOCRIT_PRE_(QS_SCHED_LOCK, (void *)0, (void *)0)
246  QS_TIME_PRE_(); /* timestamp */
247  QS_2U8_PRE_(stat, /* the previous lock prio */
248  QK_attr_.lockPrio); /* the new lock prio */
250 
251  /* add the previous lock holder priority */
253 
255  }
256  else {
257  stat = 0xFFU;
258  }
259  QF_CRIT_EXIT_();
260 
261  return stat; /* return the status to be saved in a stack variable */
262 }
263 
264 /****************************************************************************/
281  /* has the scheduler been actually locked by the last QK_schedLock()? */
282  if (stat != 0xFFU) {
284  uint_fast8_t prevPrio = (uint_fast8_t)(stat >> 8);
286  QF_CRIT_ENTRY_();
287 
292  Q_REQUIRE_ID(700, (!QK_ISR_CONTEXT_())
293  && (lockPrio > prevPrio));
294 
295  QS_BEGIN_NOCRIT_PRE_(QS_SCHED_UNLOCK, (void *)0, (void *)0)
296  QS_TIME_PRE_(); /* timestamp */
297  QS_2U8_PRE_(lockPrio, /* lock prio before unlocking */
298  prevPrio); /* lock prio after unlocking */
300 
301  /* restore the previous lock priority and lock holder */
302  QK_attr_.lockPrio = (uint8_t)prevPrio;
303  QK_attr_.lockHolder = (uint8_t)(stat & 0xFFU);
304 
305  /* find the highest-prio thread ready to run */
306  if (QK_sched_() != 0U) { /* priority found? */
307  QK_activate_(); /* activate any unlocked basic threads */
308  }
309 
310  QF_CRIT_EXIT_();
311  }
312 }
313 
314 /****************************************************************************/
329  uint_fast8_t p; /* for priority */
330 
331  /* find the highest-prio AO with non-empty event queue */
333 
334  /* is the highest-prio below the active priority? */
335  if (p <= (uint_fast8_t)QK_attr_.actPrio) {
336  p = 0U; /* active object not eligible */
337  }
338  else if (p <= (uint_fast8_t)QK_attr_.lockPrio) { /* below the lock prio?*/
339  p = 0U; /* active object not eligible */
340  }
341  else {
342  Q_ASSERT_ID(410, p <= QF_MAX_ACTIVE);
343  QK_attr_.nextPrio = (uint8_t)p; /* next AO to run */
344  }
345  return p;
346 }
347 
348 /****************************************************************************/
358 void QK_activate_(void) {
359  uint_fast8_t const pin = (uint_fast8_t)QK_attr_.actPrio; /* save */
360  uint_fast8_t p = (uint_fast8_t)QK_attr_.nextPrio; /* next prio to run */
361  QActive *a;
362 #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY)
363  uint_fast8_t pprev;
364 #endif /* QK_ON_CONTEXT_SW || Q_SPY */
365 
366  /* QK_attr_.actPrio and QK_attr_.nextPrio must be in ragne */
367  Q_REQUIRE_ID(500, (pin < Q_DIM(QF_active_))
368  && (0U < p)
369  && (p < Q_DIM(QF_active_)));
370 
371 #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY)
372  pprev = pin;
373 #endif /* QK_ON_CONTEXT_SW || Q_SPY */
374 
375  QK_attr_.nextPrio = 0U; /* clear for the next time */
376 
377  /* loop until no more ready-to-run AOs of higher prio than the initial */
378  do {
379  QEvt const *e;
380  a = QF_active_[p]; /* obtain the pointer to the AO */
381  QK_attr_.actPrio = (uint8_t)p; /* this becomes the active prio */
382 
384  QS_TIME_PRE_(); /* timestamp */
385  QS_2U8_PRE_(p, /* priority of the scheduled AO */
386  pprev); /* previous priority */
388 
389 #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY)
390  if (p != pprev) { /* changing threads? */
391 
392 #ifdef QK_ON_CONTEXT_SW
393  /* context-switch callback*/
394  QK_onContextSw(((pprev != 0U)
395  ? QF_active_[pprev]
396  : (QActive *)0), a);
397 #endif /* QK_ON_CONTEXT_SW */
398 
399  pprev = p; /* update previous priority */
400  }
401 #endif /* QK_ON_CONTEXT_SW || Q_SPY */
402 
403  QF_INT_ENABLE(); /* unconditionally enable interrupts */
404 
405  /* perform the run-to-completion (RTC) step...
406  * 1. retrieve the event from the AO's event queue, which by this
407  * time must be non-empty and QActive_get_() asserts it.
408  * 2. dispatch the event to the AO's state machine.
409  * 3. determine if event is garbage and collect it if so
410  */
411  e = QActive_get_(a);
412  QHSM_DISPATCH(&a->super, e);
413  QF_gc(e);
414 
415  /* determine the next highest-priority AO ready to run... */
416  QF_INT_DISABLE(); /* unconditionally disable interrupts */
417 
418  if (a->eQueue.frontEvt == (QEvt *)0) { /* empty queue? */
420  }
421 
422  /* find new highest-prio AO ready to run... */
424 
425  /* is the new priority below the initial preemption threshold? */
426  if (p <= pin) {
427  p = 0U;
428  }
429  else if (p <= (uint_fast8_t)QK_attr_.lockPrio) {/* below lock prio? */
430  p = 0U; /* active object not eligible */
431  }
432  else {
433  Q_ASSERT_ID(510, p <= QF_MAX_ACTIVE);
434  }
435  } while (p != 0U);
436 
437  QK_attr_.actPrio = (uint8_t)pin; /* restore the active priority */
438 
439 #if (defined QK_ON_CONTEXT_SW) || (defined Q_SPY)
440  if (pin != 0U) { /* resuming an active object? */
441  a = QF_active_[pin]; /* the pointer to the preempted AO */
442 
444  QS_TIME_PRE_(); /* timestamp */
445  QS_2U8_PRE_(pin, /* priority of the resumed AO */
446  pprev); /* previous priority */
448  }
449  else { /* resuming priority==0 --> idle */
450  a = (QActive *)0; /* QK idle loop */
451 
452  QS_BEGIN_NOCRIT_PRE_(QS_SCHED_IDLE, (void *)0, (void *)0)
453  QS_TIME_PRE_(); /* timestamp */
454  QS_U8_PRE_(pprev); /* previous priority */
456  }
457 
458 #ifdef QK_ON_CONTEXT_SW
459  QK_onContextSw(QF_active_[pprev], a); /* context-switch callback */
460 #endif /* QK_ON_CONTEXT_SW */
461 
462 #endif /* QK_ON_CONTEXT_SW || Q_SPY */
463 }
464 
QS_BEGIN_NOCRIT_PRE_
#define QS_BEGIN_NOCRIT_PRE_(rec_, objFilter_, obj_)
Internal macro to begin a predefined QS record without entering critical section.
Definition: qs_pkg.h:76
QF_bzero
void QF_bzero(void *const start, uint_fast16_t len)
Clear a specified region of memory to zero.
Definition: qf_act.c:144
QActive::prio
uint8_t prio
QF priority (1..QF_MAX_ACTIVE) of this active object.
Definition: qf.h:159
QF_onStartup
void QF_onStartup(void)
Startup QF callback.
uint8_t
unsigned char uint8_t
exact-width 8-bit unsigned int
Definition: 16bit/stdint.h:29
QF_stop
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:107
QS_U8_PRE_
#define QS_U8_PRE_(data_)
Internal QS macro to output a predefined uint8_t data element.
Definition: qs_pkg.h:93
QActive_start_
void QActive_start_(QActive *const me, uint_fast8_t prio, QEvt const **const qSto, uint_fast16_t const qLen, void *const stkSto, uint_fast16_t const stkSize, void const *const par)
Implementation of the active object start operation.
Definition: qk.c:175
QK_onContextSw
void QK_onContextSw(struct QActive *prev, struct QActive *next)
QK context switch callback (customized in BSPs for QK)
QF_run
int_t QF_run(void)
Transfers control to QF to run the application.
Definition: qk.c:133
QF_CRIT_STAT_
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.h:57
QK_PrivAttr::lockHolder
uint8_t volatile lockHolder
prio of the AO holding the lock
Definition: qk.h:66
QF_CRIT_EXIT_
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81
QF_timeEvtHead_
QTimeEvt QF_timeEvtHead_[QF_MAX_TICK_RATE]
heads of linked lists of time events, one for every clock tick rate
Definition: qf_time.c:54
QK_schedLock
QSchedStatus QK_schedLock(uint_fast8_t ceiling)
QK Scheduler lock.
Definition: qk.c:230
QS_TIME_PRE_
#define QS_TIME_PRE_()
Definition: qs.h:242
QF_maxPubSignal_
enum_t QF_maxPubSignal_
the maximum published signal
Definition: qf_ps.c:56
QK_PrivAttr::readySet
QPSet readySet
QK ready-set of AOs.
Definition: qk.h:68
QF_CRIT_ENTRY_
#define QF_CRIT_ENTRY_()
This is an internal macro for entering a critical section.
Definition: qf_pkg.h:69
QK_sched_
uint_fast8_t QK_sched_(void)
QK scheduler finds the highest-priority thread ready to run.
Definition: qk.c:328
Q_DEFINE_THIS_MODULE
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:120
QK_activate_
void QK_activate_(void)
QK activator activates the next active object.
Definition: qk.c:358
QPSet_findMax
#define QPSet_findMax(me_, n_)
Find the maximum element in the set, and assign it to n_.
Definition: qpset.h:96
qassert.h
Customizable and memory-efficient assertions for embedded systems.
QF_onCleanup
void QF_onCleanup(void)
Cleanup QF callback.
qf_pkg.h
Internal (package scope) QF/C interface.
Q_DIM
#define Q_DIM(array_)
Helper macro to calculate static dimension of a 1-dim array_.
Definition: qassert.h:337
QF_subscrList_
QSubscrList * QF_subscrList_
the subscriber list array
Definition: qf_ps.c:55
QActive
Active Object base class (based on QHsm implementation)
Definition: qf.h:116
QF_gc
void QF_gc(QEvt const *const e)
Recycle a dynamic event.
Definition: qf_dyn.c:230
QK_PrivAttr
private attributes of the QK kernel
Definition: qk.h:62
uint_fast8_t
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: 16bit/stdint.h:36
QK_PrivAttr::nextPrio
uint8_t volatile nextPrio
prio of the next AO to execute
Definition: qk.h:64
QS_SCHED_NEXT
@ QS_SCHED_NEXT
scheduler found next task to execute
Definition: qs.h:140
QActive::super
QHsm super
inherits QHsm
Definition: qf.h:117
QSchedStatus
uint_fast16_t QSchedStatus
QK Scheduler locking.
Definition: qk.h:132
QEvt
Event class.
Definition: qep.h:151
QK_schedUnlock
void QK_schedUnlock(QSchedStatus stat)
QK Scheduler unlock.
Definition: qk.c:280
qs_pkg.h
Internal (package scope) QS/C interface.
QEQueue_init
void QEQueue_init(QEQueue *const me, QEvt const **const qSto, uint_fast16_t const qLen)
Initialize the native QF event queue.
Definition: qf_qeq.c:72
QF_maxPool_
uint_fast8_t QF_maxPool_
Definition: qf_dyn.c:56
QS_SCHED_RESUME
@ QS_SCHED_RESUME
scheduler resumed previous task (not idle)
Definition: qs.h:142
initial_events
static void initial_events(void)
process all events posted during initialization
Definition: qk.c:115
AO_OBJ
@ AO_OBJ
active object
Definition: qs.h:976
QK_PrivAttr::actPrio
uint8_t volatile actPrio
prio of the active AO
Definition: qk.h:63
QActive_get_
QEvt const * QActive_get_(QActive *const me)
Get an event from the event queue of an active object.
Definition: qf_actq.c:332
QF_MAX_ACTIVE
#define QF_MAX_ACTIVE
The maximum number of active objects in the application.
Definition: qxk/qf_port.h:58
QHsm::QHSM_DISPATCH
#define QHSM_DISPATCH(me_, e_)
Polymorphically dispatches an event to a HSM.
Definition: qep.h:332
QS_QF_RUN
@ QS_QF_RUN
QF_run() was entered.
Definition: qs.h:162
QK_ISR_CONTEXT_
#define QK_ISR_CONTEXT_()
Internal macro that reports the execution context (ISR vs.
Definition: qk.h:150
QS_SCHED_UNLOCK
@ QS_SCHED_UNLOCK
scheduler was unlocked
Definition: qs.h:139
QF_INT_ENABLE
#define QF_INT_ENABLE()
Definition: qk/qf_port.h:45
QS_SCHED_LOCK
@ QS_SCHED_LOCK
scheduler was locked
Definition: qs.h:138
QF_active_
QActive * QF_active_[QF_MAX_ACTIVE+1U]
array of registered active objects
Definition: qf_act.c:54
QS_2U8_PRE_
#define QS_2U8_PRE_(data1_, data2_)
Internal QS macro to output 2 predefined uint8_t data elements.
Definition: qs_pkg.h:96
Q_ASSERT_ID
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:155
Q_REQUIRE_ID
#define Q_REQUIRE_ID(id_, test_)
Assertion for checking preconditions with user-specified assertion-id.
Definition: qassert.h:279
QK_attr_
QK_PrivAttr QK_attr_
global private attributes of the QK kernel
Definition: qk.c:59
QF_INT_DISABLE
#define QF_INT_DISABLE()
Definition: qk/qf_port.h:44
QS_FLUSH
#define QS_FLUSH()
Flush the QS trace data to the host.
Definition: qs.h:428
QK_PrivAttr::lockPrio
uint8_t volatile lockPrio
lock prio (0 == no-lock)
Definition: qk.h:65
QS_priv_
QSPrivAttr QS_priv_
Definition: qs.c:48
QK_onIdle
void QK_onIdle(void)
QK idle callback (customized in BSPs for QK)
int_t
int int_t
typedef for assertions-ids and line numbers in assertions.
Definition: qassert.h:86
QPSet
Priority Set of up to 32 elements.
Definition: qpset.h:68
QSPrivAttr::locFilter
void const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:991
QS_END_NOCRIT_PRE_
#define QS_END_NOCRIT_PRE_()
Internal QS macro to end a predefined QS record without exiting critical section.
Definition: qs_pkg.h:90
QPSet_remove
#define QPSet_remove(me_, n_)
Remove element n_ from the set me_, n_= 1..32.
Definition: qpset.h:90
QF_add_
void QF_add_(QActive *const a)
Register an active object to be managed by the framework.
Definition: qf_act.c:70
QHsm::QHSM_INIT
#define QHSM_INIT(me_, par_)
Polymorphically executes the top-most initial transition in a HSM.
Definition: qep.h:312
QS_SCHED_IDLE
@ QS_SCHED_IDLE
scheduler became idle
Definition: qs.h:141
uint_fast16_t
unsigned int uint_fast16_t
fast at-least 16-bit unsigned int
Definition: 16bit/stdint.h:38
QF_init
void QF_init(void)
QF initialization.
Definition: qk.c:72