os_core.c 122 KB

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