QP/C  6.1.1
qxk_sema.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 "qxk_pkg.h" /* QXK 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 qxk_h
52  #error "Source file included in a project NOT based on the QXK kernel"
53 #endif /* qxk_h */
54 
55 Q_DEFINE_THIS_MODULE("qxk_sema")
56 
57 /****************************************************************************/
79  uint_fast16_t max_count)
80 {
82  Q_REQUIRE_ID(100, max_count > (uint_fast16_t)0);
83  me->count = (uint16_t)count;
84  me->max_count = (uint16_t)max_count;
85  QPSet_setEmpty(&me->waitSet);
86 }
87 
88 /****************************************************************************/
113 bool QXSemaphore_wait(QXSemaphore * const me, uint_fast16_t const nTicks) {
114  QXThread *curr;
116 
117  QF_CRIT_ENTRY_();
118  curr = (QXThread *)QXK_attr_.curr;
119 
127  Q_REQUIRE_ID(200, (!QXK_ISR_CONTEXT_()) /* can't block inside an ISR */
128  && (me->max_count > (uint16_t)0) /* sema must be initialized */
129  && (curr != (QXThread *)0) /* curr must be extended */
130  && (QXK_attr_.lockHolder != curr->super.prio) /* not holding a lock */
131  && (curr->super.super.temp.obj == (QMState *)0)); /* not blocked */
132 
133  if (me->count > (uint16_t)0) {
134  --me->count;
135  curr->timeEvt.super.sig = (QSignal)QXK_SEMA_SIG; /* non-zero signal */
136  }
137  else {
138  /* remember the blocking object */
139  curr->super.super.temp.obj = (QMState const *)me;
140  QXThread_teArm_(curr, (QSignal)QXK_SEMA_SIG, nTicks);
141  QPSet_insert(&me->waitSet, (uint_fast8_t)curr->super.prio);
143  (void)QXK_sched_(); /* schedule the next thread */
144  QF_CRIT_EXIT_();
145  QF_CRIT_EXIT_NOP(); /* BLOCK here */
146 
147  QF_CRIT_ENTRY_();
148  /* the blocking object must be this semaphore */
149  Q_ASSERT_ID(210, curr->super.super.temp.obj == (QMState *)me);
150  curr->super.super.temp.obj = (QMState const *)0; /* clear */
151  }
152  QF_CRIT_EXIT_();
153 
154  /* signal of non-zero means that the time event has not expired */
155  return (bool)(curr->timeEvt.super.sig != (QSignal)0);
156 }
157 
158 /****************************************************************************/
174  bool isAvailable;
176 
178  Q_REQUIRE_ID(300, (me->max_count > (uint16_t)0));
179 
180  QF_CRIT_ENTRY_();
181  /* is the semaphore available? */
182  if (me->count > (uint16_t)0) {
183  --me->count;
184  isAvailable = true;
185  }
186  else { /* the semaphore is NOT available (would block) */
187  isAvailable = false;
188  }
189  QF_CRIT_EXIT_();
190 
191  return isAvailable;
192 }
193 
194 /****************************************************************************/
214 bool QXSemaphore_signal(QXSemaphore * const me) {
215  bool signaled = true; /* assume that the semaphore will be signaled */
217 
219  Q_REQUIRE_ID(400, (me->max_count > (uint16_t)0));
220 
221  QF_CRIT_ENTRY_();
222  if (QPSet_notEmpty(&me->waitSet)) {
223  uint_fast8_t p;
224  QXThread *thr;
225 
226  /* find the highest-priority thread waiting on this semaphore */
227  QPSet_findMax(&me->waitSet, p);
229  QPSet_remove(&me->waitSet, p);
230  thr = (QXThread *)QF_active_[p];
231 
232  Q_ASSERT_ID(410, (thr != (QXThread *)0) /* must be registered */
233  && (thr->super.osObject != (struct QActive *)0) /* extended thr.*/
234  && (me->count == (uint16_t)0)); /* sema counter must be 0 */
235 
236  /* disarm the internal time event */
237  (void)QXThread_teDisarm_(thr);
238 
239  if (!QXK_ISR_CONTEXT_()) { /* not inside ISR? */
240  /* schedule the next thread if multitasking started */
241  (void)QXK_sched_();
242  }
243  }
244  else {
245  if (me->count < me->max_count) {
246  ++me->count;
247  }
248  else {
249  signaled = false; /* semaphore NOT signaled */
250  }
251  }
252  QF_CRIT_EXIT_();
253 
254  return signaled;
255 }
256 
QXK_Attr QXK_attr_
global attributes of the QXK kernel
Definition: qxk.c:58
#define QF_CRIT_EXIT_NOP()
No-operation for exiting a critical section.
Definition: qf.h:810
uint8_t prio
QF priority (1..QF_MAX_ACTIVE) of this active object.
Definition: qf.h:153
Counting Semaphore of the QXK preemptive kernel.
Definition: qxthread.h:186
QSignal sig
signal of the event instance
Definition: qep.h:154
Internal (package scope) QXK/C interface.
bool QXSemaphore_wait(QXSemaphore *const me, uint_fast16_t const nTicks)
wait (block) on the semaphore
Definition: qxk_sema.c:113
bool QXSemaphore_tryWait(QXSemaphore *const me)
try wait on the semaphore (non-blocking)
Definition: qxk_sema.c:173
uint8_t volatile lockHolder
prio of the lock holder
Definition: qxk.h:86
#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
struct QActive *volatile curr
current thread pointer (NULL=basic)
Definition: qxk.h:82
#define QXK_ISR_CONTEXT_()
Internal macro that reports the execution context (ISR vs.
Definition: qxk.h:174
void QXThread_teArm_(QXThread *const me, QSignal sig, uint_fast16_t const nTicks)
internal function to arm the private time event for a given thread.
Definition: qxk_xthr.c:526
unsigned short uint16_t
exact-width 16-bit unsigned int
Definition: stdint.h:29
#define QF_CRIT_STAT_
This is an internal macro for defining the critical section status type.
Definition: qf_pkg.h:57
#define Q_DEFINE_THIS_MODULE(name_)
Define the user-specified module name for assertions in this file.
Definition: qassert.h:101
eXtended (blocking) thread of the QXK preemptive kernel
Definition: qxthread.h:71
uint_fast8_t QXK_sched_(void)
QXK scheduler finds the highest-priority thread ready to run.
Definition: qxk.c:371
unsigned int uint_fast8_t
fast at-least 8-bit unsigned int
Definition: stdint.h:35
bool QXSemaphore_signal(QXSemaphore *const me)
signal (unblock) the semaphore
Definition: qxk_sema.c:214
uint16_t QSignal
QSignal represents the signal of an event.
Definition: qep.h:130
QPSet readySet
ready-set of basic and extended threads
Definition: qxk.h:89
QHsm super
inherits QHsm
Definition: qf.h:111
#define QPSet_insert(me_, n_)
Insert element n_ into the set me_, n_= 1..32.
Definition: qpset.h:74
State object for the QMsm class (QM State Machine).
Definition: qep.h:402
#define QPSet_notEmpty(me_)
Evaluates to TRUE if the priority set me_ is not empty.
Definition: qpset.h:67
bool QXThread_teDisarm_(QXThread *const me)
internal function to disarm the private time event for a given thread.
Definition: qxk_xthr.c:568
#define Q_ASSERT_ID(id_, test_)
General purpose assertion with user-specified assertion-id.
Definition: qassert.h:136
#define QPSet_setEmpty(me_)
Makes the priority set me_ empty.
Definition: qpset.h:61
unsigned int uint_fast16_t
fast at-least 16-bit unsigned int
Definition: stdint.h:37
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
QPSet waitSet
set of extended-threads waiting on this semaphore
Definition: qxthread.h:187
union QHsmAttr temp
temporary: tran.
Definition: qep.h:284
#define QPSet_remove(me_, n_)
Remove element n_ from the set me_, n_= 1..32.
Definition: qpset.h:78
struct QMState const * obj
pointer to QMState object
Definition: qep.h:252
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 QXSemaphore_init(QXSemaphore *const me, uint_fast16_t count, uint_fast16_t max_count)
initialize the counting semaphore
Definition: qxk_sema.c:78
#define QF_CRIT_EXIT_()
This is an internal macro for exiting a critical section.
Definition: qf_pkg.h:81