QP/C  5.9.5
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(500, (!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  me->prio = prio; /* set the current priority of the AO */
182  QF_add_(me); /* make QF aware of this active object */
183 
184  QHSM_INIT(&me->super, ie); /* take the top-most initial tran. */
185  QS_FLUSH(); /* flush the trace buffer to the host */
186 
187  /* See if this AO needs to be scheduled in case QK is already running */
188  QF_CRIT_ENTRY_();
189  if (QK_sched_() != (uint_fast8_t)0) { /* activation needed? */
190  QK_activate_();
191  }
192  QF_CRIT_EXIT_();
193 }
194 
195 /****************************************************************************/
206 void QActive_stop(QActive * const me) {
208 
210  Q_REQUIRE_ID(600, (me == QF_active_[QK_attr_.actPrio]));
211 
212  QF_remove_(me); /* remove this active object from the QF */
213 
214  QF_CRIT_ENTRY_();
216  if (QK_sched_() != (uint_fast8_t)0) {
217  QK_activate_();
218  }
219  QF_CRIT_EXIT_();
220 }
221 
222 /****************************************************************************/
237  uint_fast8_t p; /* for priority */
238 
239  /* find the highest-prio AO with non-empty event queue */
241 
242  /* is the highest-prio below the active priority? */
243  if (p <= QK_attr_.actPrio) {
244  p = (uint_fast8_t)0; /* active object not eligible */
245  }
246  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
247  p = (uint_fast8_t)0; /* active object not eligible */
248  }
249  else {
251  QK_attr_.nextPrio = p; /* next AO to run */
252  }
253  return p;
254 }
255 
256 /****************************************************************************/
266 void QK_activate_(void) {
267  uint_fast8_t pin = QK_attr_.actPrio; /* save the active priority */
268  uint_fast8_t p = QK_attr_.nextPrio; /* the next prio to run */
269  QActive *a;
270 
271  /* QS tracing or thread-local storage? */
272 #ifdef Q_SPY
273  uint_fast8_t pprev = pin;
274 #endif /* Q_SPY */
275 
276  /* QK_attr_.nextPrio must be non-zero upon entry to QK_activate_() */
277  Q_REQUIRE_ID(800, p != (uint_fast8_t)0);
278 
279  QK_attr_.nextPrio = (uint_fast8_t)0; /* clear for the next time */
280 
281  /* loop until no more ready-to-run AOs of higher prio than the initial */
282  do {
283  QEvt const *e;
284  a = QF_active_[p]; /* obtain the pointer to the AO */
285  QK_attr_.actPrio = p; /* this becomes the active priority */
286 
288  QS_TIME_(); /* timestamp */
289  QS_2U8_((uint8_t)p, /* priority of the scheduled AO */
290  (uint8_t)pprev); /* previous priority */
292 
293 #ifdef Q_SPY
294  if (p != pprev) { /* changing priorities? */
295  pprev = p; /* update previous priority */
296  }
297 #endif /* Q_SPY */
298 
299  QF_INT_ENABLE(); /* unconditionally enable interrupts */
300 
301  /* perform the run-to-completion (RTC) step...
302  * 1. retrieve the event from the AO's event queue, which by this
303  * time must be non-empty and QActive_get_() asserts it.
304  * 2. dispatch the event to the AO's state machine.
305  * 3. determine if event is garbage and collect it if so
306  */
307  e = QActive_get_(a);
308  QHSM_DISPATCH(&a->super, e);
309  QF_gc(e);
310 
311  QF_INT_DISABLE(); /* unconditionally disable interrupts */
312 
313  if (a->eQueue.frontEvt == (QEvt const *)0) { /* empty queue? */
315  }
316 
317  /* find new highest-prio AO ready to run... */
319 
320  /* is the new priority below the initial preemption threshold? */
321  if (p <= pin) {
322  p = (uint_fast8_t)0;
323  }
324  else if (p <= QK_attr_.lockPrio) { /* is it below the lock prio? */
325  p = (uint_fast8_t)0; /* active object not eligible */
326  }
327  else {
329  }
330  } while (p != (uint_fast8_t)0);
331 
332  QK_attr_.actPrio = pin; /* restore the active priority */
333 
334 #ifdef Q_SPY
335  if (pin != (uint_fast8_t)0) { /* resuming an active object? */
336  a = QF_active_[pin]; /* the pointer to the preempted AO */
337 
339  QS_TIME_(); /* timestamp */
340  QS_2U8_((uint8_t)pin, /* priority of the resumed AO */
341  (uint8_t)pprev); /* previous priority */
343  }
344  else { /* resuming priority==0 --> idle */
345  QS_BEGIN_NOCRIT_(QS_SCHED_IDLE, (void *)0, (void *)0)
346  QS_TIME_(); /* timestamp */
347  QS_U8_((uint8_t)pprev); /* previous priority */
349  }
350 #endif /* Q_SPY */
351 }
352 
353 
#define QS_2U8_(data1_, data2_)
Internal QS macro to output 2 unformatted uint8_t data elements.
Definition: qs.h:708
#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:310
#define QK_ISR_CONTEXT_()
Internal macro that reports the execution context (ISR vs.
Definition: qk.h:128
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:266
#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:264
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: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:236
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 volatile nextPrio
prio of the next AO to execute
Definition: qk.h:63
static void initial_events(void)
process all events posted during initialization
Definition: qk.c:108
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:1015
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: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
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
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
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:162
void QF_init(void)
QF initialization.
Definition: qk.c:71
active object
Definition: qs.h:1058
enum_t QF_maxPubSignal_
the maximum published signal
Definition: qf_ps.c:55
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:254
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
QHsm super
inherits QHsm
Definition: qf.h:111
#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 const * locFilter[MAX_OBJ]
local QS filters
Definition: qs.h:1069
void QActive_stop(QActive *const me)
Stops execution of an active object and removes it from the framework&#39;s supervision.
Definition: qk.c:206
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