LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
os_sem.c
Go to the documentation of this file.
1 /*
2 ************************************************************************************************************************
3 * uC/OS-III
4 * The Real-Time Kernel
5 *
6 * (c) Copyright 2009-2012; Micrium, Inc.; Weston, FL
7 * All rights reserved. Protected by international copyright laws.
8 *
9 * SEMAPHORE MANAGEMENT
10 *
11 * File : OS_SEM.C
12 * By : JJL
13 * Version : V3.03.00
14 *
15 * LICENSING TERMS:
16 * ---------------
17 * uC/OS-III is provided in source form for FREE short-term evaluation, for educational use or
18 * for peaceful research. If you plan or intend to use uC/OS-III in a commercial application/
19 * product then, you need to contact Micrium to properly license uC/OS-III for its use in your
20 * application/product. We provide ALL the source code for your convenience and to help you
21 * experience uC/OS-III. The fact that the source is provided does NOT mean that you can use
22 * it commercially without paying a licensing fee.
23 *
24 * Knowledge of the source code may NOT be used to develop a similar product.
25 *
26 * Please help us continue to provide the embedded community with the finest software available.
27 * Your honesty is greatly appreciated.
28 *
29 * You can contact us at www.micrium.com, or by phone at +1 (954) 217-2036.
30 ************************************************************************************************************************
31 */
32 
33 #define MICRIUM_SOURCE
34 #include <os.h>
35 
36 #ifdef VSC_INCLUDE_SOURCE_FILE_NAMES
37 const CPU_CHAR *os_sem__c = "$Id: $";
38 #endif
39 
40 
41 #if OS_CFG_SEM_EN > 0u
42 /*
43 ************************************************************************************************************************
44 * CREATE A SEMAPHORE
45 *
46 * Description: This function creates a semaphore.
47 *
48 * Arguments : p_sem is a pointer to the semaphore to initialize. Your application is responsible for
49 * allocating storage for the semaphore.
50 *
51 * p_name is a pointer to the name you would like to give the semaphore.
52 *
53 * cnt is the initial value for the semaphore.
54 * If used to share resources, you should initialize to the number of resources available.
55 * If used to signal the occurrence of event(s) then you should initialize to 0.
56 *
57 * p_err is a pointer to a variable that will contain an error code returned by this function.
58 *
59 * OS_ERR_NONE if the call was successful
60 * OS_ERR_CREATE_ISR if you called this function from an ISR
61 * OS_ERR_ILLEGAL_CREATE_RUN_TIME if you are trying to create the semaphore after you
62 * called OSSafetyCriticalStart().
63 * OS_ERR_NAME if 'p_name' is a NULL pointer
64 * OS_ERR_OBJ_CREATED if the semaphore has already been created
65 * OS_ERR_OBJ_PTR_NULL if 'p_sem' is a NULL pointer
66 * OS_ERR_OBJ_TYPE if 'p_sem' has already been initialized to a different
67 * object type
68 *
69 * Returns : none
70 ************************************************************************************************************************
71 */
72 
73 void OSSemCreate (OS_SEM *p_sem,
74  CPU_CHAR *p_name,
75  OS_SEM_CTR cnt,
76  OS_ERR *p_err)
77 {
78  CPU_SR_ALLOC();
79 
80 
81 
82 #ifdef OS_SAFETY_CRITICAL
83  if (p_err == (OS_ERR *)0) {
84  OS_SAFETY_CRITICAL_EXCEPTION();
85  return;
86  }
87 #endif
88 
89 #ifdef OS_SAFETY_CRITICAL_IEC61508
90  if (OSSafetyCriticalStartFlag == DEF_TRUE) {
92  return;
93  }
94 #endif
95 
96 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
97  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to be called from an ISR */
98  *p_err = OS_ERR_CREATE_ISR;
99  return;
100  }
101 #endif
102 
103 #if OS_CFG_ARG_CHK_EN > 0u
104  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
105  *p_err = OS_ERR_OBJ_PTR_NULL;
106  return;
107  }
108 #endif
109 
111  p_sem->Type = OS_OBJ_TYPE_SEM; /* Mark the data structure as a semaphore */
112  p_sem->Ctr = cnt; /* Set semaphore value */
113  p_sem->TS = (CPU_TS)0;
114  p_sem->NamePtr = p_name; /* Save the name of the semaphore */
115  OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */
116 
117 #if OS_CFG_DBG_EN > 0u
118  OS_SemDbgListAdd(p_sem);
119 #endif
120  OSSemQty++;
121 
123  *p_err = OS_ERR_NONE;
124 }
125 
126 /*$PAGE*/
127 /*
128 ************************************************************************************************************************
129 * DELETE A SEMAPHORE
130 *
131 * Description: This function deletes a semaphore.
132 *
133 * Arguments : p_sem is a pointer to the semaphore to delete
134 *
135 * opt determines delete options as follows:
136 *
137 * OS_OPT_DEL_NO_PEND Delete semaphore ONLY if no task pending
138 * OS_OPT_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
139 * In this case, all the tasks pending will be readied.
140 *
141 * p_err is a pointer to a variable that will contain an error code returned by this function.
142 *
143 * OS_ERR_NONE The call was successful and the semaphore was deleted
144 * OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR
145 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
146 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
147 * OS_ERR_OPT_INVALID An invalid option was specified
148 * OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
149 *
150 * Returns : == 0 if no tasks were waiting on the semaphore, or upon error.
151 * > 0 if one or more tasks waiting on the semaphore are now readied and informed.
152 *
153 * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of the semaphore
154 * MUST check the return code of OSSemPend().
155 * 2) OSSemAccept() callers will not know that the intended semaphore has been deleted.
156 * 3) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in applications where
157 * the semaphore is used for mutual exclusion because the resource(s) will no longer be guarded by the
158 * semaphore.
159 ************************************************************************************************************************
160 */
161 
162 #if OS_CFG_SEM_DEL_EN > 0u
163 OS_OBJ_QTY OSSemDel (OS_SEM *p_sem,
164  OS_OPT opt,
165  OS_ERR *p_err)
166 {
167  OS_OBJ_QTY cnt;
168  OS_OBJ_QTY nbr_tasks;
169  OS_PEND_DATA *p_pend_data;
170  OS_PEND_LIST *p_pend_list;
171  OS_TCB *p_tcb;
172  CPU_TS ts;
173  CPU_SR_ALLOC();
174 
175 
176 
177 #ifdef OS_SAFETY_CRITICAL
178  if (p_err == (OS_ERR *)0) {
179  OS_SAFETY_CRITICAL_EXCEPTION();
180  return ((OS_OBJ_QTY)0);
181  }
182 #endif
183 
184 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
185  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to delete a semaphore from an ISR */
186  *p_err = OS_ERR_DEL_ISR;
187  return ((OS_OBJ_QTY)0);
188  }
189 #endif
190 
191 #if OS_CFG_ARG_CHK_EN > 0u
192  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
193  *p_err = OS_ERR_OBJ_PTR_NULL;
194  return ((OS_OBJ_QTY)0);
195  }
196  switch (opt) { /* Validate 'opt' */
197  case OS_OPT_DEL_NO_PEND:
198  case OS_OPT_DEL_ALWAYS:
199  break;
200 
201  default:
202  *p_err = OS_ERR_OPT_INVALID;
203  return ((OS_OBJ_QTY)0);
204  }
205 #endif
206 
207 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
208  if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
209  *p_err = OS_ERR_OBJ_TYPE;
210  return ((OS_OBJ_QTY)0);
211  }
212 #endif
213 
215  p_pend_list = &p_sem->PendList;
216  cnt = p_pend_list->NbrEntries;
217  nbr_tasks = cnt;
218  switch (opt) {
219  case OS_OPT_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
220  if (nbr_tasks == (OS_OBJ_QTY)0) {
221 #if OS_CFG_DBG_EN > 0u
222  OS_SemDbgListRemove(p_sem);
223 #endif
224  OSSemQty--;
225  OS_SemClr(p_sem);
227  *p_err = OS_ERR_NONE;
228  } else {
230  *p_err = OS_ERR_TASK_WAITING;
231  }
232  break;
233 
234  case OS_OPT_DEL_ALWAYS: /* Always delete the semaphore */
236  ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
237  while (cnt > 0u) { /* Remove all tasks on the pend list */
238  p_pend_data = p_pend_list->HeadPtr;
239  p_tcb = p_pend_data->TCBPtr;
240  OS_PendObjDel((OS_PEND_OBJ *)((void *)p_sem),
241  p_tcb,
242  ts);
243  cnt--;
244  }
245 #if OS_CFG_DBG_EN > 0u
246  OS_SemDbgListRemove(p_sem);
247 #endif
248  OSSemQty--;
249  OS_SemClr(p_sem);
251  OSSched(); /* Find highest priority task ready to run */
252  *p_err = OS_ERR_NONE;
253  break;
254 
255  default:
257  *p_err = OS_ERR_OPT_INVALID;
258  break;
259  }
260  return ((OS_OBJ_QTY)nbr_tasks);
261 }
262 #endif
263 
264 /*$PAGE*/
265 /*
266 ************************************************************************************************************************
267 * PEND ON SEMAPHORE
268 *
269 * Description: This function waits for a semaphore.
270 *
271 * Arguments : p_sem is a pointer to the semaphore
272 *
273 * timeout is an optional timeout period (in clock ticks). If non-zero, your task will wait for the
274 * resource up to the amount of time (in 'ticks') specified by this argument. If you specify
275 * 0, however, your task will wait forever at the specified semaphore or, until the resource
276 * becomes available (or the event occurs).
277 *
278 * opt determines whether the user wants to block if the semaphore is not available or not:
279 *
280 * OS_OPT_PEND_BLOCKING
281 * OS_OPT_PEND_NON_BLOCKING
282 *
283 * p_ts is a pointer to a variable that will receive the timestamp of when the semaphore was posted
284 * or pend aborted or the semaphore deleted. If you pass a NULL pointer (i.e. (CPU_TS*)0)
285 * then you will not get the timestamp. In other words, passing a NULL pointer is valid
286 * and indicates that you don't need the timestamp.
287 *
288 * p_err is a pointer to a variable that will contain an error code returned by this function.
289 *
290 * OS_ERR_NONE The call was successful and your task owns the resource
291 * or, the event you are waiting for occurred.
292 * OS_ERR_OBJ_DEL If 'p_sem' was deleted
293 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
294 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
295 * OS_ERR_OPT_INVALID If you specified an invalid value for 'opt'
296 * OS_ERR_PEND_ABORT If the pend was aborted by another task
297 * OS_ERR_PEND_ISR If you called this function from an ISR and the result
298 * would lead to a suspension.
299 * OS_ERR_PEND_WOULD_BLOCK If you specified non-blocking but the semaphore was not
300 * available.
301 * OS_ERR_SCHED_LOCKED If you called this function when the scheduler is locked
302 * OS_ERR_STATUS_INVALID Pend status is invalid
303 * OS_ERR_TIMEOUT The semaphore was not received within the specified
304 * timeout.
305 *
306 *
307 * Returns : The current value of the semaphore counter or 0 if not available.
308 ************************************************************************************************************************
309 */
310 
311 OS_SEM_CTR OSSemPend (OS_SEM *p_sem,
312  OS_TICK timeout,
313  OS_OPT opt,
314  CPU_TS *p_ts,
315  OS_ERR *p_err)
316 {
317  OS_SEM_CTR ctr;
318  OS_PEND_DATA pend_data;
319  CPU_SR_ALLOC();
320 
321 
322 
323 #ifdef OS_SAFETY_CRITICAL
324  if (p_err == (OS_ERR *)0) {
325  OS_SAFETY_CRITICAL_EXCEPTION();
326  return ((OS_SEM_CTR)0);
327  }
328 #endif
329 
330 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
331  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
332  *p_err = OS_ERR_PEND_ISR;
333  return ((OS_SEM_CTR)0);
334  }
335 #endif
336 
337 #if OS_CFG_ARG_CHK_EN > 0u
338  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
339  *p_err = OS_ERR_OBJ_PTR_NULL;
340  return ((OS_SEM_CTR)0);
341  }
342  switch (opt) { /* Validate 'opt' */
345  break;
346 
347  default:
348  *p_err = OS_ERR_OPT_INVALID;
349  return ((OS_SEM_CTR)0);
350  }
351 #endif
352 
353 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
354  if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
355  *p_err = OS_ERR_OBJ_TYPE;
356  return ((OS_SEM_CTR)0);
357  }
358 #endif
359 
360  if (p_ts != (CPU_TS *)0) {
361  *p_ts = (CPU_TS)0; /* Initialize the returned timestamp */
362  }
364  if (p_sem->Ctr > (OS_SEM_CTR)0) { /* Resource available? */
365  p_sem->Ctr--; /* Yes, caller may proceed */
366  if (p_ts != (CPU_TS *)0) {
367  *p_ts = p_sem->TS; /* get timestamp of last post */
368  }
369  ctr = p_sem->Ctr;
371  *p_err = OS_ERR_NONE;
372  return (ctr);
373  }
374 
375  if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { /* Caller wants to block if not available? */
376  ctr = p_sem->Ctr; /* No */
378  *p_err = OS_ERR_PEND_WOULD_BLOCK;
379  return (ctr);
380  } else { /* Yes */
381  if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't pend when the scheduler is locked */
383  *p_err = OS_ERR_SCHED_LOCKED;
384  return ((OS_SEM_CTR)0);
385  }
386  }
387 
388  OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); /* Lock the scheduler/re-enable interrupts */
389  OS_Pend(&pend_data, /* Block task pending on Semaphore */
390  (OS_PEND_OBJ *)((void *)p_sem),
392  timeout);
393 
395 
396  OSSched(); /* Find the next highest priority task ready to run */
397 
399  switch (OSTCBCurPtr->PendStatus) {
400  case OS_STATUS_PEND_OK: /* We got the semaphore */
401  if (p_ts != (CPU_TS *)0) {
402  *p_ts = OSTCBCurPtr->TS;
403  }
404  *p_err = OS_ERR_NONE;
405  break;
406 
407  case OS_STATUS_PEND_ABORT: /* Indicate that we aborted */
408  if (p_ts != (CPU_TS *)0) {
409  *p_ts = OSTCBCurPtr->TS;
410  }
411  *p_err = OS_ERR_PEND_ABORT;
412  break;
413 
414  case OS_STATUS_PEND_TIMEOUT: /* Indicate that we didn't get semaphore within timeout */
415  if (p_ts != (CPU_TS *)0) {
416  *p_ts = (CPU_TS )0;
417  }
418  *p_err = OS_ERR_TIMEOUT;
419  break;
420 
421  case OS_STATUS_PEND_DEL: /* Indicate that object pended on has been deleted */
422  if (p_ts != (CPU_TS *)0) {
423  *p_ts = OSTCBCurPtr->TS;
424  }
425  *p_err = OS_ERR_OBJ_DEL;
426  break;
427 
428  default:
429  *p_err = OS_ERR_STATUS_INVALID;
431  return ((OS_SEM_CTR)0);
432  }
433  ctr = p_sem->Ctr;
435  return (ctr);
436 }
437 
438 /*$PAGE*/
439 /*
440 ************************************************************************************************************************
441 * ABORT WAITING ON A SEMAPHORE
442 *
443 * Description: This function aborts & readies any tasks currently waiting on a semaphore. This function should be used
444 * to fault-abort the wait on the semaphore, rather than to normally signal the semaphore via OSSemPost().
445 *
446 * Arguments : p_sem is a pointer to the semaphore
447 *
448 * opt determines the type of ABORT performed:
449 *
450 * OS_OPT_PEND_ABORT_1 ABORT wait for a single task (HPT) waiting on the semaphore
451 * OS_OPT_PEND_ABORT_ALL ABORT wait for ALL tasks that are waiting on the semaphore
452 * OS_OPT_POST_NO_SCHED Do not call the scheduler
453 *
454 * p_err is a pointer to a variable that will contain an error code returned by this function.
455 *
456 * OS_ERR_NONE At least one task waiting on the semaphore was readied and
457 * informed of the aborted wait; check return value for the
458 * number of tasks whose wait on the semaphore was aborted.
459 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
460 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
461 * OS_ERR_OPT_INVALID If you specified an invalid option
462 * OS_ERR_PEND_ABORT_ISR If you called this function from an ISR
463 * OS_ERR_PEND_ABORT_NONE No task were pending
464 *
465 * Returns : == 0 if no tasks were waiting on the semaphore, or upon error.
466 * > 0 if one or more tasks waiting on the semaphore are now readied and informed.
467 ************************************************************************************************************************
468 */
469 
470 #if OS_CFG_SEM_PEND_ABORT_EN > 0u
471 OS_OBJ_QTY OSSemPendAbort (OS_SEM *p_sem,
472  OS_OPT opt,
473  OS_ERR *p_err)
474 {
475  OS_PEND_LIST *p_pend_list;
476  OS_TCB *p_tcb;
477  CPU_TS ts;
478  OS_OBJ_QTY nbr_tasks;
479  CPU_SR_ALLOC();
480 
481 
482 
483 #ifdef OS_SAFETY_CRITICAL
484  if (p_err == (OS_ERR *)0) {
485  OS_SAFETY_CRITICAL_EXCEPTION();
486  return ((OS_OBJ_QTY)0u);
487  }
488 #endif
489 
490 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
491  if (OSIntNestingCtr > (OS_NESTING_CTR)0u) { /* Not allowed to Pend Abort from an ISR */
492  *p_err = OS_ERR_PEND_ABORT_ISR;
493  return ((OS_OBJ_QTY)0u);
494  }
495 #endif
496 
497 #if OS_CFG_ARG_CHK_EN > 0u
498  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
499  *p_err = OS_ERR_OBJ_PTR_NULL;
500  return ((OS_OBJ_QTY)0u);
501  }
502  switch (opt) { /* Validate 'opt' */
503  case OS_OPT_PEND_ABORT_1:
507  break;
508 
509  default:
510  *p_err = OS_ERR_OPT_INVALID;
511  return ((OS_OBJ_QTY)0u);
512  }
513 #endif
514 
515 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
516  if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
517  *p_err = OS_ERR_OBJ_TYPE;
518  return ((OS_OBJ_QTY)0u);
519  }
520 #endif
521 
523  p_pend_list = &p_sem->PendList;
524  if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0u) { /* Any task waiting on semaphore? */
525  CPU_CRITICAL_EXIT(); /* No */
526  *p_err = OS_ERR_PEND_ABORT_NONE;
527  return ((OS_OBJ_QTY)0u);
528  }
529 
531  nbr_tasks = 0u;
532  ts = OS_TS_GET(); /* Get local time stamp so all tasks get the same time */
533  while (p_pend_list->NbrEntries > (OS_OBJ_QTY)0u) {
534  p_tcb = p_pend_list->HeadPtr->TCBPtr;
535  OS_PendAbort((OS_PEND_OBJ *)((void *)p_sem),
536  p_tcb,
537  ts);
538  nbr_tasks++;
539  if (opt != OS_OPT_PEND_ABORT_ALL) { /* Pend abort all tasks waiting? */
540  break; /* No */
541  }
542  }
544 
545  if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0u) {
546  OSSched(); /* Run the scheduler */
547  }
548 
549  *p_err = OS_ERR_NONE;
550  return (nbr_tasks);
551 }
552 #endif
553 
554 /*$PAGE*/
555 /*
556 ************************************************************************************************************************
557 * POST TO A SEMAPHORE
558 *
559 * Description: This function signals a semaphore
560 *
561 * Arguments : p_sem is a pointer to the semaphore
562 *
563 * opt determines the type of POST performed:
564 *
565 * OS_OPT_POST_1 POST and ready only the highest priority task waiting on semaphore
566 * (if tasks are waiting).
567 * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the semaphore
568 *
569 * OS_OPT_POST_NO_SCHED Do not call the scheduler
570 *
571 * Note(s): 1) OS_OPT_POST_NO_SCHED can be added with one of the other options.
572 *
573 * p_err is a pointer to a variable that will contain an error code returned by this function.
574 *
575 * OS_ERR_NONE The call was successful and the semaphore was signaled.
576 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
577 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
578 * OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow.
579 *
580 * Returns : The current value of the semaphore counter or 0 upon error.
581 ************************************************************************************************************************
582 */
583 
584 OS_SEM_CTR OSSemPost (OS_SEM *p_sem,
585  OS_OPT opt,
586  OS_ERR *p_err)
587 {
588  OS_SEM_CTR ctr;
589  CPU_TS ts;
590 
591 
592 
593 #ifdef OS_SAFETY_CRITICAL
594  if (p_err == (OS_ERR *)0) {
595  OS_SAFETY_CRITICAL_EXCEPTION();
596  return ((OS_SEM_CTR)0);
597  }
598 #endif
599 
600 #if OS_CFG_ARG_CHK_EN > 0u
601  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
602  *p_err = OS_ERR_OBJ_PTR_NULL;
603  return ((OS_SEM_CTR)0);
604  }
605  switch (opt) { /* Validate 'opt' */
606  case OS_OPT_POST_1:
607  case OS_OPT_POST_ALL:
608  case OS_OPT_POST_1 | OS_OPT_POST_NO_SCHED:
609  case OS_OPT_POST_ALL | OS_OPT_POST_NO_SCHED:
610  break;
611 
612  default:
613  *p_err = OS_ERR_OPT_INVALID;
614  return ((OS_SEM_CTR)0u);
615  }
616 #endif
617 
618 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
619  if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
620  *p_err = OS_ERR_OBJ_TYPE;
621  return ((OS_SEM_CTR)0);
622  }
623 #endif
624 
625  ts = OS_TS_GET(); /* Get timestamp */
626 
627 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
628  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* See if called from an ISR */
629  OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_SEM, /* Post to ISR queue */
630  (void *)p_sem,
631  (void *)0,
632  (OS_MSG_SIZE)0,
633  (OS_FLAGS )0,
634  (OS_OPT )opt,
635  (CPU_TS )ts,
636  (OS_ERR *)p_err);
637  return ((OS_SEM_CTR)0);
638  }
639 #endif
640 
641  ctr = OS_SemPost(p_sem, /* Post to semaphore */
642  opt,
643  ts,
644  p_err);
645 
646  return (ctr);
647 }
648 
649 /*$PAGE*/
650 /*
651 ************************************************************************************************************************
652 * SET SEMAPHORE
653 *
654 * Description: This function sets the semaphore count to the value specified as an argument. Typically, this value
655 * would be 0 but of course, we can set the semaphore to any value.
656 *
657 * You would typically use this function when a semaphore is used as a signaling mechanism
658 * and, you want to reset the count value.
659 *
660 * Arguments : p_sem is a pointer to the semaphore
661 *
662 * cnt is the new value for the semaphore count. You would pass 0 to reset the semaphore count.
663 *
664 * p_err is a pointer to a variable that will contain an error code returned by this function.
665 *
666 * OS_ERR_NONE The call was successful and the semaphore value was set.
667 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
668 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing to a semaphore.
669 * OS_ERR_TASK_WAITING If tasks are waiting on the semaphore.
670 *
671 * Returns : None
672 ************************************************************************************************************************
673 */
674 
675 #if OS_CFG_SEM_SET_EN > 0u
676 void OSSemSet (OS_SEM *p_sem,
677  OS_SEM_CTR cnt,
678  OS_ERR *p_err)
679 {
680  OS_PEND_LIST *p_pend_list;
681  CPU_SR_ALLOC();
682 
683 
684 
685 #ifdef OS_SAFETY_CRITICAL
686  if (p_err == (OS_ERR *)0) {
687  OS_SAFETY_CRITICAL_EXCEPTION();
688  return;
689  }
690 #endif
691 
692 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
693  if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't call this function from an ISR */
694  *p_err = OS_ERR_SET_ISR;
695  return;
696  }
697 #endif
698 
699 #if OS_CFG_ARG_CHK_EN > 0u
700  if (p_sem == (OS_SEM *)0) { /* Validate 'p_sem' */
701  *p_err = OS_ERR_OBJ_PTR_NULL;
702  return;
703  }
704 #endif
705 
706 #if OS_CFG_OBJ_TYPE_CHK_EN > 0u
707  if (p_sem->Type != OS_OBJ_TYPE_SEM) { /* Make sure semaphore was created */
708  *p_err = OS_ERR_OBJ_TYPE;
709  return;
710  }
711 #endif
712 
713  *p_err = OS_ERR_NONE;
715  if (p_sem->Ctr > (OS_SEM_CTR)0) { /* See if semaphore already has a count */
716  p_sem->Ctr = cnt; /* Yes, set it to the new value specified. */
717  } else {
718  p_pend_list = &p_sem->PendList; /* No */
719  if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* See if task(s) waiting? */
720  p_sem->Ctr = cnt; /* No, OK to set the value */
721  } else {
722  *p_err = OS_ERR_TASK_WAITING;
723  }
724  }
726 }
727 #endif
728 
729 /*$PAGE*/
730 /*
731 ************************************************************************************************************************
732 * CLEAR THE CONTENTS OF A SEMAPHORE
733 *
734 * Description: This function is called by OSSemDel() to clear the contents of a semaphore
735 *
736 
737 * Argument(s): p_sem is a pointer to the semaphore to clear
738 * -----
739 *
740 * Returns : none
741 *
742 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
743 ************************************************************************************************************************
744 */
745 
746 void OS_SemClr (OS_SEM *p_sem)
747 {
748  p_sem->Type = OS_OBJ_TYPE_NONE; /* Mark the data structure as a NONE */
749  p_sem->Ctr = (OS_SEM_CTR)0; /* Set semaphore value */
750  p_sem->TS = (CPU_TS )0; /* Clear the time stamp */
751  p_sem->NamePtr = (CPU_CHAR *)((void *)"?SEM");
752  OS_PendListInit(&p_sem->PendList); /* Initialize the waiting list */
753 }
754 
755 /*$PAGE*/
756 /*
757 ************************************************************************************************************************
758 * ADD/REMOVE SEMAPHORE TO/FROM DEBUG LIST
759 *
760 * Description: These functions are called by uC/OS-III to add or remove a semaphore to/from the debug list.
761 *
762 * Arguments : p_sem is a pointer to the semaphore to add/remove
763 *
764 * Returns : none
765 *
766 * Note(s) : These functions are INTERNAL to uC/OS-III and your application should not call it.
767 ************************************************************************************************************************
768 */
769 
770 
771 #if OS_CFG_DBG_EN > 0u
772 void OS_SemDbgListAdd (OS_SEM *p_sem)
773 {
774  p_sem->DbgNamePtr = (CPU_CHAR *)((void *)" ");
775  p_sem->DbgPrevPtr = (OS_SEM *)0;
776  if (OSSemDbgListPtr == (OS_SEM *)0) {
777  p_sem->DbgNextPtr = (OS_SEM *)0;
778  } else {
779  p_sem->DbgNextPtr = OSSemDbgListPtr;
780  OSSemDbgListPtr->DbgPrevPtr = p_sem;
781  }
782  OSSemDbgListPtr = p_sem;
783 }
784 
785 
786 
787 void OS_SemDbgListRemove (OS_SEM *p_sem)
788 {
789  OS_SEM *p_sem_next;
790  OS_SEM *p_sem_prev;
791 
792 
793  p_sem_prev = p_sem->DbgPrevPtr;
794  p_sem_next = p_sem->DbgNextPtr;
795 
796  if (p_sem_prev == (OS_SEM *)0) {
797  OSSemDbgListPtr = p_sem_next;
798  if (p_sem_next != (OS_SEM *)0) {
799  p_sem_next->DbgPrevPtr = (OS_SEM *)0;
800  }
801  p_sem->DbgNextPtr = (OS_SEM *)0;
802 
803  } else if (p_sem_next == (OS_SEM *)0) {
804  p_sem_prev->DbgNextPtr = (OS_SEM *)0;
805  p_sem->DbgPrevPtr = (OS_SEM *)0;
806 
807  } else {
808  p_sem_prev->DbgNextPtr = p_sem_next;
809  p_sem_next->DbgPrevPtr = p_sem_prev;
810  p_sem->DbgNextPtr = (OS_SEM *)0;
811  p_sem->DbgPrevPtr = (OS_SEM *)0;
812  }
813 }
814 #endif
815 
816 /*$PAGE*/
817 /*
818 ************************************************************************************************************************
819 * SEMAPHORE INITIALIZATION
820 *
821 * Description: This function is called by OSInit() to initialize the semaphore management.
822 *
823 
824 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
825 *
826 * OS_ERR_NONE the call was successful
827 *
828 * Returns : none
829 *
830 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
831 ************************************************************************************************************************
832 */
833 
834 void OS_SemInit (OS_ERR *p_err)
835 {
836 #ifdef OS_SAFETY_CRITICAL
837  if (p_err == (OS_ERR *)0) {
838  OS_SAFETY_CRITICAL_EXCEPTION();
839  return;
840  }
841 #endif
842 
843 #if OS_CFG_DBG_EN > 0u
844  OSSemDbgListPtr = (OS_SEM *)0;
845 #endif
846 
847  OSSemQty = (OS_OBJ_QTY)0;
848  *p_err = OS_ERR_NONE;
849 }
850 
851 /*$PAGE*/
852 /*
853 ************************************************************************************************************************
854 * POST TO A SEMAPHORE
855 *
856 * Description: This function signals a semaphore
857 *
858 * Arguments : p_sem is a pointer to the semaphore
859 *
860 * opt determines the type of POST performed:
861 *
862 * OS_OPT_POST_1 POST to a single waiting task
863 * OS_OPT_POST_ALL POST to ALL tasks that are waiting on the semaphore
864 *
865 * OS_OPT_POST_NO_SCHED Do not call the scheduler
866 *
867 * Note(s): 1) OS_OPT_POST_NO_SCHED can be added with one of the other options.
868 *
869 * ts is a timestamp indicating when the post occurred.
870 *
871 * p_err is a pointer to a variable that will contain an error code returned by this function.
872 *
873 * OS_ERR_NONE The call was successful and the semaphore was signaled.
874 * OS_ERR_OBJ_PTR_NULL If 'p_sem' is a NULL pointer.
875 * OS_ERR_OBJ_TYPE If 'p_sem' is not pointing at a semaphore
876 * OS_ERR_SEM_OVF If the post would cause the semaphore count to overflow.
877 *
878 * Returns : The current value of the semaphore counter or 0 upon error.
879 *
880 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
881 ************************************************************************************************************************
882 */
883 
884 OS_SEM_CTR OS_SemPost (OS_SEM *p_sem,
885  OS_OPT opt,
886  CPU_TS ts,
887  OS_ERR *p_err)
888 {
889  OS_OBJ_QTY cnt;
890  OS_SEM_CTR ctr;
891  OS_PEND_LIST *p_pend_list;
892  OS_PEND_DATA *p_pend_data;
893  OS_PEND_DATA *p_pend_data_next;
894  OS_TCB *p_tcb;
895  CPU_SR_ALLOC();
896 
897 
898 
900  p_pend_list = &p_sem->PendList;
901  if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* Any task waiting on semaphore? */
902  switch (sizeof(OS_SEM_CTR)) {
903  case 1u:
904  if (p_sem->Ctr == DEF_INT_08U_MAX_VAL) {
906  *p_err = OS_ERR_SEM_OVF;
907  return ((OS_SEM_CTR)0);
908  }
909  break;
910 
911  case 2u:
912  if (p_sem->Ctr == DEF_INT_16U_MAX_VAL) {
914  *p_err = OS_ERR_SEM_OVF;
915  return ((OS_SEM_CTR)0);
916  }
917  break;
918 
919  case 4u:
920  if (p_sem->Ctr == DEF_INT_32U_MAX_VAL) {
922  *p_err = OS_ERR_SEM_OVF;
923  return ((OS_SEM_CTR)0);
924  }
925  break;
926 
927  default:
928  break;
929  }
930  p_sem->Ctr++; /* No */
931  ctr = p_sem->Ctr;
932  p_sem->TS = ts; /* Save timestamp in semaphore control block */
934  *p_err = OS_ERR_NONE;
935  return (ctr);
936  }
937 
939  if ((opt & OS_OPT_POST_ALL) != (OS_OPT)0) { /* Post message to all tasks waiting? */
940  cnt = p_pend_list->NbrEntries; /* Yes */
941  } else {
942  cnt = (OS_OBJ_QTY)1; /* No */
943  }
944  p_pend_data = p_pend_list->HeadPtr;
945  while (cnt > 0u) {
946  p_tcb = p_pend_data->TCBPtr;
947  p_pend_data_next = p_pend_data->NextPtr;
948  OS_Post((OS_PEND_OBJ *)((void *)p_sem),
949  p_tcb,
950  (void *)0,
951  (OS_MSG_SIZE)0,
952  ts);
953  p_pend_data = p_pend_data_next;
954  cnt--;
955  }
956  ctr = p_sem->Ctr;
958  if ((opt & OS_OPT_POST_NO_SCHED) == (OS_OPT)0) {
959  OSSched(); /* Run the scheduler */
960  }
961  *p_err = OS_ERR_NONE;
962  return (ctr);
963 }
964 
965 #endif