训练营PLSR题目
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

2635 строки
122 KiB

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