| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

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) {
91 *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME;
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
110 OS_CRITICAL_ENTER();
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
122 OS_CRITICAL_EXIT_NO_SCHED();
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
214 CPU_CRITICAL_ENTER();
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);
226 CPU_CRITICAL_EXIT();
227 *p_err = OS_ERR_NONE;
228 } else {
229 CPU_CRITICAL_EXIT();
230 *p_err = OS_ERR_TASK_WAITING;
231 }
232 break;
233
234 case OS_OPT_DEL_ALWAYS: /* Always delete the semaphore */
235 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
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);
250 OS_CRITICAL_EXIT_NO_SCHED();
251 OSSched(); /* Find highest priority task ready to run */
252 *p_err = OS_ERR_NONE;
253 break;
254
255 default:
256 CPU_CRITICAL_EXIT();
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' */
343 case OS_OPT_PEND_BLOCKING:
344 case OS_OPT_PEND_NON_BLOCKING:
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 }
363 CPU_CRITICAL_ENTER();
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;
370 CPU_CRITICAL_EXIT();
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 */
377 CPU_CRITICAL_EXIT();
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 */
382 CPU_CRITICAL_EXIT();
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),
391 OS_TASK_PEND_ON_SEM,
392 timeout);
393
394 OS_CRITICAL_EXIT_NO_SCHED();
395
396 OSSched(); /* Find the next highest priority task ready to run */
397
398 CPU_CRITICAL_ENTER();
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;
430 CPU_CRITICAL_EXIT();
431 return ((OS_SEM_CTR)0);
432 }
433 ctr = p_sem->Ctr;
434 CPU_CRITICAL_EXIT();
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:
504 case OS_OPT_PEND_ABORT_ALL:
505 case OS_OPT_PEND_ABORT_1 | OS_OPT_POST_NO_SCHED:
506 case OS_OPT_PEND_ABORT_ALL | OS_OPT_POST_NO_SCHED:
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
522 CPU_CRITICAL_ENTER();
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
530 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
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 }
543 OS_CRITICAL_EXIT_NO_SCHED();
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;
714 CPU_CRITICAL_ENTER();
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 }
725 CPU_CRITICAL_EXIT();
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
899 CPU_CRITICAL_ENTER();
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) {
905 CPU_CRITICAL_EXIT();
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) {
913 CPU_CRITICAL_EXIT();
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) {
921 CPU_CRITICAL_EXIT();
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 */
933 CPU_CRITICAL_EXIT();
934 *p_err = OS_ERR_NONE;
935 return (ctr);
936 }
937
938 OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT();
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;
957 OS_CRITICAL_EXIT_NO_SCHED();
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