| 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_core.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 * CORE FUNCTIONS
10 *
11 * File : OS_CORE.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_core__c = "$Id: $";
38 #endif
39
40 /*
41 ************************************************************************************************************************
42 * INITIALIZATION
43 *
44 * Description: This function is used to initialize the internals of uC/OS-III and MUST be called prior to
45 * creating any uC/OS-III object and, prior to calling OS_Start().
46 *
47 * Arguments : p_err is a pointer to a variable that will contain an error code returned by this function.
48 *
49 * OS_ERR_NONE Initialization was successful
50 * Other Other OS_ERR_xxx depending on the sub-functions called by OSInit().
51 * Returns : none
52 ************************************************************************************************************************
53 */
54
55 void OSInit (OS_ERR *p_err)
56 {
57 CPU_STK *p_stk;
58 CPU_STK_SIZE size;
59
60
61
62 #ifdef OS_SAFETY_CRITICAL
63 if (p_err == (OS_ERR *)0) {
64 OS_SAFETY_CRITICAL_EXCEPTION();
65 return;
66 }
67 #endif
68
69 OSInitHook(); /* Call port specific initialization code */
70
71 OSIntNestingCtr = (OS_NESTING_CTR)0; /* Clear the interrupt nesting counter */
72
73 OSRunning = OS_STATE_OS_STOPPED; /* Indicate that multitasking not started */
74
75 OSSchedLockNestingCtr = (OS_NESTING_CTR)0; /* Clear the scheduling lock counter */
76
77 OSTCBCurPtr = (OS_TCB *)0; /* Initialize OS_TCB pointers to a known state */
78 OSTCBHighRdyPtr = (OS_TCB *)0;
79
80 OSPrioCur = (OS_PRIO)0; /* Initialize priority variables to a known state */
81 OSPrioHighRdy = (OS_PRIO)0;
82 OSPrioSaved = (OS_PRIO)0;
83
84 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
85 OSSchedLockTimeBegin = (CPU_TS)0;
86 OSSchedLockTimeMax = (CPU_TS)0;
87 OSSchedLockTimeMaxCur = (CPU_TS)0;
88 #endif
89
90 #ifdef OS_SAFETY_CRITICAL_IEC61508
91 OSSafetyCriticalStartFlag = DEF_FALSE;
92 #endif
93
94 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
95 OSSchedRoundRobinEn = DEF_FALSE;
96 OSSchedRoundRobinDfltTimeQuanta = OSCfg_TickRate_Hz / 10u;
97 #endif
98
99 if (OSCfg_ISRStkSize > (CPU_STK_SIZE)0) {
100 p_stk = OSCfg_ISRStkBasePtr; /* Clear exception stack for stack checking. */
101 if (p_stk != (CPU_STK *)0) {
102 size = OSCfg_ISRStkSize;
103 while (size > (CPU_STK_SIZE)0) {
104 size--;
105 *p_stk = (CPU_STK)0;
106 p_stk++;
107 }
108 }
109 }
110
111 #if OS_CFG_APP_HOOKS_EN > 0u
112 OS_AppTaskCreateHookPtr = (OS_APP_HOOK_TCB )0; /* Clear application hook pointers */
113 OS_AppTaskDelHookPtr = (OS_APP_HOOK_TCB )0;
114 OS_AppTaskReturnHookPtr = (OS_APP_HOOK_TCB )0;
115
116 OS_AppIdleTaskHookPtr = (OS_APP_HOOK_VOID)0;
117 OS_AppStatTaskHookPtr = (OS_APP_HOOK_VOID)0;
118 OS_AppTaskSwHookPtr = (OS_APP_HOOK_VOID)0;
119 OS_AppTimeTickHookPtr = (OS_APP_HOOK_VOID)0;
120 #endif
121
122 #if OS_CFG_TASK_REG_TBL_SIZE > 0u
123 OSTaskRegNextAvailID = (OS_REG_ID)0;
124 #endif
125
126 OS_PrioInit(); /* Initialize the priority bitmap table */
127
128 OS_RdyListInit(); /* Initialize the Ready List */
129
130
131 #if OS_CFG_FLAG_EN > 0u /* Initialize the Event Flag module */
132 OS_FlagInit(p_err);
133 if (*p_err != OS_ERR_NONE) {
134 return;
135 }
136 #endif
137
138
139 #if OS_CFG_MEM_EN > 0u /* Initialize the Memory Manager module */
140 OS_MemInit(p_err);
141 if (*p_err != OS_ERR_NONE) {
142 return;
143 }
144 #endif
145
146
147 #if (OS_MSG_EN) > 0u /* Initialize the free list of OS_MSGs */
148 OS_MsgPoolInit(p_err);
149 if (*p_err != OS_ERR_NONE) {
150 return;
151 }
152 #endif
153
154
155 #if OS_CFG_MUTEX_EN > 0u /* Initialize the Mutex Manager module */
156 OS_MutexInit(p_err);
157 if (*p_err != OS_ERR_NONE) {
158 return;
159 }
160 #endif
161
162
163 #if OS_CFG_Q_EN > 0u
164 OS_QInit(p_err); /* Initialize the Message Queue Manager module */
165 if (*p_err != OS_ERR_NONE) {
166 return;
167 }
168 #endif
169
170
171 #if OS_CFG_SEM_EN > 0u /* Initialize the Semaphore Manager module */
172 OS_SemInit(p_err);
173 if (*p_err != OS_ERR_NONE) {
174 return;
175 }
176 #endif
177
178
179 #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
180 OS_TLS_Init(p_err); /* Initialize Task Local Storage, before creating tasks */
181 if (*p_err != OS_ERR_NONE) {
182 return;
183 }
184 #endif
185
186
187 OS_TaskInit(p_err); /* Initialize the task manager */
188 if (*p_err != OS_ERR_NONE) {
189 return;
190 }
191
192
193 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
194 OS_IntQTaskInit(p_err); /* Initialize the Interrupt Queue Handler Task */
195 if (*p_err != OS_ERR_NONE) {
196 return;
197 }
198 #endif
199
200
201 OS_IdleTaskInit(p_err); /* Initialize the Idle Task */
202 if (*p_err != OS_ERR_NONE) {
203 return;
204 }
205
206
207 OS_TickTaskInit(p_err); /* Initialize the Tick Task */
208 if (*p_err != OS_ERR_NONE) {
209 return;
210 }
211
212
213 #if OS_CFG_STAT_TASK_EN > 0u /* Initialize the Statistic Task */
214 OS_StatTaskInit(p_err);
215 if (*p_err != OS_ERR_NONE) {
216 return;
217 }
218 #endif
219
220
221 #if OS_CFG_TMR_EN > 0u /* Initialize the Timer Manager module */
222 OS_TmrInit(p_err);
223 if (*p_err != OS_ERR_NONE) {
224 return;
225 }
226 #endif
227
228
229 #if OS_CFG_DBG_EN > 0u
230 OS_Dbg_Init();
231 #endif
232
233
234 OSCfg_Init();
235 }
236
237 /*$PAGE*/
238 /*
239 ************************************************************************************************************************
240 * ENTER ISR
241 *
242 * Description: This function is used to notify uC/OS-III that you are about to service an interrupt service routine
243 * (ISR). This allows uC/OS-III to keep track of interrupt nesting and thus only perform rescheduling at
244 * the last nested ISR.
245 *
246 * Arguments : none
247 *
248 * Returns : none
249 *
250 * Note(s) : 1) This function MUST be called with interrupts already disabled
251 *
252 * 2) Your ISR can directly increment 'OSIntNestingCtr' without calling this function because OSIntNestingCtr has
253 * been declared 'global', the port is actually considered part of the OS and thus is allowed to access
254 * uC/OS-III variables.
255 *
256 * 3) You MUST still call OSIntExit() even though you increment 'OSIntNestingCtr' directly.
257 *
258 * 4) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call to OSIntEnter()
259 * (or direct increment to OSIntNestingCtr) at the beginning of the ISR you MUST have a call to OSIntExit()
260 * at the end of the ISR.
261 *
262 * 5) You are allowed to nest interrupts up to 250 levels deep.
263 ************************************************************************************************************************
264 */
265
266 void OSIntEnter (void)
267 {
268 if (OSRunning != OS_STATE_OS_RUNNING) { /* Is OS running? */
269 return; /* No */
270 }
271
272 if (OSIntNestingCtr >= (OS_NESTING_CTR)250u) { /* Have we nested past 250 levels? */
273 return; /* Yes */
274 }
275
276 OSIntNestingCtr++; /* Increment ISR nesting level */
277 }
278
279 /*$PAGE*/
280 /*
281 ************************************************************************************************************************
282 * EXIT ISR
283 *
284 * Description: This function is used to notify uC/OS-III that you have completed servicing an ISR. When the last nested
285 * ISR has completed, uC/OS-III will call the scheduler to determine whether a new, high-priority task, is
286 * ready to run.
287 *
288 * Arguments : none
289 *
290 * Returns : none
291 *
292 * Note(s) : 1) You MUST invoke OSIntEnter() and OSIntExit() in pair. In other words, for every call to OSIntEnter()
293 * (or direct increment to OSIntNestingCtr) at the beginning of the ISR you MUST have a call to OSIntExit()
294 * at the end of the ISR.
295 *
296 * 2) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
297 ************************************************************************************************************************
298 */
299
300 void OSIntExit (void)
301 {
302 CPU_SR_ALLOC();
303
304
305
306 if (OSRunning != OS_STATE_OS_RUNNING) { /* Has the OS started? */
307 return; /* No */
308 }
309
310 CPU_INT_DIS();
311 if (OSIntNestingCtr == (OS_NESTING_CTR)0) { /* Prevent OSIntNestingCtr from wrapping */
312 CPU_INT_EN();
313 return;
314 }
315 OSIntNestingCtr--;
316 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ISRs still nested? */
317 CPU_INT_EN(); /* Yes */
318 return;
319 }
320
321 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler still locked? */
322 CPU_INT_EN(); /* Yes */
323 return;
324 }
325
326 OSPrioHighRdy = OS_PrioGetHighest(); /* Find highest priority */
327 OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr; /* Get highest priority task ready-to-run */
328 if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task still the highest priority? */
329 CPU_INT_EN(); /* Yes */
330 return;
331 }
332
333 #if OS_CFG_TASK_PROFILE_EN > 0u
334 OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches for this new task */
335 #endif
336 OSTaskCtxSwCtr++; /* Keep track of the total number of ctx switches */
337
338 #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
339 OS_TLS_TaskSw();
340 #endif
341
342 OSIntCtxSw(); /* Perform interrupt level ctx switch */
343 CPU_INT_EN();
344 }
345
346 /*$PAGE*/
347 /*
348 ************************************************************************************************************************
349 * INDICATE THAT IT'S NO LONGER SAFE TO CREATE OBJECTS
350 *
351 * Description: This function is called by the application code to indicate that all initialization has been completed
352 * and that kernel objects are no longer allowed to be created.
353 *
354 * Arguments : none
355 *
356 * Returns : none
357 *
358 * Note(s) : none
359 ************************************************************************************************************************
360 */
361
362 #ifdef OS_SAFETY_CRITICAL_IEC61508
363 void OSSafetyCriticalStart (void)
364 {
365 OSSafetyCriticalStartFlag = DEF_TRUE;
366 }
367
368 #endif
369
370 /*$PAGE*/
371 /*
372 ************************************************************************************************************************
373 * SCHEDULER
374 *
375 * Description: This function is called by other uC/OS-III services to determine whether a new, high priority task has
376 * been made ready to run. This function is invoked by TASK level code and is not used to reschedule tasks
377 * from ISRs (see OSIntExit() for ISR rescheduling).
378 *
379 * Arguments : none
380 *
381 * Returns : none
382 *
383 * Note(s) : 1) Rescheduling is prevented when the scheduler is locked (see OSSchedLock())
384 ************************************************************************************************************************
385 */
386
387 void OSSched (void)
388 {
389 CPU_SR_ALLOC();
390
391
392
393 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* ISRs still nested? */
394 return; /* Yes ... only schedule when no nested ISRs */
395 }
396
397 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Scheduler locked? */
398 return; /* Yes */
399 }
400
401 CPU_INT_DIS();
402 OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority ready */
403 OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
404 if (OSTCBHighRdyPtr == OSTCBCurPtr) { /* Current task is still highest priority task? */
405 CPU_INT_EN(); /* Yes ... no need to context switch */
406 return;
407 }
408
409 #if OS_CFG_TASK_PROFILE_EN > 0u
410 OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches to this task */
411 #endif
412 OSTaskCtxSwCtr++; /* Increment context switch counter */
413
414 #if defined(OS_CFG_TLS_TBL_SIZE) && (OS_CFG_TLS_TBL_SIZE > 0u)
415 OS_TLS_TaskSw();
416 #endif
417
418 OS_TASK_SW(); /* Perform a task level context switch */
419 CPU_INT_EN();
420 }
421
422 /*$PAGE*/
423 /*
424 ************************************************************************************************************************
425 * PREVENT SCHEDULING
426 *
427 * Description: This function is used to prevent rescheduling from taking place. This allows your application to prevent
428 * context switches until you are ready to permit context switching.
429 *
430 * Arguments : p_err is a pointer to a variable that will receive an error code:
431 *
432 * OS_ERR_NONE The scheduler is locked
433 * OS_ERR_LOCK_NESTING_OVF If you attempted to nest call to this function > 250 levels
434 * OS_ERR_OS_NOT_RUNNING If uC/OS-III is not running yet.
435 * OS_ERR_SCHED_LOCK_ISR If you called this function from an ISR.
436 *
437 * Returns : none
438 *
439 * Note(s) : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every
440 * call to OSSchedLock() you MUST have a call to OSSchedUnlock().
441 ************************************************************************************************************************
442 */
443
444 void OSSchedLock (OS_ERR *p_err)
445 {
446 CPU_SR_ALLOC();
447
448
449
450 #ifdef OS_SAFETY_CRITICAL
451 if (p_err == (OS_ERR *)0) {
452 OS_SAFETY_CRITICAL_EXCEPTION();
453 return;
454 }
455 #endif
456
457 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
458 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
459 *p_err = OS_ERR_SCHED_LOCK_ISR;
460 return;
461 }
462 #endif
463
464 if (OSRunning != OS_STATE_OS_RUNNING) { /* Make sure multitasking is running */
465 *p_err = OS_ERR_OS_NOT_RUNNING;
466 return;
467 }
468
469 if (OSSchedLockNestingCtr >= (OS_NESTING_CTR)250u) { /* Prevent OSSchedLockNestingCtr overflowing */
470 *p_err = OS_ERR_LOCK_NESTING_OVF;
471 return;
472 }
473
474 CPU_CRITICAL_ENTER();
475 OSSchedLockNestingCtr++; /* Increment lock nesting level */
476 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
477 OS_SchedLockTimeMeasStart();
478 #endif
479 CPU_CRITICAL_EXIT();
480 *p_err = OS_ERR_NONE;
481 }
482
483 /*$PAGE*/
484 /*
485 ************************************************************************************************************************
486 * ENABLE SCHEDULING
487 *
488 * Description: This function is used to re-allow rescheduling.
489 *
490 * Arguments : p_err is a pointer to a variable that will contain an error code returned by this function.
491 *
492 * OS_ERR_NONE
493 * OS_ERR_OS_NOT_RUNNING The scheduler has been enabled
494 * OS_ERR_SCHED_LOCKED The scheduler is still locked, still nested
495 * OS_ERR_SCHED_NOT_LOCKED The scheduler was not locked
496 * OS_ERR_SCHED_UNLOCK_ISR If you called this function from an ISR.
497 *
498 * Returns : none
499 *
500 * Note(s) : 1) You MUST invoke OSSchedLock() and OSSchedUnlock() in pair. In other words, for every call to
501 * OSSchedLock() you MUST have a call to OSSchedUnlock().
502 ************************************************************************************************************************
503 */
504
505 void OSSchedUnlock (OS_ERR *p_err)
506 {
507 CPU_SR_ALLOC();
508
509
510
511 #ifdef OS_SAFETY_CRITICAL
512 if (p_err == (OS_ERR *)0) {
513 OS_SAFETY_CRITICAL_EXCEPTION();
514 return;
515 }
516 #endif
517
518 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
519 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Not allowed to call from an ISR */
520 *p_err = OS_ERR_SCHED_UNLOCK_ISR;
521 return;
522 }
523 #endif
524
525 if (OSRunning != OS_STATE_OS_RUNNING) { /* Make sure multitasking is running */
526 *p_err = OS_ERR_OS_NOT_RUNNING;
527 return;
528 }
529
530 if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { /* See if the scheduler is locked */
531 *p_err = OS_ERR_SCHED_NOT_LOCKED;
532 return;
533 }
534
535 CPU_CRITICAL_ENTER();
536 OSSchedLockNestingCtr--; /* Decrement lock nesting level */
537 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) {
538 CPU_CRITICAL_EXIT(); /* Scheduler is still locked */
539 *p_err = OS_ERR_SCHED_LOCKED;
540 return;
541 }
542
543 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
544 OS_SchedLockTimeMeasStop();
545 #endif
546
547 CPU_CRITICAL_EXIT(); /* Scheduler should be re-enabled */
548 OSSched(); /* Run the scheduler */
549 *p_err = OS_ERR_NONE;
550 }
551
552 /*$PAGE*/
553 /*
554 ************************************************************************************************************************
555 * CONFIGURE ROUND-ROBIN SCHEDULING PARAMETERS
556 *
557 * Description: This function is called to change the round-robin scheduling parameters.
558 *
559 * Arguments : en determines whether round-robin will be enabled (when DEF_EN) or not (when DEF_DIS)
560 *
561 * dflt_time_quanta default number of ticks between time slices. 0 means assumes OSCfg_TickRate_Hz / 10.
562 *
563 * p_err is a pointer to a variable that will contain an error code returned by this function.
564 *
565 * OS_ERR_NONE The call was successful
566 *
567 * Returns : none
568 ************************************************************************************************************************
569 */
570
571 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
572 void OSSchedRoundRobinCfg (CPU_BOOLEAN en,
573 OS_TICK dflt_time_quanta,
574 OS_ERR *p_err)
575 {
576 CPU_SR_ALLOC();
577
578
579
580 #ifdef OS_SAFETY_CRITICAL
581 if (p_err == (OS_ERR *)0) {
582 OS_SAFETY_CRITICAL_EXCEPTION();
583 return;
584 }
585 #endif
586
587 CPU_CRITICAL_ENTER();
588 if (en != DEF_ENABLED) {
589 OSSchedRoundRobinEn = DEF_DISABLED;
590 } else {
591 OSSchedRoundRobinEn = DEF_ENABLED;
592 }
593
594 if (dflt_time_quanta > (OS_TICK)0) {
595 OSSchedRoundRobinDfltTimeQuanta = dflt_time_quanta;
596 } else {
597 OSSchedRoundRobinDfltTimeQuanta = (OS_TICK)(OSCfg_TickRate_Hz / (OS_RATE_HZ)10);
598 }
599 CPU_CRITICAL_EXIT();
600 *p_err = OS_ERR_NONE;
601 }
602 #endif
603
604 /*$PAGE*/
605 /*
606 ************************************************************************************************************************
607 * YIELD CPU WHEN TASK NO LONGER NEEDS THE TIME SLICE
608 *
609 * Description: This function is called to give up the CPU when it is done executing before its time slice expires.
610 *
611 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
612 *
613 * OS_ERR_NONE The call was successful
614 * OS_ERR_ROUND_ROBIN_1 Only 1 task at this priority, nothing to yield to
615 * OS_ERR_ROUND_ROBIN_DISABLED Round Robin is not enabled
616 * OS_ERR_SCHED_LOCKED The scheduler has been locked
617 * OS_ERR_YIELD_ISR Can't be called from an ISR
618 *
619 * Returns : none
620 *
621 * Note(s) : 1) This function MUST be called from a task.
622 ************************************************************************************************************************
623 */
624
625 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
626 void OSSchedRoundRobinYield (OS_ERR *p_err)
627 {
628 OS_RDY_LIST *p_rdy_list;
629 OS_TCB *p_tcb;
630 CPU_SR_ALLOC();
631
632
633
634 #ifdef OS_SAFETY_CRITICAL
635 if (p_err == (OS_ERR *)0) {
636 OS_SAFETY_CRITICAL_EXCEPTION();
637 return;
638 }
639 #endif
640
641 #if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u
642 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { /* Can't call this function from an ISR */
643 *p_err = OS_ERR_YIELD_ISR;
644 return;
645 }
646 #endif
647
648 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't yield if the scheduler is locked */
649 *p_err = OS_ERR_SCHED_LOCKED;
650 return;
651 }
652
653 if (OSSchedRoundRobinEn != DEF_TRUE) { /* Make sure round-robin has been enabled */
654 *p_err = OS_ERR_ROUND_ROBIN_DISABLED;
655 return;
656 }
657
658 CPU_CRITICAL_ENTER();
659 p_rdy_list = &OSRdyList[OSPrioCur]; /* Can't yield if it's the only task at that priority */
660 if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) {
661 CPU_CRITICAL_EXIT();
662 *p_err = OS_ERR_ROUND_ROBIN_1;
663 return;
664 }
665
666 OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */
667 p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */
668 if (p_tcb->TimeQuanta == (OS_TICK)0) { /* See if we need to use the default time slice */
669 p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
670 } else {
671 p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */
672 }
673
674 CPU_CRITICAL_EXIT();
675
676 OSSched(); /* Run new task */
677 *p_err = OS_ERR_NONE;
678 }
679 #endif
680
681 /*$PAGE*/
682 /*
683 ************************************************************************************************************************
684 * START MULTITASKING
685 *
686 * Description: This function is used to start the multitasking process which lets uC/OS-III manages the task that you
687 * created. Before you can call OSStart(), you MUST have called OSInit() and you MUST have created at least
688 * one application task.
689 *
690 * Argument(s): p_err is a pointer to a variable that will contain an error code returned by this function.
691 *
692 * OS_ERR_FATAL_RETURN OS was running and OSStart() returned.
693 * OS_ERR_OS_RUNNING OS is already running, OSStart() has no effect
694 *
695 * Returns : none
696 *
697 * Note(s) : 1) OSStartHighRdy() MUST:
698 * a) Call OSTaskSwHook() then,
699 * b) Load the context of the task pointed to by OSTCBHighRdyPtr.
700 * c) Execute the task.
701 *
702 * 2) OSStart() is not supposed to return. If it does, that would be considered a fatal error.
703 ************************************************************************************************************************
704 */
705
706 void OSStart (OS_ERR *p_err)
707 {
708 #ifdef OS_SAFETY_CRITICAL
709 if (p_err == (OS_ERR *)0) {
710 OS_SAFETY_CRITICAL_EXCEPTION();
711 return;
712 }
713 #endif
714
715 if (OSRunning == OS_STATE_OS_STOPPED) {
716 OSPrioHighRdy = OS_PrioGetHighest(); /* Find the highest priority */
717 OSPrioCur = OSPrioHighRdy;
718 OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;
719 OSTCBCurPtr = OSTCBHighRdyPtr;
720 OSRunning = OS_STATE_OS_RUNNING;
721 OSStartHighRdy(); /* Execute target specific code to start task */
722 *p_err = OS_ERR_FATAL_RETURN; /* OSStart() is not supposed to return */
723 } else {
724 *p_err = OS_ERR_OS_RUNNING; /* OS is already running */
725 }
726 }
727
728 /*$PAGE*/
729 /*
730 ************************************************************************************************************************
731 * GET VERSION
732 *
733 * Description: This function is used to return the version number of uC/OS-III. The returned value corresponds to
734 * uC/OS-III's version number multiplied by 10000. In other words, version 3.01.02 would be returned as 30102.
735 *
736 * Arguments : p_err is a pointer to a variable that will receive an error code. However, OSVersion() set this
737 * variable to
738 *
739 * OS_ERR_NONE
740 *
741 * Returns : The version number of uC/OS-III multiplied by 10000.
742 ************************************************************************************************************************
743 */
744
745 CPU_INT16U OSVersion (OS_ERR *p_err)
746 {
747 #ifdef OS_SAFETY_CRITICAL
748 if (p_err == (OS_ERR *)0) {
749 OS_SAFETY_CRITICAL_EXCEPTION();
750 return ((CPU_INT16U)0u);
751 }
752 #endif
753
754 *p_err = OS_ERR_NONE;
755 return (OS_VERSION);
756 }
757
758 /*$PAGE*/
759 /*
760 ************************************************************************************************************************
761 * IDLE TASK
762 *
763 * Description: This task is internal to uC/OS-III and executes whenever no other higher priority tasks executes because
764 * they are ALL waiting for event(s) to occur.
765 *
766 * Arguments : p_arg is an argument passed to the task when the task is created.
767 *
768 * Returns : none
769 *
770 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
771 *
772 * 2) OSIdleTaskHook() is called after the critical section to ensure that interrupts will be enabled for at
773 * least a few instructions. On some processors (ex. Philips XA), enabling and then disabling interrupts
774 * doesn't allow the processor enough time to have interrupts enabled before they were disabled again.
775 * uC/OS-III would thus never recognize interrupts.
776 *
777 * 3) This hook has been added to allow you to do such things as STOP the CPU to conserve power.
778 ************************************************************************************************************************
779 */
780
781 void OS_IdleTask (void *p_arg)
782 {
783 CPU_SR_ALLOC();
784
785
786
787 p_arg = p_arg; /* Prevent compiler warning for not using 'p_arg' */
788
789 while (DEF_ON) {
790 CPU_CRITICAL_ENTER();
791 OSIdleTaskCtr++;
792 #if OS_CFG_STAT_TASK_EN > 0u
793 OSStatTaskCtr++;
794 #endif
795 CPU_CRITICAL_EXIT();
796
797 OSIdleTaskHook(); /* Call user definable HOOK */
798 }
799 }
800
801 /*$PAGE*/
802 /*
803 ************************************************************************************************************************
804 * INITIALIZE THE IDLE TASK
805 *
806 * Description: This function initializes the idle task
807 *
808 * Arguments : p_err is a pointer to a variable that will contain an error code returned by this function.
809 *
810 * Returns : none
811 *
812 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
813 ************************************************************************************************************************
814 */
815
816 void OS_IdleTaskInit (OS_ERR *p_err)
817 {
818 #ifdef OS_SAFETY_CRITICAL
819 if (p_err == (OS_ERR *)0) {
820 OS_SAFETY_CRITICAL_EXCEPTION();
821 return;
822 }
823 #endif
824
825 OSIdleTaskCtr = (OS_IDLE_CTR)0;
826 /* ---------------- CREATE THE IDLE TASK ---------------- */
827 OSTaskCreate((OS_TCB *)&OSIdleTaskTCB,
828 (CPU_CHAR *)((void *)"uC/OS-III Idle Task"),
829 (OS_TASK_PTR)OS_IdleTask,
830 (void *)0,
831 (OS_PRIO )(OS_CFG_PRIO_MAX - 1u),
832 (CPU_STK *)OSCfg_IdleTaskStkBasePtr,
833 (CPU_STK_SIZE)OSCfg_IdleTaskStkLimit,
834 (CPU_STK_SIZE)OSCfg_IdleTaskStkSize,
835 (OS_MSG_QTY )0u,
836 (OS_TICK )0u,
837 (void *)0,
838 (OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
839 (OS_ERR *)p_err);
840 }
841
842 /*$PAGE*/
843 /*
844 ************************************************************************************************************************
845 * BLOCK A TASK PENDING ON EVENT
846 *
847 * Description: This function is called to place a task in the blocked state waiting for an event to occur. This function
848 * exist because it is common to a number of OSxxxPend() services.
849 *
850 * Arguments : p_pend_data is a pointer to an object used to link the task being blocked to the list of task(s)
851 * ----------- pending on the desired object.
852
853 * p_obj is a pointer to the object to pend on. If there are no object used to pend on then
854 * ----- the caller must pass a NULL pointer.
855 *
856 * pending_on Specifies what the task will be pending on:
857 *
858 * OS_TASK_PEND_ON_FLAG
859 * OS_TASK_PEND_ON_TASK_Q <- No object (pending for a message sent to the task)
860 * OS_TASK_PEND_ON_MUTEX
861 * OS_TASK_PEND_ON_Q
862 * OS_TASK_PEND_ON_SEM
863 * OS_TASK_PEND_ON_TASK_SEM <- No object (pending on a signal sent to the task)
864 *
865 * timeout Is the amount of time the task will wait for the event to occur.
866 *
867 * Returns : none
868 *
869 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
870 ************************************************************************************************************************
871 */
872
873 void OS_Pend (OS_PEND_DATA *p_pend_data,
874 OS_PEND_OBJ *p_obj,
875 OS_STATE pending_on,
876 OS_TICK timeout)
877 {
878 OS_PEND_LIST *p_pend_list;
879
880
881
882 OSTCBCurPtr->PendOn = pending_on; /* Resource not available, wait until it is */
883 OSTCBCurPtr->PendStatus = OS_STATUS_PEND_OK;
884
885 OS_TaskBlock(OSTCBCurPtr, /* Block the task and add it to the tick list if needed */
886 timeout);
887
888 if (p_obj != (OS_PEND_OBJ *)0) { /* Add the current task to the pend list ... */
889 p_pend_list = &p_obj->PendList; /* ... if there is an object to pend on */
890 p_pend_data->PendObjPtr = p_obj; /* Save the pointer to the object pending on */
891 OS_PendDataInit((OS_TCB *)OSTCBCurPtr, /* Initialize the remaining field */
892 (OS_PEND_DATA *)p_pend_data,
893 (OS_OBJ_QTY )1);
894 OS_PendListInsertPrio(p_pend_list, /* Insert in the pend list in priority order */
895 p_pend_data);
896 } else {
897 OSTCBCurPtr->PendDataTblEntries = (OS_OBJ_QTY )0; /* If no object being pended on the clear these fields */
898 OSTCBCurPtr->PendDataTblPtr = (OS_PEND_DATA *)0; /* ... in the TCB */
899 }
900 #if OS_CFG_DBG_EN > 0u
901 OS_PendDbgNameAdd(p_obj,
902 OSTCBCurPtr);
903 #endif
904 }
905
906 /*$PAGE*/
907 /*
908 ************************************************************************************************************************
909 * ABORT PENDING
910 *
911 * Description: This function is called by OSxxxPendAbort() functions to abort pending on an event.
912 *
913 * Arguments : p_obj Is a pointer to the object to pend abort.
914 * -----
915 *
916 * p_tcb Is a pointer to the OS_TCB of the task that we'll abort the pend for
917 * -----
918 *
919 * ts The is a timestamp as to when the pend abort occurred
920 *
921 * Returns : none
922 *
923 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
924 ************************************************************************************************************************
925 */
926
927 void OS_PendAbort (OS_PEND_OBJ *p_obj,
928 OS_TCB *p_tcb,
929 CPU_TS ts)
930 {
931 switch (p_tcb->TaskState) {
932 case OS_TASK_STATE_RDY: /* Cannot Pend Abort a task that is ready */
933 case OS_TASK_STATE_DLY: /* Cannot Pend Abort a task that is delayed */
934 case OS_TASK_STATE_SUSPENDED: /* Cannot Pend Abort a suspended task */
935 case OS_TASK_STATE_DLY_SUSPENDED: /* Cannot Pend Abort a suspended task that was also dly'd */
936 break;
937
938 case OS_TASK_STATE_PEND:
939 case OS_TASK_STATE_PEND_TIMEOUT:
940 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
941 OS_PendAbort1(p_obj, /* Indicate which object was pend aborted */
942 p_tcb,
943 ts);
944 }
945 #if (OS_MSG_EN > 0u)
946 p_tcb->MsgPtr = (void *)0;
947 p_tcb->MsgSize = (OS_MSG_SIZE)0u;
948 #endif
949 p_tcb->TS = ts;
950 if (p_obj != (OS_PEND_OBJ *)0) {
951 OS_PendListRemove(p_tcb); /* Remove task from all pend lists */
952 }
953 OS_TaskRdy(p_tcb);
954 p_tcb->TaskState = OS_TASK_STATE_RDY; /* Task will be ready */
955 p_tcb->PendStatus = OS_STATUS_PEND_ABORT; /* Indicate pend was aborted */
956 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
957 break;
958
959 case OS_TASK_STATE_PEND_SUSPENDED:
960 case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
961 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
962 OS_PendAbort1(p_obj, /* Indicate which object was pend aborted */
963 p_tcb,
964 ts);
965 }
966 #if (OS_MSG_EN > 0u)
967 p_tcb->MsgPtr = (void *)0;
968 p_tcb->MsgSize = (OS_MSG_SIZE)0u;
969 #endif
970 p_tcb->TS = ts;
971 if (p_obj != (OS_PEND_OBJ *)0) {
972 OS_PendListRemove(p_tcb); /* Remove task from all pend lists */
973 }
974 OS_TickListRemove(p_tcb); /* Cancel the timeout */
975 p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; /* Pend Aborted task is still suspended */
976 p_tcb->PendStatus = OS_STATUS_PEND_ABORT; /* Indicate pend was aborted */
977 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
978 break;
979
980 default:
981 break;
982 }
983 }
984
985 /*$PAGE*/
986 /*
987 ************************************************************************************************************************
988 * PEND ABORT A TASK PENDING ON MULTIPLE OBJECTS
989 *
990 * Description: This function is called when a task is pending on multiple objects and one of the objects has been pend
991 * aborted. This function needs to indicate to the caller which object was pend aborted by placing the
992 * address of the object in the OS_PEND_DATA table corresponding to the pend aborted object.
993 *
994 * For example, if the task pends on six (6) objects, the address of those 6 objects are placed in the
995 * .PendObjPtr field of the OS_PEND_DATA table as shown below. Note that the .PendDataTblEntries of the
996 * OS_TCB would be set to six (6) in this case. As shown, when the pend call returns because a task pend
997 * aborted 'Obj C' then, only the one entry contains the .RdyObjPtr filled in data and the other entries
998 * contains NULL pointers and zero data.
999 *
1000 * You should note that the NULL pointers are zero data values are actually filled in by the pend call.
1001 *
1002 *
1003 * .PendObjPtr .RdyObjPtr .RdyMsgPtr .RdyMsgSize .RdyTS
1004 * +--------------+--------------+--------------+--------------+--------------+
1005 * p_tcb->PendDataTblPtr -> | Obj A | 0 | 0 | 0 | 0 |
1006 * +--------------+--------------+--------------+--------------+--------------+
1007 * | Obj B | 0 | 0 | 0 | 0 |
1008 * +--------------+--------------+--------------+--------------+--------------+
1009 * | Obj C | Obj C | 0 | 0 | TS |
1010 * +--------------+--------------+--------------+--------------+--------------+
1011 * | Obj D | 0 | 0 | 0 | 0 |
1012 * +--------------+--------------+--------------+--------------+--------------+
1013 * | Obj E | 0 | 0 | 0 | 0 |
1014 * +--------------+--------------+--------------+--------------+--------------+
1015 * | Obj F | 0 | 0 | 0 | 0 |
1016 * +--------------+--------------+--------------+--------------+--------------+
1017 *
1018 *
1019 * Arguments : p_obj is a pointer to the object being pend aborted to
1020 * -----
1021 *
1022 * p_tcb is a pointer to the OS_TCB of the task that we'll abort he pend for
1023 * -----
1024 *
1025 * ts is the time stamp of when the pend abort occurred
1026 *
1027 * Returns : none
1028 *
1029 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1030 ************************************************************************************************************************
1031 */
1032
1033 void OS_PendAbort1 (OS_PEND_OBJ *p_obj,
1034 OS_TCB *p_tcb,
1035 CPU_TS ts)
1036 {
1037 OS_OBJ_QTY n_pend_list; /* Number of pend lists */
1038 OS_PEND_DATA *p_pend_data;
1039
1040
1041
1042 p_pend_data = p_tcb->PendDataTblPtr; /* Point to the first OS_PEND_DATA to remove */
1043 n_pend_list = p_tcb->PendDataTblEntries; /* Get number of entries in the table */
1044
1045 while (n_pend_list > (OS_OBJ_QTY)0) { /* Mark posted object in OS_PEND_DATA table */
1046 if (p_obj == p_pend_data->PendObjPtr) { /* Did we find the object pend aborted? */
1047 p_pend_data->RdyObjPtr = p_obj; /* Yes, indicate the object in the .RdyObjPtr */
1048 p_pend_data->RdyTS = ts; /* save the timestamp of the pend abort */
1049 break;
1050 }
1051 p_pend_data++;
1052 n_pend_list--;
1053 }
1054 }
1055
1056 /*$PAGE*/
1057 /*
1058 ************************************************************************************************************************
1059 * INITIALIZE A WAIT LIST TABLE
1060 *
1061 * Description: This function is called to initialize the fields of a table of OS_PEND_DATA entries. It's assumed that
1062 * the .PendObjPtr field of each entry in the table is set by the caller and thus will NOT be touched by
1063 * this function.
1064 *
1065 * Arguments : p_tcb is a pointer to the TCB of the task that we want to pend abort.
1066 * -----
1067 *
1068 * p_pend_data_tbl is a pointer to a table (see below) of OS_PEND_DATA elements to initialize.
1069 * ---------------
1070 *
1071 * .PendObjPtr .RdyObjPtr .RdyMsgPtr .RdyMsgSize .RdyTS .TCBPtr .NextPtr .PrevPtr
1072 * +-----------+----------+----------+-----------+------+-------+--------+--------+ ^
1073 * p_pend_data_tbl-> | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1074 * +-----------+----------+----------+-----------+------+-------+--------+--------+ |
1075 * | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1076 * +-----------+----------+----------+-----------+------+-------+--------+--------+ |
1077 * | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1078 * +-----------+----------+----------+-----------+------+-------+--------+--------+ size
1079 * | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1080 * +-----------+----------+----------+-----------+------+-------+--------+--------+ |
1081 * | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1082 * +-----------+----------+----------+-----------+------+-------+--------+--------+ |
1083 * | ? | 0 | 0 | 0 | 0 | p_tcb | 0 | 0 | |
1084 * +-----------+----------+----------+-----------+------+-------+--------+--------+ V
1085 *
1086 * tbl_size is the size of the table in number of entries
1087 *
1088 * Returns : none
1089 *
1090 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application must not call it.
1091 *
1092 * 2) It's possible for the table to be of size 1 when multi-pend is not used
1093 *
1094 * 3) Note that the .PendObjPtr is NOT touched because it's assumed to be set by the caller.
1095 ************************************************************************************************************************
1096 */
1097
1098 void OS_PendDataInit (OS_TCB *p_tcb,
1099 OS_PEND_DATA *p_pend_data_tbl,
1100 OS_OBJ_QTY tbl_size)
1101 {
1102 OS_OBJ_QTY i;
1103
1104
1105
1106 p_tcb->PendDataTblEntries = tbl_size; /* Link the TCB to the beginning of the table */
1107 p_tcb->PendDataTblPtr = p_pend_data_tbl;
1108
1109 for (i = 0u; i < tbl_size; i++) {
1110 p_pend_data_tbl->NextPtr = (OS_PEND_DATA *)0; /* Initialize all the fields */
1111 p_pend_data_tbl->PrevPtr = (OS_PEND_DATA *)0;
1112 p_pend_data_tbl->RdyObjPtr = (OS_PEND_OBJ *)0;
1113 p_pend_data_tbl->RdyMsgPtr = (void *)0;
1114 p_pend_data_tbl->RdyMsgSize = (OS_MSG_SIZE )0;
1115 p_pend_data_tbl->RdyTS = (CPU_TS )0;
1116 p_pend_data_tbl->TCBPtr = p_tcb; /* Every entry points back to the TCB of the task */
1117 p_pend_data_tbl++;
1118 }
1119 }
1120
1121 /*$PAGE*/
1122 /*
1123 ************************************************************************************************************************
1124 * ADD/REMOVE DEBUG NAMES TO PENDED OBJECT AND OS_TCB
1125 *
1126 * Description: These functions are used to add pointers to ASCII 'names' of objects so they can easily be displayed
1127 * using a kernel aware tool.
1128 *
1129 * Arguments : p_obj is a pointer to the object being pended on
1130 *
1131 * p_tcb is a pointer to the OS_TCB of the task pending on the object
1132 *
1133 * Returns : none
1134 *
1135 * Note(s) : 1) These functions are INTERNAL to uC/OS-III and your application must not call it.
1136 ************************************************************************************************************************
1137 */
1138
1139
1140 #if OS_CFG_DBG_EN > 0u
1141 void OS_PendDbgNameAdd (OS_PEND_OBJ *p_obj,
1142 OS_TCB *p_tcb)
1143 {
1144 OS_PEND_LIST *p_pend_list;
1145 OS_PEND_DATA *p_pend_data;
1146 OS_TCB *p_tcb1;
1147
1148
1149 if (p_obj != (OS_PEND_OBJ *)0) {
1150 p_tcb->DbgNamePtr = p_obj->NamePtr; /* Task pending on this object ... save name in TCB */
1151 p_pend_list = &p_obj->PendList; /* Find name of HP task pending on this object ... */
1152 p_pend_data = p_pend_list->HeadPtr;
1153 p_tcb1 = p_pend_data->TCBPtr;
1154 p_obj->DbgNamePtr = p_tcb1->NamePtr; /* ... Save in object */
1155 } else {
1156 switch (p_tcb->PendOn) {
1157 case OS_TASK_PEND_ON_TASK_Q:
1158 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Q");
1159 break;
1160
1161 case OS_TASK_PEND_ON_TASK_SEM:
1162 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)"Task Sem");
1163 break;
1164
1165 default:
1166 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" ");
1167 break;
1168 }
1169 }
1170 }
1171
1172
1173
1174 void OS_PendDbgNameRemove (OS_PEND_OBJ *p_obj,
1175 OS_TCB *p_tcb)
1176 {
1177 OS_PEND_LIST *p_pend_list;
1178 OS_PEND_DATA *p_pend_data;
1179 OS_TCB *p_tcb1;
1180
1181
1182 p_tcb->DbgNamePtr = (CPU_CHAR *)((void *)" "); /* Remove name of object pended on for readied task */
1183 p_pend_list = &p_obj->PendList;
1184 p_pend_data = p_pend_list->HeadPtr;
1185 if (p_pend_data != (OS_PEND_DATA *)0) {
1186 p_tcb1 = p_pend_data->TCBPtr;
1187 p_obj->DbgNamePtr = p_tcb1->NamePtr;
1188 } else {
1189 p_obj->DbgNamePtr = (CPU_CHAR *)((void *)" "); /* No other task pending on object */
1190 }
1191 }
1192 #endif
1193
1194 /*$PAGE*/
1195 /*
1196 ************************************************************************************************************************
1197 * CHANGE THE PRIORITY OF A TASK WAITING IN ONE OR MORE PEND LISTS
1198 *
1199 * Description: This function is called to change the position of a task waiting in one or more pend lists. Because a
1200 * task can be waiting on multiple objects then each pend list needs to be updated. Specifically, the
1201 * task can be the highest priority task waiting on one pend list, the lowest priority task waiting in yet
1202 * another pend list or somewhere else in another pend list. Because of this, we need to be able to change
1203 * each of those pend lists individually.
1204 *
1205 * The drawing below shows an example of a task (OS_TCB) that belongs to 3 separate pend lists. Each
1206 * pend list can contain multiple tasks (the .PrevPtr and .NextPtr show a '?' to indicate this). The OS_TCB
1207 * contains a pointer (.PendDataTblPtr) to the first entry in the list of pend lists.
1208 *
1209 * OS_TCB
1210 * +--------------------+
1211 * | |
1212 * +--------------------+
1213 * | PendDataTblEntries |
1214 * Point to first entry in the OS_PEND_DATA table (i.e. [0]) +--------------------+
1215 * /-----------------------------<------------------------- | PendDataTblPtr |
1216 * | +--------------------+
1217 * | ^
1218 * OS_PEND_LIST | |
1219 * +------------+ | |
1220 * | TailPtr | | |
1221 * +------------+ | |
1222 * | HeadPtr | | |
1223 * +------------+ | /---------->-------------/
1224 * | NbrEntries | | | |
1225 * +------------+ [0] V OS_PEND_DATA | |
1226 * +---------+------------+-------+---------+--------+---------+ |
1227 * ? <---- | PrevPtr | PendObjPtr | | | TCBPtr | NextPtr | --> ? |
1228 * +---------+------------+-------+---------+--------+---------+ |
1229 * |
1230 * |
1231 * |
1232 * |
1233 * |
1234 * OS_PEND_LIST Point back to TCB |
1235 * +------------+ |
1236 * | TailPtr | |
1237 * +------------+ |
1238 * | HeadPtr | |
1239 * +------------+ /----------->-------------/
1240 * | NbrEntries | | |
1241 * +------------+ [1] OS_PEND_DATA | |
1242 * +---------+------------+-------+---------+--------+---------+ |
1243 * ? <---- | PrevPtr | PendObjPtr | | | TCBPtr | NextPtr | --> ? |
1244 * +---------+------------+-------+---------+--------+---------+ |
1245 * |
1246 * |
1247 * |
1248 * |
1249 * |
1250 * OS_PEND_LIST |
1251 * +------------+ |
1252 * | TailPtr | |
1253 * +------------+ |
1254 * | HeadPtr | |
1255 * +------------+ /----------->-------------/
1256 * | NbrEntries | |
1257 * +------------+ [2] OS_PEND_DATA |
1258 * +---------+------------+-------+---------+--------+---------+
1259 * ? <---- | PrevPtr | PendObjPtr | | | TCBPtr | NextPtr | ----> ?
1260 * +---------+------------+-------+---------+--------+---------+
1261 *
1262 *
1263 * Arguments : p_tcb is a pointer to the TCB of the task to move
1264 * -----
1265 *
1266 * prio_new is the new priority for the task
1267 *
1268 * Returns : none
1269 *
1270 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1271 *
1272 * 2) It's assumed that the TCB contains the NEW priority in its .Prio field.
1273 ************************************************************************************************************************
1274 */
1275
1276 void OS_PendListChangePrio (OS_TCB *p_tcb,
1277 OS_PRIO prio_new)
1278 {
1279 OS_OBJ_QTY n_pend_list; /* Number of pend lists */
1280 OS_PEND_DATA *p_pend_data;
1281 OS_PEND_LIST *p_pend_list;
1282 OS_PEND_OBJ *p_obj;
1283
1284
1285 p_tcb->Prio = prio_new;
1286 p_pend_data = p_tcb->PendDataTblPtr; /* Point to first wait list entry */
1287 n_pend_list = p_tcb->PendDataTblEntries; /* Get the number of pend list task is in */
1288
1289 while (n_pend_list > 0u) {
1290 p_obj = p_pend_data->PendObjPtr; /* Get pointer to pend list */
1291 p_pend_list = &p_obj->PendList;
1292 if (p_pend_list->NbrEntries > 1u) { /* Only move if multiple entries in the list */
1293 OS_PendListRemove1(p_pend_list, /* Remove entry from current position */
1294 p_pend_data);
1295 OS_PendListInsertPrio(p_pend_list, /* INSERT it back in the list */
1296 p_pend_data);
1297 }
1298 p_pend_data++; /* Point to next wait list */
1299 n_pend_list--;
1300 }
1301 }
1302
1303 /*$PAGE*/
1304 /*
1305 ************************************************************************************************************************
1306 * INITIALIZE A WAIT LIST
1307 *
1308 * Description: This function is called to initialize the fields of an OS_PEND_LIST.
1309 *
1310 * Arguments : p_pend_list is a pointer to an OS_PEND_LIST
1311 * -----------
1312 *
1313 * Returns : none
1314 *
1315 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application must not call it.
1316 ************************************************************************************************************************
1317 */
1318
1319 void OS_PendListInit (OS_PEND_LIST *p_pend_list)
1320 {
1321 p_pend_list->HeadPtr = (OS_PEND_DATA *)0;
1322 p_pend_list->TailPtr = (OS_PEND_DATA *)0;
1323 p_pend_list->NbrEntries = (OS_OBJ_QTY )0;
1324 }
1325
1326 /*$PAGE*/
1327 /*
1328 ************************************************************************************************************************
1329 * INSERT PEND DATA AT THE BEGINNING OF A WAIT LIST
1330 *
1331 * Description: This function is called to place an OS_PEND_DATA entry at the beginning of a linked list as follows:
1332 *
1333 * CASE 0: Insert in an empty list.
1334 *
1335 * OS_PEND_LIST
1336 * +--------------+
1337 * | TailPtr |-> 0
1338 * +--------------+
1339 * | HeadPtr |-> 0
1340 * +--------------+
1341 * | NbrEntries=0 |
1342 * +--------------+
1343 *
1344 *
1345 *
1346 * CASE 1: Insert BEFORE the current head of list
1347 *
1348 * OS_PEND_LIST
1349 * +--------------+ OS_PEND_DATA
1350 * | TailPtr |--+---> +------------+
1351 * +--------------+ | | NextPtr |->0
1352 * | HeadPtr |--/ +------------+
1353 * +--------------+ 0<-| PrevPtr |
1354 * | NbrEntries=1 | +------------+
1355 * +--------------+ | |
1356 * +------------+
1357 * | |
1358 * +------------+
1359 *
1360 *
1361 * Arguments : p_pend_list is a pointer to a wait list found inside an object. The OS_PEND_DATA entry will be
1362 * ----------- inserted at the head of the list.
1363 *
1364 * p_pend_data is a pointer to the OS_PEND_DATA entry to add to the list
1365 * -----------
1366 *
1367 * Returns : none
1368 *
1369 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1370 ************************************************************************************************************************
1371 */
1372
1373 void OS_PendListInsertHead (OS_PEND_LIST *p_pend_list,
1374 OS_PEND_DATA *p_pend_data)
1375 {
1376 OS_PEND_DATA *p_pend_data_next;
1377
1378
1379
1380 p_pend_list->NbrEntries++; /* One more entry in the list */
1381 p_pend_data->NextPtr = p_pend_list->HeadPtr; /* Adjust new entry's links */
1382 p_pend_data->PrevPtr = (OS_PEND_DATA *)0;
1383 p_pend_data_next = p_pend_list->HeadPtr; /* Adjust old head of list's links */
1384 if (p_pend_data_next != (OS_PEND_DATA *)0) { /* See if we already have a head to replace */
1385 p_pend_data_next->PrevPtr = p_pend_data; /* Yes, point to new entry */
1386 }
1387 p_pend_list->HeadPtr = p_pend_data; /* We have a new list head */
1388 if (p_pend_list->NbrEntries == 1u) {
1389 p_pend_list->TailPtr = p_pend_data;
1390 }
1391 }
1392
1393 /*$PAGE*/
1394 /*
1395 ************************************************************************************************************************
1396 * INSERT PEND DATA BASED ON IT'S PRIORITY IN A LIST
1397 *
1398 * Description: This function is called to place an OS_PEND_DATA entry in a linked list based on its priority. The
1399 * highest priority being placed at the head of the list. It's assumed that the OS_PEND_DATA entry to
1400 * insert points to the TCB of the task being inserted. The TCB is also assumed to contain the priority
1401 * of the task in its .Prio field.
1402 *
1403 * CASE 0: Insert in an empty list.
1404 *
1405 * OS_PEND_LIST
1406 * +---------------+
1407 * | TailPtr |-> 0
1408 * +---------------+
1409 * | HeadPtr |-> 0
1410 * +---------------+
1411 * | NbrEntries=0 |
1412 * +---------------+
1413 *
1414 *
1415 *
1416 * CASE 1: Insert BEFORE or AFTER an OS_TCB
1417 *
1418 * OS_PEND_LIST
1419 * +--------------+ OS_PEND_DATA
1420 * | TailPtr |--+---> +------------+
1421 * +--------------+ | | NextPtr |->0
1422 * | HeadPtr |--/ +------------+
1423 * +--------------+ 0<-| PrevPtr |
1424 * | NbrEntries=1 | +------------+
1425 * +--------------+ | |
1426 * +------------+
1427 * | |
1428 * +------------+
1429 *
1430 *
1431 * OS_PEND_LIST
1432 * +--------------+
1433 * | TailPtr |-----------------------------------------------+
1434 * +--------------+ OS_PEND_DATA OS_PEND_DATA | OS_PEND_DATA
1435 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
1436 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
1437 * | NbrEntries=N | +------------+ +------------+ +------------+
1438 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
1439 * +------------+ +------------+ +------------+
1440 * | | | | | |
1441 * +------------+ +------------+ +------------+
1442 * | | | | | |
1443 * +------------+ +------------+ +------------+
1444 *
1445 *
1446 * Arguments : p_pend_list is a pointer to the OS_PEND_LIST where the OS_PEND_DATA entry will be inserted
1447 * -----------
1448 *
1449 * p_pend_data is the OS_PEND_DATA to insert in the list
1450 * -----------
1451 *
1452 * Returns : none
1453 *
1454 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1455 *
1456 * 2) 'p_pend_data->TCBPtr->Prio' contains the priority of the TCB associated with the entry to insert.
1457 * We can compare this priority with the priority of other entries in the list.
1458 ************************************************************************************************************************
1459 */
1460
1461 void OS_PendListInsertPrio (OS_PEND_LIST *p_pend_list,
1462 OS_PEND_DATA *p_pend_data)
1463 {
1464 OS_PRIO prio;
1465 OS_TCB *p_tcb;
1466 OS_TCB *p_tcb_next;
1467 OS_PEND_DATA *p_pend_data_prev;
1468 OS_PEND_DATA *p_pend_data_next;
1469
1470
1471
1472 p_tcb = p_pend_data->TCBPtr; /* Obtain the priority of the task to insert */
1473 prio = p_tcb->Prio;
1474 if (p_pend_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
1475 p_pend_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
1476 p_pend_data->NextPtr = (OS_PEND_DATA *)0; /* No other OS_PEND_DATAs in the list */
1477 p_pend_data->PrevPtr = (OS_PEND_DATA *)0;
1478 p_pend_list->HeadPtr = p_pend_data; /* */
1479 p_pend_list->TailPtr = p_pend_data;
1480 } else {
1481 p_pend_list->NbrEntries++; /* CASE 1: One more OS_PEND_DATA in the list */
1482 p_pend_data_next = p_pend_list->HeadPtr;
1483 while (p_pend_data_next != (OS_PEND_DATA *)0) { /* Find the position where to insert */
1484 p_tcb_next = p_pend_data_next->TCBPtr;
1485 if (prio < p_tcb_next->Prio) {
1486 break; /* Found! ... insert BEFORE current */
1487 } else {
1488 p_pend_data_next = p_pend_data_next->NextPtr; /* Not Found, follow the list */
1489 }
1490 }
1491 if (p_pend_data_next == (OS_PEND_DATA *)0) { /* TCB to insert is lower in prio */
1492 p_pend_data->NextPtr = (OS_PEND_DATA *)0; /* ... insert at the tail. */
1493 p_pend_data_prev = p_pend_list->TailPtr;
1494 p_pend_data->PrevPtr = p_pend_data_prev;
1495 p_pend_data_prev->NextPtr = p_pend_data;
1496 p_pend_list->TailPtr = p_pend_data;
1497 } else {
1498 if (p_pend_data_next->PrevPtr == (OS_PEND_DATA *)0) { /* Is new TCB highest priority? */
1499 p_pend_data_next->PrevPtr = p_pend_data; /* Yes, insert as new Head of list */
1500 p_pend_data->PrevPtr = (OS_PEND_DATA *)0;
1501 p_pend_data->NextPtr = p_pend_data_next;
1502 p_pend_list->HeadPtr = p_pend_data;
1503 } else {
1504 p_pend_data_prev = p_pend_data_next->PrevPtr;/* No, insert in between two entries */
1505 p_pend_data->PrevPtr = p_pend_data_prev;
1506 p_pend_data->NextPtr = p_pend_data_next;
1507 p_pend_data_prev->NextPtr = p_pend_data;
1508 p_pend_data_next->PrevPtr = p_pend_data;
1509 }
1510 }
1511 }
1512 }
1513
1514 /*$PAGE*/
1515 /*
1516 ************************************************************************************************************************
1517 * REMOVE TASK FROM PEND LIST(s) KNOWING ONLY WHICH TCB TO REMOVE
1518 *
1519 * Description: This function is called to remove a task from a pend list knowing only the TCB of the task to remove
1520 *
1521 *
1522 * CASE 0: OS_PEND_DATA list is empty, nothing to do.
1523 *
1524 * CASE 1: Only 1 OS_PEND_DATA in the list.
1525 *
1526 * OS_PEND_LIST
1527 * +--------------+ OS_PEND_DATA
1528 * | TailPtr |--+---> +------------+
1529 * +--------------+ | | NextPtr |->0
1530 * | HeadPtr |--/ +------------+
1531 * +--------------+ 0<-| PrevPtr |
1532 * | NbrEntries=1 | +------------+
1533 * +--------------+ | |
1534 * +------------+
1535 * | |
1536 * +------------+
1537 *
1538 * CASE N: Two or more OS_PEND_DATAs in the list.
1539 *
1540 * OS_PEND_LIST
1541 * +--------------+
1542 * | TailPtr |-----------------------------------------------+
1543 * +--------------+ OS_PEND_DATA OS_PEND_DATA | OS_PEND_DATA
1544 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
1545 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
1546 * | NbrEntries=N | +------------+ +------------+ +------------+
1547 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
1548 * +------------+ +------------+ +------------+
1549 * | | | | | |
1550 * +------------+ +------------+ +------------+
1551 * | | | | | |
1552 * +------------+ +------------+ +------------+
1553 *
1554 *
1555 * Arguments : p_tcb is a pointer to the TCB of the task to remove from all pend lists
1556 * -----
1557 *
1558 * Returns : none
1559 *
1560 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1561 ************************************************************************************************************************
1562 */
1563
1564 void OS_PendListRemove (OS_TCB *p_tcb)
1565 {
1566 OS_OBJ_QTY n_pend_list; /* Number of pend lists */
1567 OS_PEND_DATA *p_pend_data;
1568 OS_PEND_LIST *p_pend_list;
1569 OS_PEND_OBJ *p_obj;
1570
1571
1572
1573 p_pend_data = p_tcb->PendDataTblPtr; /* Point to the first OS_PEND_DATA to remove */
1574 n_pend_list = p_tcb->PendDataTblEntries; /* Get number of entries in the table */
1575
1576 while (n_pend_list > (OS_OBJ_QTY)0) {
1577 p_obj = p_pend_data->PendObjPtr; /* Get pointer to pend list */
1578 p_pend_list = &p_obj->PendList;
1579 OS_PendListRemove1(p_pend_list,
1580 p_pend_data);
1581 p_pend_data++;
1582 n_pend_list--;
1583 }
1584 p_tcb->PendDataTblEntries = (OS_OBJ_QTY )0;
1585 p_tcb->PendDataTblPtr = (OS_PEND_DATA *)0;
1586 }
1587
1588 /*$PAGE*/
1589 /*
1590 ************************************************************************************************************************
1591 * REMOVE AN 'OS_PEND_DATA' ENTRY from a 'OS_PEND_LIST'
1592 *
1593 * Description: This function is called to remove a task from a wait list knowing only the TCB of the task to remove
1594 *
1595 *
1596 * CASE 1: Only 1 OS_PEND_DATA in the list.
1597 *
1598 * OS_PEND_LIST
1599 * +--------------+ OS_PEND_DATA
1600 * | TailPtr |--+---> +------------+
1601 * +--------------+ | | NextPtr |->0
1602 * | HeadPtr |--/ +------------+
1603 * +--------------+ 0<-| PrevPtr |
1604 * | NbrEntries=1 | +------------+
1605 * +--------------+ | |
1606 * +------------+
1607 * | |
1608 * +------------+
1609 *
1610 * CASE N: Two or more OS_PEND_DATAs in the list.
1611 *
1612 * OS_PEND_LIST
1613 * +--------------+
1614 * | TailPtr |-----------------------------------------------+
1615 * +--------------+ OS_PEND_DATA OS_PEND_DATA | OS_PEND_DATA
1616 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
1617 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
1618 * | NbrEntries=N | +------------+ +------------+ +------------+
1619 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
1620 * +------------+ +------------+ +------------+
1621 * | | | | | |
1622 * +------------+ +------------+ +------------+
1623 * | | | | | |
1624 * +------------+ +------------+ +------------+
1625 *
1626 *
1627 * Arguments : p_pend_list is a pointer to the pend list where 'p_pend_data' will be removed from
1628 * -----------
1629 *
1630 * p_pend_data is a pointer to the OS_PEND_DATA to remove from the pend list
1631 * -----------
1632 *
1633 * Returns : none
1634 *
1635 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1636 ************************************************************************************************************************
1637 */
1638
1639 void OS_PendListRemove1 (OS_PEND_LIST *p_pend_list,
1640 OS_PEND_DATA *p_pend_data)
1641 {
1642 OS_PEND_DATA *p_prev;
1643 OS_PEND_DATA *p_next;
1644
1645
1646
1647 if (p_pend_list->NbrEntries == 1u) {
1648 p_pend_list->HeadPtr = (OS_PEND_DATA *)0; /* Only one entry in the pend list */
1649 p_pend_list->TailPtr = (OS_PEND_DATA *)0;
1650
1651 } else if (p_pend_data->PrevPtr == (OS_PEND_DATA *)0) { /* See if entry is at the head of the list */
1652 p_next = p_pend_data->NextPtr; /* Yes */
1653 p_next->PrevPtr = (OS_PEND_DATA *)0;
1654 p_pend_list->HeadPtr = p_next;
1655
1656 } else if (p_pend_data->NextPtr == (OS_PEND_DATA *)0) { /* See if entry is at the tail of the list */
1657 p_prev = p_pend_data->PrevPtr; /* Yes */
1658 p_prev->NextPtr = (OS_PEND_DATA *)0;
1659 p_pend_list->TailPtr = p_prev;
1660
1661 } else {
1662 p_prev = p_pend_data->PrevPtr; /* Remove from inside the list */
1663 p_next = p_pend_data->NextPtr;
1664 p_prev->NextPtr = p_next;
1665 p_next->PrevPtr = p_prev;
1666 }
1667 p_pend_list->NbrEntries--; /* One less entry in the list */
1668 p_pend_data->NextPtr = (OS_PEND_DATA *)0;
1669 p_pend_data->PrevPtr = (OS_PEND_DATA *)0;
1670 }
1671
1672 /*$PAGE*/
1673 /*
1674 ************************************************************************************************************************
1675 * READY A TASK THAT WAS PENDING ON AN OBJECT BEING DELETED
1676 *
1677 * Description: This function is called when a object is to make a task ready-to-run.
1678 *
1679 * Arguments : p_obj is a pointer to the object being deleted
1680 * -----
1681 *
1682 * p_tcb is a pointer to the OS_TCB of the task to make ready-to-run
1683 * -----
1684 *
1685 * ts is a timestamp to indicate when the object was deleted
1686 *
1687 * Returns : none
1688 *
1689 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
1690 ************************************************************************************************************************
1691 */
1692
1693 void OS_PendObjDel (OS_PEND_OBJ *p_obj,
1694 OS_TCB *p_tcb,
1695 CPU_TS ts)
1696 {
1697 switch (p_tcb->TaskState) {
1698 case OS_TASK_STATE_RDY: /* These states should never occur */
1699 case OS_TASK_STATE_DLY:
1700 case OS_TASK_STATE_SUSPENDED:
1701 case OS_TASK_STATE_DLY_SUSPENDED:
1702 break;
1703
1704 case OS_TASK_STATE_PEND:
1705 case OS_TASK_STATE_PEND_TIMEOUT:
1706 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
1707 OS_PendObjDel1(p_obj, /* Indicate which object was pend aborted */
1708 p_tcb,
1709 ts);
1710 }
1711 #if (OS_MSG_EN > 0u)
1712 p_tcb->MsgPtr = (void *)0;
1713 p_tcb->MsgSize = (OS_MSG_SIZE)0u;
1714 #endif
1715 p_tcb->TS = ts;
1716 OS_PendListRemove(p_tcb); /* Remove task from all wait lists */
1717 OS_TaskRdy(p_tcb);
1718 p_tcb->TaskState = OS_TASK_STATE_RDY; /* Task is readied because object is deleted */
1719 p_tcb->PendStatus = OS_STATUS_PEND_DEL; /* Indicate pend was aborted */
1720 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING;
1721 break;
1722
1723 case OS_TASK_STATE_PEND_SUSPENDED:
1724 case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
1725 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
1726 OS_PendObjDel1(p_obj, /* Indicate which object was pend aborted */
1727 p_tcb,
1728 ts);
1729 }
1730 #if (OS_MSG_EN > 0u)
1731 p_tcb->MsgPtr = (void *)0;
1732 p_tcb->MsgSize = (OS_MSG_SIZE)0u;
1733 #endif
1734 p_tcb->TS = ts;
1735 OS_TickListRemove(p_tcb); /* Cancel the timeout */
1736 OS_PendListRemove(p_tcb); /* Remove task from all wait lists */
1737 p_tcb->TaskState = OS_TASK_STATE_SUSPENDED; /* Task needs to remain suspended */
1738 p_tcb->PendStatus = OS_STATUS_PEND_DEL; /* Indicate pend was aborted */
1739 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
1740 break;
1741
1742 default:
1743 break;
1744 }
1745 }
1746
1747 /*$PAGE*/
1748 /*
1749 ************************************************************************************************************************
1750 * DELETE AN OBJECT FROM A TASK PENDING ON MULTIPLE OBJECTS
1751 *
1752 * Description: This function is called when a task is pending on multiple objects and the object is being deleted.
1753 * This function needs to indicate to the caller which object was deleted by placing the address of the
1754 * object in the OS_PEND_DATA table corresponding to the deleted object.
1755 *
1756 * For example, if the task pends on six (6) objects, the address of those 6 objects are placed in the
1757 * .PendObjPtr field of the OS_PEND_DATA table as shown below. Note that the .PendDataTblEntries would be
1758 * set to six (6) in this case. As shown, when the pend call returns because a task deleted 'Obj C' then,
1759 * only the one entry contains the filled in data and the other entries contains NULL pointers and zero
1760 * data.
1761 *
1762 * You should note that the NULL pointers are zero data values are actually filled in by the pend call.
1763 *
1764 *
1765 * .PendObjPtr .RdyObjPtr .RdyMsgPtr .RdyMsgSize .RdyTS
1766 * +--------------+--------------+--------------+--------------+--------------+
1767 * p_tcb->PendDataTblPtr -> | Obj A | 0 | 0 | 0 | 0 |
1768 * +--------------+--------------+--------------+--------------+--------------+
1769 * | Obj B | 0 | 0 | 0 | 0 |
1770 * +--------------+--------------+--------------+--------------+--------------+
1771 * | Obj C | Obj C | 0 | 0 | TS |
1772 * +--------------+--------------+--------------+--------------+--------------+
1773 * | Obj D | 0 | 0 | 0 | 0 |
1774 * +--------------+--------------+--------------+--------------+--------------+
1775 * | Obj E | 0 | 0 | 0 | 0 |
1776 * +--------------+--------------+--------------+--------------+--------------+
1777 * | Obj F | 0 | 0 | 0 | 0 |
1778 * +--------------+--------------+--------------+--------------+--------------+
1779 *
1780 *
1781 * Arguments : p_obj is a pointer to the object being deleted
1782 * -----
1783 *
1784 * p_tcb is the OS_TCB of the task pending on the object being deleted
1785 * -----
1786 *
1787 * ts is the time stamp of when the object was deleted
1788 *
1789 * Returns : none
1790 *
1791 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1792 ************************************************************************************************************************
1793 */
1794
1795 void OS_PendObjDel1 (OS_PEND_OBJ *p_obj,
1796 OS_TCB *p_tcb,
1797 CPU_TS ts)
1798 {
1799 OS_OBJ_QTY n_pend_list; /* Number of pend lists */
1800 OS_PEND_DATA *p_pend_data;
1801
1802
1803
1804 p_pend_data = p_tcb->PendDataTblPtr; /* Point to the first OS_PEND_DATA to remove */
1805 n_pend_list = p_tcb->PendDataTblEntries; /* Get number of entries in the table */
1806
1807 while (n_pend_list > (OS_OBJ_QTY)0) { /* Mark posted object in OS_PEND_DATA table */
1808 if (p_obj == p_pend_data->PendObjPtr) { /* Did we find the object deleted? */
1809 p_pend_data->RdyObjPtr = p_obj; /* Yes, indicate the object in the .RdyObjPtr */
1810 p_pend_data->RdyTS = ts; /* save the timestamp */
1811 break;
1812 }
1813 p_pend_data++;
1814 n_pend_list--;
1815 }
1816 }
1817
1818 /*$PAGE*/
1819 /*
1820 ************************************************************************************************************************
1821 * POST TO A TASK
1822 *
1823 * Description: This function is called to post to a task. This function exist because it is common to a number of
1824 * OSxxxPost() services.
1825 *
1826 * Arguments : p_obj Is a pointer to the object being posted to or NULL pointer if there is no object
1827 * -----
1828 *
1829 * p_tcb Is a pointer to the OS_TCB that will receive the 'post'
1830 * -----
1831 *
1832 * p_void If we are posting a message to a task, this is the message that the task will receive
1833 *
1834 * msg_size If we are posting a message to a task, this is the size of the message
1835 *
1836 * ts The timestamp as to when the post occurred
1837 *
1838 * Returns : none
1839 *
1840 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
1841 ************************************************************************************************************************
1842 */
1843
1844 void OS_Post (OS_PEND_OBJ *p_obj,
1845 OS_TCB *p_tcb,
1846 void *p_void,
1847 OS_MSG_SIZE msg_size,
1848 CPU_TS ts)
1849 {
1850 switch (p_tcb->TaskState) {
1851 case OS_TASK_STATE_RDY: /* Cannot Pend Abort a task that is ready */
1852 case OS_TASK_STATE_DLY: /* Cannot Pend Abort a task that is delayed */
1853 case OS_TASK_STATE_SUSPENDED: /* Cannot Post a suspended task */
1854 case OS_TASK_STATE_DLY_SUSPENDED: /* Cannot Post a suspended task that was also dly'd */
1855 break;
1856
1857 case OS_TASK_STATE_PEND:
1858 case OS_TASK_STATE_PEND_TIMEOUT:
1859 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
1860 OS_Post1(p_obj, /* Indicate which object was posted to */
1861 p_tcb,
1862 p_void,
1863 msg_size,
1864 ts);
1865 } else {
1866 #if (OS_MSG_EN > 0u)
1867 p_tcb->MsgPtr = p_void; /* Deposit message in OS_TCB of task waiting */
1868 p_tcb->MsgSize = msg_size; /* ... assuming posting a message */
1869 #endif
1870 p_tcb->TS = ts;
1871 }
1872 if (p_obj != (OS_PEND_OBJ *)0) {
1873 OS_PendListRemove(p_tcb); /* Remove task from wait list(s) */
1874 #if OS_CFG_DBG_EN > 0u
1875 OS_PendDbgNameRemove(p_obj,
1876 p_tcb);
1877 #endif
1878 }
1879 OS_TaskRdy(p_tcb); /* Make task ready to run */
1880 p_tcb->TaskState = OS_TASK_STATE_RDY;
1881 p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */
1882 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
1883 break;
1884
1885 case OS_TASK_STATE_PEND_SUSPENDED:
1886 case OS_TASK_STATE_PEND_TIMEOUT_SUSPENDED:
1887 if (p_tcb->PendOn == OS_TASK_PEND_ON_MULTI) {
1888 OS_Post1(p_obj, /* Indicate which object was posted to */
1889 p_tcb,
1890 p_void,
1891 msg_size,
1892 ts);
1893 } else {
1894 #if (OS_MSG_EN > 0u)
1895 p_tcb->MsgPtr = p_void; /* Deposit message in OS_TCB of task waiting */
1896 p_tcb->MsgSize = msg_size; /* ... assuming posting a message */
1897 #endif
1898 p_tcb->TS = ts;
1899 }
1900 OS_TickListRemove(p_tcb); /* Cancel any timeout */
1901 if (p_obj != (OS_PEND_OBJ *)0) {
1902 OS_PendListRemove(p_tcb); /* Remove task from wait list(s) */
1903 #if OS_CFG_DBG_EN > 0u
1904 OS_PendDbgNameRemove(p_obj,
1905 p_tcb);
1906 #endif
1907 }
1908 p_tcb->TaskState = OS_TASK_STATE_SUSPENDED;
1909 p_tcb->PendStatus = OS_STATUS_PEND_OK; /* Clear pend status */
1910 p_tcb->PendOn = OS_TASK_PEND_ON_NOTHING; /* Indicate no longer pending */
1911 break;
1912
1913 default:
1914 break;
1915 }
1916 }
1917
1918 /*$PAGE*/
1919 /*
1920 ************************************************************************************************************************
1921 * POST TO A TASK PENDING ON MULTIPLE OBJECTS
1922 *
1923 * Description: This function is called when a task is pending on multiple objects and the object has been posted to.
1924 * This function needs to indicate to the caller which object was posted to by placing the address of the
1925 * object in the OS_PEND_DATA table corresponding to the posted object.
1926 *
1927 * For example, if the task pends on six (6) objects, the address of those 6 objects are placed in the
1928 * .PendObjPtr field of the OS_PEND_DATA table as shown below. Note that the .PendDataTblEntries would be
1929 * set to six (6) in this case. As shown, when the pend call returns because a task or an ISR posted to
1930 * 'Obj C' then, only the one entry contains the filled in data and the other entries contains NULL pointers
1931 * and zero data.
1932 *
1933 * You should note that the NULL pointers are zero data values are actually filled in by the pend call.
1934 *
1935 *
1936 * .PendObjPtr .RdyObjPtr .RdyMsgPtr .RdyMsgSize .RdyTS
1937 * +--------------+--------------+--------------+--------------+--------------+
1938 * p_tcb->PendDataTblPtr -> | Obj A | 0 | 0 | 0 | 0 |
1939 * +--------------+--------------+--------------+--------------+--------------+
1940 * | Obj B | 0 | 0 | 0 | 0 |
1941 * +--------------+--------------+--------------+--------------+--------------+
1942 * | Obj C | Obj C | Msg Ptr | Msg Size | TS |
1943 * +--------------+--------------+--------------+--------------+--------------+
1944 * | Obj D | 0 | 0 | 0 | 0 |
1945 * +--------------+--------------+--------------+--------------+--------------+
1946 * | Obj E | 0 | 0 | 0 | 0 |
1947 * +--------------+--------------+--------------+--------------+--------------+
1948 * | Obj F | 0 | 0 | 0 | 0 |
1949 * +--------------+--------------+--------------+--------------+--------------+
1950 *
1951 *
1952 * Arguments : p_obj is a pointer to the object being posted to
1953 * -----
1954 *
1955 * p_tcb is the OS_TCB of the task receiving the signal or the message
1956 * -----
1957 *
1958 * p_void is the actual message (assuming posting to a message queue). A NULL pointer otherwise.
1959 *
1960 * msg_size is the size of the message sent (if posted to a message queue)
1961 *
1962 * ts is the time stamp of when the post occurred
1963 *
1964 * Returns : none
1965 *
1966 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
1967 ************************************************************************************************************************
1968 */
1969
1970 void OS_Post1 (OS_PEND_OBJ *p_obj,
1971 OS_TCB *p_tcb,
1972 void *p_void,
1973 OS_MSG_SIZE msg_size,
1974 CPU_TS ts)
1975 {
1976 OS_OBJ_QTY n_pend_list; /* Number of pend lists */
1977 OS_PEND_DATA *p_pend_data;
1978
1979
1980
1981 p_pend_data = p_tcb->PendDataTblPtr; /* Point to the first OS_PEND_DATA to remove */
1982 n_pend_list = p_tcb->PendDataTblEntries; /* Get number of entries in the table */
1983
1984 while (n_pend_list > (OS_OBJ_QTY)0) { /* Mark posted object in OS_PEND_DATA table */
1985 if (p_obj == p_pend_data->PendObjPtr) { /* Did we find the object posted to? */
1986 p_pend_data->RdyObjPtr = p_obj; /* Yes, indicate the object in the .RdyObjPtr */
1987 p_pend_data->RdyMsgPtr = p_void; /* store the message posted */
1988 p_pend_data->RdyMsgSize = msg_size; /* store the size of the message posted */
1989 p_pend_data->RdyTS = ts; /* save the timestamp of the post */
1990 break;
1991 }
1992 p_pend_data++;
1993 n_pend_list--;
1994 }
1995 }
1996
1997 /*$PAGE*/
1998 /*
1999 ************************************************************************************************************************
2000 * INITIALIZATION
2001 * READY LIST INITIALIZATION
2002 *
2003 * Description: This function is called by OSInit() to initialize the ready list. The ready list contains a list of all
2004 * the tasks that are ready to run. The list is actually an array of OS_RDY_LIST. An OS_RDY_LIST contains
2005 * three fields. The number of OS_TCBs in the list (i.e. .NbrEntries), a pointer to the first OS_TCB in the
2006 * OS_RDY_LIST (i.e. .HeadPtr) and a pointer to the last OS_TCB in the OS_RDY_LIST (i.e. .TailPtr).
2007 *
2008 * OS_TCBs are doubly linked in the OS_RDY_LIST and each OS_TCB points pack to the OS_RDY_LIST it belongs
2009 * to.
2010 *
2011 * 'OS_RDY_LIST OSRdyTbl[OS_CFG_PRIO_MAX]' looks like this once initialized:
2012 *
2013 * +---------------+--------------+
2014 * | | TailPtr |-----> 0
2015 * [0] | NbrEntries=0 +--------------+
2016 * | | HeadPtr |-----> 0
2017 * +---------------+--------------+
2018 * | | TailPtr |-----> 0
2019 * [1] | NbrEntries=0 +--------------+
2020 * | | HeadPtr |-----> 0
2021 * +---------------+--------------+
2022 * : :
2023 * : :
2024 * : :
2025 * +---------------+--------------+
2026 * | | TailPtr |-----> 0
2027 * [OS_CFG_PRIO_MAX-1] | NbrEntries=0 +--------------+
2028 * | | HeadPtr |-----> 0
2029 * +---------------+--------------+
2030 *
2031 *
2032 * Arguments : none
2033 *
2034 * Returns : none
2035 *
2036 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
2037 ************************************************************************************************************************
2038 */
2039
2040 void OS_RdyListInit (void)
2041 {
2042 OS_PRIO i;
2043 OS_RDY_LIST *p_rdy_list;
2044
2045
2046
2047 for (i = 0u; i < OS_CFG_PRIO_MAX; i++) { /* Initialize the array of OS_RDY_LIST at each priority */
2048 p_rdy_list = &OSRdyList[i];
2049 p_rdy_list->NbrEntries = (OS_OBJ_QTY)0;
2050 p_rdy_list->HeadPtr = (OS_TCB *)0;
2051 p_rdy_list->TailPtr = (OS_TCB *)0;
2052 }
2053 }
2054
2055 /*$PAGE*/
2056 /*
2057 ************************************************************************************************************************
2058 * INSERT TCB IN THE READY LIST
2059 *
2060 * Description: This function is called to insert a TCB in the ready list.
2061 *
2062 * The TCB is inserted at the tail of the list if the priority of the TCB is the same as the priority of the
2063 * current task. The TCB is inserted at the head of the list if not.
2064 *
2065 * Arguments : p_tcb is a pointer to the TCB to insert into the ready list
2066 * -----
2067 *
2068 * Returns : none
2069 *
2070 * Note(s) : This function is INTERNAL to uC/OS-III and your application should not call it.
2071 ************************************************************************************************************************
2072 */
2073
2074 void OS_RdyListInsert (OS_TCB *p_tcb)
2075 {
2076 OS_PrioInsert(p_tcb->Prio);
2077 if (p_tcb->Prio == OSPrioCur) { /* Are we readying a task at the same prio? */
2078 OS_RdyListInsertTail(p_tcb); /* Yes, insert readied task at the end of the list */
2079 } else {
2080 OS_RdyListInsertHead(p_tcb); /* No, insert readied task at the beginning of the list */
2081 }
2082 }
2083
2084
2085 /*
2086 ************************************************************************************************************************
2087 * INSERT TCB AT THE BEGINNING OF A LIST
2088 *
2089 * Description: This function is called to place an OS_TCB at the beginning of a linked list as follows:
2090 *
2091 * CASE 0: Insert in an empty list.
2092 *
2093 * OS_RDY_LIST
2094 * +--------------+
2095 * | TailPtr |-> 0
2096 * +--------------+
2097 * | HeadPtr |-> 0
2098 * +--------------+
2099 * | NbrEntries=0 |
2100 * +--------------+
2101 *
2102 *
2103 *
2104 * CASE 1: Insert BEFORE the current head of list
2105 *
2106 * OS_RDY_LIST
2107 * +--------------+ OS_TCB
2108 * | TailPtr |--+---> +------------+
2109 * +--------------+ | | NextPtr |->0
2110 * | HeadPtr |--/ +------------+
2111 * +--------------+ 0<-| PrevPtr |
2112 * | NbrEntries=1 | +------------+
2113 * +--------------+ : :
2114 * : :
2115 * +------------+
2116 *
2117 *
2118 * OS_RDY_LIST
2119 * +--------------+
2120 * | TailPtr |-----------------------------------------------+
2121 * +--------------+ OS_TCB OS_TCB | OS_TCB
2122 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
2123 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
2124 * | NbrEntries=N | +------------+ +------------+ +------------+
2125 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
2126 * +------------+ +------------+ +------------+
2127 * : : : : : :
2128 * : : : : : :
2129 * +------------+ +------------+ +------------+
2130 *
2131 *
2132 * Arguments : p_tcb is the OS_TCB to insert in the list
2133 * -----
2134 *
2135 * Returns : none
2136 *
2137 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2138 ************************************************************************************************************************
2139 */
2140
2141 void OS_RdyListInsertHead (OS_TCB *p_tcb)
2142 {
2143 OS_RDY_LIST *p_rdy_list;
2144 OS_TCB *p_tcb2;
2145
2146
2147
2148 p_rdy_list = &OSRdyList[p_tcb->Prio];
2149 if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
2150 p_rdy_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
2151 p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */
2152 p_tcb->PrevPtr = (OS_TCB *)0;
2153 p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */
2154 p_rdy_list->TailPtr = p_tcb;
2155 } else { /* CASE 1: Insert BEFORE the current head of list */
2156 p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */
2157 p_tcb->NextPtr = p_rdy_list->HeadPtr; /* Adjust new OS_TCBs links */
2158 p_tcb->PrevPtr = (OS_TCB *)0;
2159 p_tcb2 = p_rdy_list->HeadPtr; /* Adjust old head of list's links */
2160 p_tcb2->PrevPtr = p_tcb;
2161 p_rdy_list->HeadPtr = p_tcb;
2162 }
2163 }
2164
2165 /*$PAGE*/
2166 /*
2167 ************************************************************************************************************************
2168 * INSERT TCB AT THE END OF A LIST
2169 *
2170 * Description: This function is called to place an OS_TCB at the end of a linked list as follows:
2171 *
2172 * CASE 0: Insert in an empty list.
2173 *
2174 * OS_RDY_LIST
2175 * +--------------+
2176 * | TailPtr |-> 0
2177 * +--------------+
2178 * | HeadPtr |-> 0
2179 * +--------------+
2180 * | NbrEntries=0 |
2181 * +--------------+
2182 *
2183 *
2184 *
2185 * CASE 1: Insert AFTER the current tail of list
2186 *
2187 * OS_RDY_LIST
2188 * +--------------+ OS_TCB
2189 * | TailPtr |--+---> +------------+
2190 * +--------------+ | | NextPtr |->0
2191 * | HeadPtr |--/ +------------+
2192 * +--------------+ 0<-| PrevPtr |
2193 * | NbrEntries=1 | +------------+
2194 * +--------------+ : :
2195 * : :
2196 * +------------+
2197 *
2198 *
2199 * OS_RDY_LIST
2200 * +--------------+
2201 * | TailPtr |-----------------------------------------------+
2202 * +--------------+ OS_TCB OS_TCB | OS_TCB
2203 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
2204 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
2205 * | NbrEntries=N | +------------+ +------------+ +------------+
2206 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
2207 * +------------+ +------------+ +------------+
2208 * : : : : : :
2209 * : : : : : :
2210 * +------------+ +------------+ +------------+
2211 *
2212 *
2213 * Arguments : p_tcb is the OS_TCB to insert in the list
2214 * -----
2215 *
2216 * Returns : none
2217 *
2218 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2219 ************************************************************************************************************************
2220 */
2221
2222 void OS_RdyListInsertTail (OS_TCB *p_tcb)
2223 {
2224 OS_RDY_LIST *p_rdy_list;
2225 OS_TCB *p_tcb2;
2226
2227
2228
2229 p_rdy_list = &OSRdyList[p_tcb->Prio];
2230 if (p_rdy_list->NbrEntries == (OS_OBJ_QTY)0) { /* CASE 0: Insert when there are no entries */
2231 p_rdy_list->NbrEntries = (OS_OBJ_QTY)1; /* This is the first entry */
2232 p_tcb->NextPtr = (OS_TCB *)0; /* No other OS_TCBs in the list */
2233 p_tcb->PrevPtr = (OS_TCB *)0;
2234 p_rdy_list->HeadPtr = p_tcb; /* Both list pointers point to this OS_TCB */
2235 p_rdy_list->TailPtr = p_tcb;
2236 } else { /* CASE 1: Insert AFTER the current tail of list */
2237 p_rdy_list->NbrEntries++; /* One more OS_TCB in the list */
2238 p_tcb->NextPtr = (OS_TCB *)0; /* Adjust new OS_TCBs links */
2239 p_tcb2 = p_rdy_list->TailPtr;
2240 p_tcb->PrevPtr = p_tcb2;
2241 p_tcb2->NextPtr = p_tcb; /* Adjust old tail of list's links */
2242 p_rdy_list->TailPtr = p_tcb;
2243 }
2244 }
2245
2246 /*$PAGE*/
2247 /*
2248 ************************************************************************************************************************
2249 * MOVE TCB AT HEAD TO TAIL
2250 *
2251 * Description: This function is called to move the current head of a list to the tail of the list.
2252 *
2253 *
2254 * CASE 0: TCB list is empty, nothing to do.
2255 *
2256 * CASE 1: Only 1 OS_TCB in the list, nothing to do.
2257 *
2258 * CASE 2: Only 2 OS_TCBs in the list.
2259 *
2260 * OS_RDY_LIST
2261 * +--------------+
2262 * | TailPtr |--------------------------+
2263 * +--------------+ OS_TCB | OS_TCB
2264 * | HeadPtr |------> +------------+ +-> +------------+
2265 * +--------------+ | NextPtr |------> | NextPtr |->0
2266 * | NbrEntries=2 | +------------+ +------------+
2267 * +--------------+ 0<-| PrevPtr | <------| PrevPtr |
2268 * +------------+ +------------+
2269 * : : : :
2270 * : : : :
2271 * +------------+ +------------+
2272 *
2273 *
2274 * CASE N: More than 2 OS_TCBs in the list.
2275 *
2276 * OS_RDY_LIST
2277 * +--------------+
2278 * | TailPtr |-----------------------------------------------+
2279 * +--------------+ OS_TCB OS_TCB | OS_TCB
2280 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
2281 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
2282 * | NbrEntries=N | +------------+ +------------+ +------------+
2283 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
2284 * +------------+ +------------+ +------------+
2285 * : : : : : :
2286 * : : : : : :
2287 * +------------+ +------------+ +------------+
2288 *
2289 *
2290 * Arguments : p_list is a pointer to the OS_RDY_LIST where the OS_TCB will be inserted
2291 * ------
2292 *
2293 * Returns : none
2294 *
2295 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2296 ************************************************************************************************************************
2297 */
2298
2299 void OS_RdyListMoveHeadToTail (OS_RDY_LIST *p_rdy_list)
2300 {
2301 OS_TCB *p_tcb1;
2302 OS_TCB *p_tcb2;
2303 OS_TCB *p_tcb3;
2304
2305
2306
2307 switch (p_rdy_list->NbrEntries) {
2308 case 0:
2309 case 1:
2310 break;
2311
2312 case 2: /* SWAP the TCBs */
2313 p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */
2314 p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */
2315 p_tcb1->PrevPtr = p_tcb2;
2316 p_tcb1->NextPtr = (OS_TCB *)0;
2317 p_tcb2->PrevPtr = (OS_TCB *)0;
2318 p_tcb2->NextPtr = p_tcb1;
2319 p_rdy_list->HeadPtr = p_tcb2;
2320 p_rdy_list->TailPtr = p_tcb1;
2321 break;
2322
2323 default: /* Move only if there are more than 2 OS_TCBs in the list */
2324 p_tcb1 = p_rdy_list->HeadPtr; /* Point to current head */
2325 p_tcb2 = p_rdy_list->TailPtr; /* Point to current tail */
2326 p_tcb3 = p_tcb1->NextPtr; /* Point to new list head */
2327 p_tcb3->PrevPtr = (OS_TCB *)0; /* Adjust back link of new list head */
2328 p_tcb1->NextPtr = (OS_TCB *)0; /* Adjust forward link of new list tail */
2329 p_tcb1->PrevPtr = p_tcb2; /* Adjust back link of new list tail */
2330 p_tcb2->NextPtr = p_tcb1; /* Adjust forward link of old list tail */
2331 p_rdy_list->HeadPtr = p_tcb3; /* Adjust new list head and tail pointers */
2332 p_rdy_list->TailPtr = p_tcb1;
2333 break;
2334 }
2335 }
2336
2337 /*$PAGE*/
2338 /*
2339 ************************************************************************************************************************
2340 * REMOVE TCB FROM LIST KNOWING ONLY WHICH OS_TCB TO REMOVE
2341 *
2342 * Description: This function is called to remove an OS_TCB from an OS_RDY_LIST knowing the address of the OS_TCB to
2343 * remove.
2344 *
2345 *
2346 * CASE 0: TCB list is empty, nothing to do.
2347 *
2348 * CASE 1: Only 1 OS_TCBs in the list.
2349 *
2350 * OS_RDY_LIST
2351 * +--------------+ OS_TCB
2352 * | TailPtr |--+---> +------------+
2353 * +--------------+ | | NextPtr |->0
2354 * | HeadPtr |--/ +------------+
2355 * +--------------+ 0<-| PrevPtr |
2356 * | NbrEntries=1 | +------------+
2357 * +--------------+ : :
2358 * : :
2359 * +------------+
2360 *
2361 * CASE N: Two or more OS_TCBs in the list.
2362 *
2363 * OS_RDY_LIST
2364 * +--------------+
2365 * | TailPtr |-----------------------------------------------+
2366 * +--------------+ OS_TCB OS_TCB | OS_TCB
2367 * | HeadPtr |------> +------------+ +------------+ +-> +------------+
2368 * +--------------+ | NextPtr |------>| NextPtr | ...... | NextPtr |->0
2369 * | NbrEntries=N | +------------+ +------------+ +------------+
2370 * +--------------+ 0<-| PrevPtr |<------| PrevPtr | ...... | PrevPtr |
2371 * +------------+ +------------+ +------------+
2372 * : : : : : :
2373 * : : : : : :
2374 * +------------+ +------------+ +------------+
2375 *
2376 *
2377 * Arguments : p_tcb is a pointer to the OS_TCB to remove
2378 * -----
2379 *
2380 * Returns : A pointer to the OS_RDY_LIST where the OS_TCB was
2381 *
2382 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2383 ************************************************************************************************************************
2384 */
2385
2386 void OS_RdyListRemove (OS_TCB *p_tcb)
2387 {
2388 OS_RDY_LIST *p_rdy_list;
2389 OS_TCB *p_tcb1;
2390 OS_TCB *p_tcb2;
2391
2392
2393
2394 p_rdy_list = &OSRdyList[p_tcb->Prio];
2395 p_tcb1 = p_tcb->PrevPtr; /* Point to next and previous OS_TCB in the list */
2396 p_tcb2 = p_tcb->NextPtr;
2397 if (p_tcb1 == (OS_TCB *)0) { /* Was the OS_TCB to remove was at the head? */
2398 if (p_tcb2 == (OS_TCB *)0) { /* Yes, was it the only OS_TCB? */
2399 p_rdy_list->NbrEntries = (OS_OBJ_QTY)0; /* Yes, no more entries */
2400 p_rdy_list->HeadPtr = (OS_TCB *)0;
2401 p_rdy_list->TailPtr = (OS_TCB *)0;
2402 OS_PrioRemove(p_tcb->Prio);
2403 } else {
2404 p_rdy_list->NbrEntries--; /* No, one less entry */
2405 p_tcb2->PrevPtr = (OS_TCB *)0; /* adjust back link of new list head */
2406 p_rdy_list->HeadPtr = p_tcb2; /* adjust OS_RDY_LIST's new head */
2407 }
2408 } else {
2409 p_rdy_list->NbrEntries--; /* No, one less entry */
2410 p_tcb1->NextPtr = p_tcb2;
2411 if (p_tcb2 == (OS_TCB *)0) {
2412 p_rdy_list->TailPtr = p_tcb1; /* Removing the TCB at the tail, adj the tail ptr */
2413 } else {
2414 p_tcb2->PrevPtr = p_tcb1;
2415 }
2416 }
2417 p_tcb->PrevPtr = (OS_TCB *)0;
2418 p_tcb->NextPtr = (OS_TCB *)0;
2419 }
2420
2421 /*$PAGE*/
2422 /*
2423 ************************************************************************************************************************
2424 * SCHEDULE THE ISR HANDLER TASK
2425 *
2426 * Description: This function is called by other uC/OS-III services to schedule task at priority 0 which is always the
2427 * ISR handler task.
2428 *
2429 * Arguments : none
2430 *
2431 * Returns : none
2432 *
2433 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2434 ************************************************************************************************************************
2435 */
2436
2437 #if OS_CFG_ISR_POST_DEFERRED_EN > 0u
2438 void OS_Sched0 (void)
2439 {
2440 CPU_SR_ALLOC();
2441
2442
2443
2444 CPU_INT_DIS();
2445 OSPrioHighRdy = (OS_PRIO)0; /* Force the priority to 0 */
2446 OSTCBHighRdyPtr = &OSIntQTaskTCB; /* Always schedule the ISR handler task */
2447 #if OS_CFG_TASK_PROFILE_EN > 0u
2448 OSTCBHighRdyPtr->CtxSwCtr++; /* Inc. # of context switches to this task */
2449 #endif
2450 OSTaskCtxSwCtr++; /* Increment context switch counter */
2451 OS_TASK_SW(); /* Perform a task level context switch */
2452 CPU_INT_EN();
2453 }
2454 #endif
2455
2456 /*$PAGE*/
2457 /*
2458 ************************************************************************************************************************
2459 * SCHEDULER LOCK TIME MEASUREMENT
2460 *
2461 * Description: These functions are used to measure the peak amount of time that the scheduler is locked
2462 *
2463 * Arguments : none
2464 *
2465 * Returns : none
2466 *
2467 * Note(s) : 1) The are internal functions to uC/OS-III and MUST not be called by your application code.
2468 *
2469 * 2) It's assumed that these functions are called when interrupts are disabled.
2470 *
2471 * 3) We are reading the CPU_TS_TmrRd() directly even if this is a 16-bit timer. The reason is that we
2472 * don't expect to have the scheduler locked for 65536 counts even at the rate the TS timer is updated.
2473 * In other words, locking the scheduler for longer than 65536 count would not be a good thing for a
2474 * real-time system.
2475 ************************************************************************************************************************
2476 */
2477
2478 #if OS_CFG_SCHED_LOCK_TIME_MEAS_EN > 0u
2479 void OS_SchedLockTimeMeasStart (void)
2480 {
2481 if (OSSchedLockNestingCtr == 1u) {
2482 OSSchedLockTimeBegin = CPU_TS_TmrRd();
2483 }
2484 }
2485
2486
2487
2488
2489 void OS_SchedLockTimeMeasStop (void)
2490 {
2491 CPU_TS_TMR delta;
2492
2493
2494 if (OSSchedLockNestingCtr == (OS_NESTING_CTR)0) { /* Make sure we fully un-nested scheduler lock */
2495 delta = CPU_TS_TmrRd() /* Compute the delta time between begin and end */
2496 - OSSchedLockTimeBegin;
2497 if (OSSchedLockTimeMax < delta) { /* Detect peak value */
2498 OSSchedLockTimeMax = delta;
2499 }
2500 if (OSSchedLockTimeMaxCur < delta) { /* Detect peak value (for resettable value) */
2501 OSSchedLockTimeMaxCur = delta;
2502 }
2503 }
2504 }
2505 #endif
2506
2507 /*$PAGE*/
2508 /*
2509 ************************************************************************************************************************
2510 * RUN ROUND-ROBIN SCHEDULING ALGORITHM
2511 *
2512 * Description: This function is called on every tick to determine if a new task at the same priority needs to execute.
2513 *
2514 *
2515 * Arguments : p_rdy_list is a pointer to the OS_RDY_LIST entry of the ready list at the current priority
2516 * ----------
2517 *
2518 * Returns : none
2519 *
2520 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2521 ************************************************************************************************************************
2522 */
2523
2524 #if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
2525 void OS_SchedRoundRobin (OS_RDY_LIST *p_rdy_list)
2526 {
2527 OS_TCB *p_tcb;
2528 CPU_SR_ALLOC();
2529
2530
2531
2532 if (OSSchedRoundRobinEn != DEF_TRUE) { /* Make sure round-robin has been enabled */
2533 return;
2534 }
2535
2536 CPU_CRITICAL_ENTER();
2537 p_tcb = p_rdy_list->HeadPtr; /* Decrement time quanta counter */
2538
2539 if (p_tcb == (OS_TCB *)0) {
2540 CPU_CRITICAL_EXIT();
2541 return;
2542 }
2543
2544 if (p_tcb == &OSIdleTaskTCB) {
2545 CPU_CRITICAL_EXIT();
2546 return;
2547 }
2548
2549 if (p_tcb->TimeQuantaCtr > (OS_TICK)0) {
2550 p_tcb->TimeQuantaCtr--;
2551 }
2552
2553 if (p_tcb->TimeQuantaCtr > (OS_TICK)0) { /* Task not done with its time quanta */
2554 CPU_CRITICAL_EXIT();
2555 return;
2556 }
2557
2558 if (p_rdy_list->NbrEntries < (OS_OBJ_QTY)2) { /* See if it's time to time slice current task */
2559 CPU_CRITICAL_EXIT(); /* ... only if multiple tasks at same priority */
2560 return;
2561 }
2562
2563 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { /* Can't round-robin if the scheduler is locked */
2564 CPU_CRITICAL_EXIT();
2565 return;
2566 }
2567
2568 OS_RdyListMoveHeadToTail(p_rdy_list); /* Move current OS_TCB to the end of the list */
2569 p_tcb = p_rdy_list->HeadPtr; /* Point to new OS_TCB at head of the list */
2570 if (p_tcb->TimeQuanta == (OS_TICK)0) { /* See if we need to use the default time slice */
2571 p_tcb->TimeQuantaCtr = OSSchedRoundRobinDfltTimeQuanta;
2572 } else {
2573 p_tcb->TimeQuantaCtr = p_tcb->TimeQuanta; /* Load time slice counter with new time */
2574 }
2575 CPU_CRITICAL_EXIT();
2576 }
2577 #endif
2578
2579 /*$PAGE*/
2580 /*
2581 ************************************************************************************************************************
2582 * BLOCK A TASK
2583 *
2584 * Description: This function is called to remove a task from the ready list and also insert it in the timer tick list if
2585 * the specified timeout is non-zero.
2586 *
2587 * Arguments : p_tcb is a pointer to the OS_TCB of the task block
2588 * -----
2589 *
2590 * timeout is the desired timeout
2591 *
2592 * Returns : none
2593 *
2594 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2595 ************************************************************************************************************************
2596 */
2597
2598 void OS_TaskBlock (OS_TCB *p_tcb,
2599 OS_TICK timeout)
2600 {
2601 OS_ERR err;
2602
2603
2604 if (timeout > (OS_TICK)0) { /* Add task to tick list if timeout non zero */
2605 OS_TickListInsert(p_tcb,
2606 timeout,
2607 OS_OPT_TIME_TIMEOUT,
2608 &err);
2609 if (err == OS_ERR_NONE) {
2610 p_tcb->TaskState = OS_TASK_STATE_PEND_TIMEOUT;
2611 } else {
2612 p_tcb->TaskState = OS_TASK_STATE_PEND;
2613 }
2614 } else {
2615 p_tcb->TaskState = OS_TASK_STATE_PEND;
2616 }
2617 OS_RdyListRemove(p_tcb);
2618 }
2619
2620 /*$PAGE*/
2621 /*
2622 ************************************************************************************************************************
2623 * READY A TASK
2624 *
2625 * Description: This function is called to make a task ready-to-run.
2626 *
2627 * Arguments : p_tcb is a pointer to the OS_TCB of the task to make ready-to-run
2628 * -----
2629 *
2630 * Returns : none
2631 *
2632 * Note(s) : 1) This function is INTERNAL to uC/OS-III and your application MUST NOT call it.
2633 ************************************************************************************************************************
2634 */
2635
2636 void OS_TaskRdy (OS_TCB *p_tcb)
2637 {
2638 OS_TickListRemove(p_tcb); /* Remove from tick list */
2639 if ((p_tcb->TaskState & OS_TASK_STATE_BIT_SUSPENDED) == (OS_STATE)0) {
2640 OS_RdyListInsert(p_tcb); /* Insert the task in the ready list */
2641 }
2642 }