windLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:41k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* windLib.c - internal VxWorks kernel library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02a,22may02,jgn  updated tick counter to be 64 bit - SPR #70255
  8. 01z,20mar02,bwa  windPendQRemove() now moves task out of the tick Q. (SPR
  9.                  #74673).
  10. 01y,18dec00,pes  Correct compiler warnings
  11. 01x,29oct97,cth  removed references to scrPad for WV2.0
  12. 01w,03dec96,dbt  Added intLock and intUnlock in windWdStart to protect the
  13.                  decrement of the defer start counter (fixed spr #7070).
  14. 01v,24jun96,sbs  made windview instrumentation conditionally compiled
  15. 01t,31jan95,tmk  added OBJ_VERIFY clause to windSemDelete()
  16.    +rrr
  17. 01s,27jan95,ms   windDestroy flushes the right saftey queue now
  18.    +rrr
  19. 01u,02feb94,smb  windPendQFlush no longer causes scratch-pad overflow SPR #2981
  20. 01t,24jan94,smb  added tid to EVENT_WINDTICKTIMEOUT
  21. 01s,10dec93,smb  added instrumentation
  22. 01r,13nov92,dnw  added include of smObjLib.h
  23. 01q,19jul92,pme  Added windReadyQPut, made windDelete and windPendQRemove
  24.                  return STATUS, made windTickAnnounce set task return
  25.                  value acording to possible shared memory objects errors. 
  26. 01p,04jul92,jcf  private headers.
  27. 01n,05jun92,ajm  intCnt is now fixed, see excALib.s
  28. 01o,26may92,rrr  the tree shuffle
  29. 01n,15oct91,ajm  intCnt change for mips, this must be FIXED correctly soon
  30. 01m,04oct91,rrr  passed through the ansification filter
  31.                   -changed functions to ansi style
  32.   -changed includes to have absolute path from h/
  33.   -changed VOID to void
  34.   -changed copyright notice
  35. 01l,28sep90,jcf  documentation.
  36. 01k,04sep90,jcf  documentation.
  37. 01j,03aug90,jcf  fixed bug in watchdog routine calling wdStart.
  38. 01i,15jul90,jcf  fixed bug in watchdog handling which allowed work q to overflow
  39. 01h,03jul90,jcf  added windPendQTerminate().
  40.  added timer queue rollover algorithm.
  41. 01g,26jun90,jcf  simplified priority inheritance algorithm.
  42.  changed windSem*() to windPendQ*().
  43. 01f,28aug89,jcf  modified to support version 2.0 of wind.
  44. 01e,09aug89,gae  SPARCintized windDummyCreate.
  45. 01d,19nov88,jcf  validated task id before operations undertaken.
  46.    changed lstFirst, lstPrevious, lstNext to macros.
  47. 01c,23aug88,gae  documentation.
  48. 01b,12aug88,jcf  cleanup.
  49. 01a,12mar88,jcf  written.
  50. */
  51. /*
  52. DESCRIPTION
  53. The VxWorks kernel provides tasking control services to an application.  The
  54. libraries kernelLib, taskLib, semLib, tickLib, and wdLib comprise the kernel
  55. functionality.  This library is internal to the VxWorks kernel and contains
  56. no user callable routines.
  57. INTERNAL
  58. This is a description of the architecture of Wind version 2.0.  The information
  59. here applies to the following libraries: kernelLib, taskLib, semLib, tickLib,
  60. wdLib, schedLib, workQLib, windLib, windALib, semALib, and workQALib.
  61. STATE MACHINE
  62. The kernel is a small state machine.  Each task contains state information in
  63. the status field.  The possible states in wind 2.0 are:
  64.     WIND_READY, Ready for execution, in readyQHead.
  65.     WIND_DELAY, Sleeping, in tickQHead.
  66.     WIND_PEND, Blocked, in resource pendQHead.
  67.     WIND_PEND | WIND_DELAY, Blocked w/timeout in pendQHead/tickQHead
  68.     WIND_SUSPEND, Suspended, in no queue.
  69.     WIND_DELAY | WIND_SUSPEND, Suspended sleeping, in tickQHead
  70.     WIND_PEND | WIND_SUSPEND, Suspended blocked, in pendQHead.
  71.     WIND_PEND|WIND_DELAY|WIND_SUSPEND,  Susp blocked w/tout, pendQHead/tickQHead
  72.     WIND_DEAD Extinct, gone, deceased, an Ex-Task.
  73. We provide a rich set of routines to move routines from state to another in
  74. the aforementioned libraries.  The actual work of changing a task's state and
  75. shuffling it into the appropriate queue is done within this library as a
  76. lower level call to the user routines elsewhere.  For instance taskSuspend()
  77. calls windSuspend().  This decomposition is not purely aesthetic, the separation
  78. is necessary as part of the mutual exclusion method used by the kernel.
  79. MUTUAL EXCLUSION
  80. By the time we arrive in the routines located here, higher level routines have
  81. obtained mutual exclusion to all kernel queues by entering kernel state.  The
  82. routines located here have free reign over any kernel data structure.  Kernel
  83. state is a powerful means of mutual exclusion, unfortunately preemption is
  84. disabled for the duration of kernel state.  High preemptive latency undermines
  85. the reactive latency of a real time system, so it is crucial to use this
  86. mechanism sparingly.  Indeed the basic design philosophy of the kernel is to
  87. keep it as minimal as possible, while still capable of supporting higher level
  88. facilities.
  89. Kernel routines fit the template illuminated by taskResume():
  90.     if (kernelState) /@ defer work if in kernel @/
  91. {
  92. workQAdd1 (windResume, tid); /@ add work to kernel work q @/
  93. return (OK);
  94. }
  95.     kernelState = TRUE; /@ KERNEL ENTER @/
  96.     windResume ((WIND_TCB *) tid); /@ resume task @/
  97.     windExit (); /@ KERNEL EXIT @/
  98. To enter kernel state one simply sets the global variable kernelState to TRUE.
  99. From that point, all kernel data structures are protected from contention.
  100. When finished with the kernel operation, kernel state is left via windExit()
  101. which sets kernelState back to FALSE.  Lets consider who, in fact, contends
  102. for the internal data structures.  An interrupt service routine is the only
  103. possible initiator of additional kernel work.  That is, once a system enters
  104. kernel state the only way an application could request more kernel work is
  105. from an ISR.
  106. WORK QUEUE
  107. Notice in the above template that kernelState is always checked before it
  108. is set.  This is the backbone of the mutual exclusion.  The kernel uses a
  109. technique of work deferral as a means of mutual exclusion.  When kernelState
  110. is TRUE, the function of interest is not invoked directly, but rather
  111. the work is deferred by enqueueing the job to the kernel work queue.
  112. The kernel work queue is emptied by windExit(), (or intExit in the case of an
  113. ISR entering the kernel first), before loading the context of the appropriate
  114. task.  At the very end of kernel state we lock interrupts, check the work
  115. queue is still empty, and enter a selected task's context.  The deferral of
  116. kernel work is necessary for all kernel routines which are ISR callable.
  117. SPECIAL PROBLEMS
  118. Some facilities are quite elaborate and require special discussions.  Most are
  119. areas still under research or involve some form of tricky code.
  120. WATCHDOGS
  121. Watchdogs present two ugly problems.  The first problem is the routine wdStart()
  122. takes four parameters: the watchdog id, the timeout, the routine, and a routine
  123. parameter.  A work queue job only has room for 3 parameters.  So if an ISR
  124. calls wdStart() after interrupting the kernel, we cannot simply defer the
  125. work to the work queue.  The solution is to write windWdStart to take only
  126. two parameters, the watchdog id, and a timeout.  The routine and parmeter
  127. are stored in the watchdog itself.  We're not out of the woods yet, because
  128. what if five different ISRs which interrupt the kernel perform a wdStart on the
  129. same watchdog?  Where do we keep all the parameters?  The answer is to simply
  130. clobber the existing routine and parameter with the new routine and new
  131. parameter and bump a defer count variable within the watchdog.  Every time
  132. windWdStart() is called as kernel work (or otherwise), the defer count is
  133. decremented.  If the resulting defer count is zero, the watchdog is sorted to
  134. the appropriate timeout in the tick queue.  We know that the timeout
  135. corresponds to the watchdog routine and parameter resident in the watchdog
  136. structure because the defer count has been decremented as many times as it
  137. was incremented.
  138. The second problem is even uglier.  Watchdogs routines may be any arbitrary
  139. routine including kernel routines.  The problem is watchdog routines are
  140. now called from deep within the kernel, in kernel state.  All kernel routines
  141. made from a watchdog will be deferred to the work queue.  The kicker is that
  142. there is no limit to the number of watchdogs that can go off in the same tick.
  143. If all kernel work is deferred by a limitless number of watchdog routines
  144. expiring at the same tick, there is a chance that we will overflow the kernel
  145. work queue.  The work queue is implemented as circular queue with a capacity
  146. of 64 jobs.  The solution to this problem is to empty the work queue after
  147. each watchdog routine is called.  We assume that a watchdog routine will never
  148. make more than 64 kernel calls.
  149. Watchdogs are being rethought.  They were not initially considered as part
  150. of the kernel, but to make them utilize the tick queue, they got dragged in.
  151. As is evident from the problems outlined above, its not a marriage made in
  152. heaven.  They are serviceable, but a future version of VxWorks will probably
  153. elect to demote watchdog routines to execute at task level within the context
  154. of a dedicated alarm task.
  155. PRIORITY INHERITANCE
  156. Priority inversion arises when a higher-priority task is forced to wait an
  157. indefinite period of time for the completion of a lower-priority task.
  158. Consider the following scenario: T1, T2, and T3 are tasks of high, medium,
  159. and low priority, respectively.  T3 has acquired some resource by taking
  160. its associated semaphore.  When T1 preempts T3 and contends for the
  161. resource by taking the same semaphore, it becomes blocked.  If we could be
  162. assured that T1 would be blocked no longer than the time it normally takes
  163. T3 to finish with the resource, the situation would not be particularly
  164. problematic.  After all the resource is non-preemptible.  However, the
  165. low-priority task is vulnerable to preemption by medium-priority tasks; a
  166. preempting task, T2, will inhibit T3 from relinquishing the resource.  This
  167. condition could persist, blocking T1 for an indefinite period of time.
  168. A priority inheritance protocal solves the problem of priority inversion by
  169. elevating the priority of T3 to the priority of T1 during the time T1 is
  170. blocked on T3.  This protects T3, and indirectly T1, from preemption by
  171. T2.  Stated more generally, the priority inheritance protocol assures that
  172. a task which owns a resource will execute at the priority of the highest
  173. priority task blocked on that resource.  When execution is complete, the
  174. task gives up the resource and returns to its normal, or standard,
  175. priority.  Hence, the "inheriting" task is protected from preemption by any
  176. intermediate-priority tasks.
  177. Special circumstances apply to nested priority inheritance.  When a task
  178. owns multiple resources guarded from priority inversion, the task's priority
  179. will `ratchet up' as higher priority tasks contend for the resources.  For
  180. efficiency and simplicity of implementation, task priorities are only allowed
  181. to be lowered when a task owns no resources guarded from priority inversion.
  182. This rule is useful for situations where a high priority task contends for
  183. an owned resource, the priority is inheritted by the owner, but then the high
  184. priority task is deleted.  Strictly speaking, it would be fair game to lower
  185. the resource owner back to its original priority, but the implemenation is
  186. a collosal waste of time and space.  The small price to pay is that tasks
  187. may inherit a priority for a little longer than is actually necessary but I
  188. won't tell anyone if you won't.
  189. DELETION PROBLEM
  190. The deletion problem has two prongs.  The first is that a resource
  191. may be deleted right ought from under a task.  Nothing protects a task
  192. from a semaphore, for example, from being deleted by another task.  We expect
  193. that applications will discipline object deletion to take place safely.  In
  194. the case of a semaphore, for example, the semaphore should be taken by the
  195. deleter before deletion.  Also note, that the actual invalidation of an
  196. object must be done with mutual exclusion.  Objects which may be utilized
  197. from interrupt level must, therefore, protect the object invalidation with
  198. interrupt locks.
  199. Object reference counts were considered as an alternative, the difficulty
  200. lies in the fact that objects are shared in VxWorks without prior consent
  201. from the operating system.  Some OS require tasks to bind to an object by
  202. name before gaining the capability of access.  Object binding does not fit
  203. with current thinking on the matter, but as we explore
  204. distributed/multiprocessor extensions to VxWorks, object id binding may
  205. resurface.
  206. The second prong of the deletion problem is harder.  It is possible that
  207. a task may be deleted while engaged in some operation on some resource.  This
  208. could leave the resource in an unusable, unavailable state.  Tasks are a
  209. special class of object, an active object which engages passive objects.  The
  210. deletion of an active object must account for the passive objects currently
  211. engaged.  We solve this problem in the same way we approach kernel work
  212. deferral.  The deletion of a task is deferred until the task is safe to delete.
  213. A deleter will block while a task is protected from deletion, otherwise a
  214. deleter might get the false impression that the task deleted is acutually gone.
  215. Applications must assist the kernel in determining when a task should be
  216. protected from deletion.  The routine taskSafe() and taskUnsafe() are the
  217. basic operations controlling task deletion protection.  For convenience, a
  218. mutual exclusion semaphore type is available which has an implicit taskSafe()
  219. call on a semTake(), and an implicit taskUnsafe() call on semGive().  Resource
  220. deletion protection by use of mutual exclusion semaphores is strong step
  221. towards making VxWorks truly capable of dynamic object deletion.
  222. FILE STRUCTURE
  223.                                      ---------
  224.                                      |semBLib|
  225.              |semMLib|
  226.                                      |semCLib|
  227.                 U  S  E  R           |semOLib|  I  N  T  E  R  F  A  C  E
  228.    ----------- ----------- --------- -.-.-.-.- ------- ------------ ---------
  229.    |kernelLib| |<msgQLib>| |taskLib| |semLib | |wdLib| |<eventLib>| |tickLib|
  230.    ----------- ----------- --------- -.-.-.-.- ------- ------------ ---------
  231.         |           |          |     |semALib|    |         |           |
  232.         |           |          |     ---------    |         |           |
  233.         |           |          |         |        |         |           |
  234.                                   ---------    /         /           /
  235.          ==========================> |windLib| <========================
  236.          |           |          |    ---------    |         |          |
  237.          |           |          |                 |         |          |
  238.          |           |          |                 |         |          |
  239.                                   ----------   /         /          /
  240.           =========================> |windALib| <======================
  241.              |schedLib|
  242.              ----------
  243. ROUTINE STRUCTURE
  244.     taskDelete        taskSpawn
  245.                                 |              /      |
  246.         |        taskCreat    |
  247.                                 |            /        |
  248.  taskTerminate  taskInit  taskActivate
  249.                                 |           |         |
  250.  taskPrioritySet@* taskDelay* taskDestroy*  |    taskResume@*
  251.    |                   |         |          |         |
  252.      tickAnnounce@*   |         |          |         |       taskSuspend@*
  253.                      |         |          |         |          /
  254.                 windDelay windDelete windSpawn windResume    /
  255.                                                            /
  256.          windTickAnnounce               *             windSuspend
  257.                           |
  258.   windPriNormalSet--windPrioritySet   windExit         windPendQPut-semTake*
  259.                |                        msgQRecv*
  260.  wdStart@*                               |    
  261.                                         |              windPendQGet-semGive@*
  262.      ----windWdStart                reschedule                     msgQSend@*
  263.                                          |      |
  264.  wdCancel@*                    @         |      |     windPendQFlush-semFlush@*
  265.      ------windWdCancel       |         |      |              msgQBroadcast@*
  266.     workQAdd#    |     workQDoWork
  267.      loadContext
  268. .CS
  269. windview INSTRUMENTATION
  270. ------------------------
  271.         LEVEL 1 N/A
  272.         LEVEL 2
  273.                 windSpawn causes EVENT_WINDSPAWN
  274.                 windDelete causes EVENT_WINDDELETE
  275.                 windSuspend causes EVENT_WINDSUSPEND
  276.                 windResume causes EVENT_WINDRESUME
  277.                 windPrioritySet causes EVENT_WINDPRIORITYSETLOWER
  278.                 windPrioritySet causes EVENT_WINDPRIORITYSETRAISE
  279.                 windSemDelete causes EVENT_WINDSEMDELETE
  280.                 windTickAnnounce causes EVENT_WINDTICKUNDELAY
  281.                 windTickAnnounce causes EVENT_WINDTICKANNOUNCETMRWD
  282.                 windTickAnnounce causes EVENT_WINDTICKANNOUNCETMRSLC
  283.                 windTickAnnounce causes EVENT_WINDTICKANNOUNCETMR
  284.                 windDelay causes EVENT_WINDDELAY
  285.                 windUndelay causes EVENT_WINDUNDELAY
  286.                 windWdStart causes EVENT_WINDWDSTART
  287.                 windWdCancel causes EVENT_WINDWDCANCEL
  288.                 windPendQGet causes EVENT_WINDPENDQGET
  289.                 windPendQFlush causes EVENT_WINDPENDQFLUSH
  290.                 windPendQPut causes EVENT_WINDPENDQPUT
  291.                 windPendQTerminate causes EVENT_WINDPENDQTERMINATE
  292.         LEVEL 3 N/A
  293. .CE
  294. SEE ALSO: "Basic OS", windALib
  295. */
  296. #include "vxWorks.h"
  297. #include "tickLib.h"
  298. #include "taskArchLib.h"
  299. #include "semLib.h"
  300. #include "smLib.h"
  301. #include "wdLib.h"
  302. #include "errno.h"
  303. #include "qFifoLib.h"
  304. #include "qFifoGLib.h"
  305. #include "intLib.h"
  306. #include "smObjLib.h"
  307. #include "private/eventP.h"
  308. #include "private/funcBindP.h"
  309. #include "private/objLibP.h"
  310. #include "private/windLibP.h"
  311. #include "private/taskLibP.h"
  312. #include "private/workQLibP.h"
  313. #include "private/kernelLibP.h"
  314. /* global variables */
  315. BOOL kernelState; /* mutex to enter kernel state */
  316. BOOL kernelIsIdle; /* boolean reflecting idle state */
  317. /* shared memory objects globals */
  318. int  smObjPoolMinusOne;      /* set to smObj pool local address - 1 */
  319. int  localToGlobalOffset;    /* localAdrs - globalAdrs */
  320. /*******************************************************************************
  321. *
  322. * windSpawn - create a task and leave it in the suspend state
  323. *
  324. * This routine inserts the specified tcb into the active queue.
  325. * A newly created task is initially in the suspended state.
  326. *
  327. * NOMANUAL
  328. */
  329. void windSpawn
  330.     (
  331.     FAST WIND_TCB *pTcb         /* address of new task's tcb */
  332.     )
  333.     {
  334. #ifdef WV_INSTRUMENTATION
  335.     /* windview - level 2 event logging */
  336.     EVT_TASK_2 (EVENT_WINDSPAWN, (int) pTcb, pTcb->priority); 
  337. #endif
  338.     Q_PUT (&activeQHead, &pTcb->activeNode, FIFO_KEY_TAIL); /* in active q*/
  339.     }
  340. /*******************************************************************************
  341. *
  342. * windDelete - delete a task
  343. *
  344. * Delete task and reorganize any queue the task was in.
  345. * Assumes that the task owns no inheritance semaphores.
  346. *
  347. * NOMANUAL
  348. */
  349. STATUS windDelete
  350.     (
  351.     FAST WIND_TCB *pTcb         /* address of task's tcb */
  352.     )
  353.     {
  354.     FAST USHORT mask;
  355.     FAST int ix;
  356.     int  status = OK; /* status return by windPendQRemove */
  357. #ifdef WV_INSTRUMENTATION
  358.     /* windview - level 2 event logging */
  359.     EVT_TASK_1 (EVENT_WINDDELETE, (int) pTcb);  /* log event */
  360. #endif
  361.     if (pTcb->status == WIND_READY) /* if task is ready */
  362. Q_REMOVE (&readyQHead, pTcb); /* remove from queue */
  363.     else
  364. {
  365. if (pTcb->status & WIND_PEND) /* if task is pended */
  366.             status = windPendQRemove (pTcb);            /* remove from queue */
  367. if (pTcb->status & WIND_DELAY) /* if task is delayed */
  368.     Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  369. }
  370.     /* disconnect all the swap in hooks the task has connected to */
  371.     for (ix = 0, mask = pTcb->swapInMask; mask != 0; ix++, mask = mask << 1)
  372. if (mask & 0x8000)
  373.    taskSwapReference [ix] --;
  374.     /* disconnect all the swap out hooks the task has connected to */
  375.     for (ix = 0, mask = pTcb->swapOutMask; mask != 0; ix++, mask = mask << 1)
  376. if (mask & 0x8000)
  377.    taskSwapReference [ix] --;
  378.     Q_REMOVE (&activeQHead, &pTcb->activeNode); /* deactivate it */
  379.     pTcb->status = WIND_DEAD;         /* kill it */
  380.     return (status);
  381.     }
  382. /*******************************************************************************
  383. *
  384. * windSuspend - suspend a task
  385. *
  386. * Suspension is an additive state.  When a task is on the ready queue it
  387. * is removed and changed to suspended.  Otherwise, the status is updated
  388. * to include suspended in addition to the state it is already in.
  389. *
  390. * NOMANUAL
  391. */
  392. void windSuspend
  393.     (
  394.     FAST WIND_TCB *pTcb         /* address of task's tcb, 0 = current task */
  395.     )
  396.     {
  397. #ifdef WV_INSTRUMENTATION
  398.     /* windview - level 2 event logging */
  399.     EVT_TASK_1 (EVENT_WINDSUSPEND, (int) pTcb);  /* log event */
  400. #endif
  401.     if (pTcb->status == WIND_READY)
  402. Q_REMOVE (&readyQHead, pTcb);
  403.     pTcb->status |= WIND_SUSPEND; /* update status */
  404.     }
  405. /*******************************************************************************
  406. *
  407. * windResume - resume a task
  408. *
  409. * Resume the specified task and place in the ready queue if necessary.
  410. *
  411. * NOMANUAL
  412. */
  413. void windResume
  414.     (
  415.     FAST WIND_TCB *pTcb         /* task to resume */
  416.     )
  417.     {
  418. #ifdef WV_INSTRUMENTATION
  419.     /* windview - level 2 event logging */
  420.     EVT_TASK_1 (EVENT_WINDRESUME, (int) pTcb);  /* log event */
  421. #endif
  422.     if (pTcb->status == WIND_SUSPEND) /* just suspended so */
  423. Q_PUT (&readyQHead, pTcb, pTcb->priority); /* put in ready queue */
  424.     pTcb->status &= ~WIND_SUSPEND; /* mask out the suspend state */
  425.     }
  426. /*******************************************************************************
  427. *
  428. * windPriNormalSet - set the normal priority of a task
  429. *
  430. * Set the normal priority of a task.  A task will execute at its normal priority
  431. * as long as no priority inheritance has taken place.
  432. *
  433. * NOMANUAL
  434. */
  435. void windPriNormalSet
  436.     (
  437.     WIND_TCB    *pTcb,          /* address of task's tcb */
  438.     UINT         priNormal      /* new normal priority */
  439.     )
  440.     {
  441.     pTcb->priNormal = priNormal; /* update normal priority */
  442.     windPrioritySet (pTcb, priNormal); /* resort to appropriate priority */
  443.     }
  444. /*******************************************************************************
  445. *
  446. * windPrioritySet - resort the specified task to the appropriate priority
  447. *
  448. * This routine sets the actual priority of task, taking into account priority
  449. * inversion safety.  If a task owns any priority inversion safety semaphores
  450. * then the priority will not be allowed to lower.
  451. *
  452. * NOMANUAL
  453. */
  454. void windPrioritySet
  455.     (
  456.     FAST WIND_TCB *pTcb,        /* address of task's tcb */
  457.     FAST UINT      priority     /* new priority */
  458.     )
  459.     {
  460.     /* if lowering the current priority and the task doesn't own any mutex
  461.      * semaphores with inheritance, then go ahead and lower current priority.
  462.      */
  463.     if ((pTcb->priMutexCnt == 0) && (pTcb->priority < priority))
  464. {
  465. #ifdef WV_INSTRUMENTATION
  466.         /* windview - level 2 event logging */
  467. EVT_TASK_3 (EVENT_WINDPRIORITYSETLOWER, (int) pTcb, 
  468. pTcb->priority, priority);
  469. #endif
  470. pTcb->priority = priority; /* lower current priority */
  471. if (pTcb->status == WIND_READY) /* task is in ready Q? */
  472.     {
  473.     Q_RESORT (&readyQHead, pTcb, priority);
  474.     }
  475. else if (pTcb->status & WIND_PEND) /* task is in pend Q? */
  476.     {
  477.     Q_RESORT (pTcb->pPendQ, pTcb, priority);
  478.     }
  479. return; /* no inheritance if lowering */
  480. }
  481.     while (pTcb->priority > priority) /* current priority too low? */
  482. {
  483. #ifdef WV_INSTRUMENTATION
  484.         /* windview - level 2 event logging */
  485. EVT_TASK_3 (EVENT_WINDPRIORITYSETRAISE, (int) pTcb, 
  486. pTcb->priority, priority);
  487. #endif
  488. pTcb->priority = priority; /* raise current priority */
  489. if (pTcb->status == WIND_READY) /* task is in ready Q? */
  490.     {
  491.     Q_RESORT (&readyQHead, pTcb, priority);
  492.     }
  493. else if (pTcb->status & WIND_PEND) /* task is in pend Q? */
  494.     {
  495.     Q_RESORT (pTcb->pPendQ, pTcb, priority);
  496.     if (pTcb->pPriMutex != NULL) /* chain up for inheritance */
  497. pTcb = pTcb->pPriMutex->semOwner;
  498.     }
  499. }
  500.     }
  501. /*******************************************************************************
  502. *
  503. * windSemDelete - delete a semaphore
  504. *
  505. * Delete a semaphore and unblock any tasks pended on it.  Unblocked tasks
  506. * will be returned ERROR.
  507. *
  508. * NOMANUAL
  509. */
  510. void windSemDelete
  511.     (
  512.     FAST SEM_ID semId   /* semaphore to delete */
  513.     )
  514.     {
  515.     FAST WIND_TCB *pTcb;
  516. #ifdef WV_INSTRUMENTATION
  517.     /* windview - level 2 event logging */
  518.     EVT_TASK_1 (EVENT_WINDSEMDELETE, (int) semId);      /* log event */
  519. #endif
  520.     windPendQTerminate (&semId->qHead); /* terminate pend q */
  521.     if ((semId->semType == SEM_TYPE_MUTEX) && /* mutex semaphore? */
  522. ((pTcb = semId->semOwner) != NULL) && /* is there an owner? */
  523.         (OBJ_VERIFY (&((WIND_TCB *)(pTcb))->objCore, taskClassId) == OK))
  524. {
  525. if ((semId->options & SEM_INVERSION_SAFE) && /* inversion safe opt?*/
  526.     (-- pTcb->priMutexCnt == 0) &&  /* last mutex owned? */
  527.     (pTcb->priority != pTcb->priNormal)) /* priority inherited?*/
  528.     {
  529.     windPrioritySet (pTcb, pTcb->priNormal); /* back to normal pri */
  530.     }
  531. if ((semId->options & SEM_DELETE_SAFE) && /* deletion safe opt? */
  532.     ((-- pTcb->safeCnt) == 0) && /* unsafe now? */
  533.     (Q_FIRST (&pTcb->safetyQHead) != NULL)) /* deleters pended? */
  534.     {
  535.     windPendQFlush (&pTcb->safetyQHead); /* flush deleters */
  536.     }
  537. }
  538.     }
  539. /*******************************************************************************
  540. *
  541. * windTickAnnounce - acknowledge the passing of time
  542. *
  543. * Process delay list.  Make tasks at the end of their delay, ready.
  544. * Perform round robin scheduling if selected.
  545. * Call any expired watchdog routines.
  546. *
  547. * NOMANUAL
  548. */
  549. void windTickAnnounce (void)
  550.     {
  551.     FAST Q_NODE * pNode; /* node of tick queue */
  552.     FAST WIND_TCB * pTcb; /* pointer to task control block */
  553.     FAST WDOG * wdId; /* pointer to a watchdog */
  554.     FUNCPTR wdRtn; /* watch dog routine to invoke */
  555.     int wdArg; /* watch dog argument to pass with wdRtn */
  556.     int  status; /* status return by Q_REMOVE */
  557.     /* advance and manage the tick queue */
  558.     vxTicks ++; /* advance rel time */
  559.     vxAbsTicks++; /* advance abs time */
  560.     Q_ADVANCE (&tickQHead); /* advance tick queue */
  561.     while ((pNode = (Q_NODE *) Q_GET_EXPIRED (&tickQHead)) != NULL)
  562. {
  563. pTcb = (WIND_TCB *) ((int)pNode - OFFSET (WIND_TCB, tickNode));
  564. if  (
  565.     (pTcb->objCore.pObjClass == taskClassId) /* is it a task? */
  566. #ifdef WV_INSTRUMENTATION 
  567.     || (pTcb->objCore.pObjClass == taskInstClassId)
  568. #endif
  569.     )
  570.     { pTcb->status &= ~WIND_DELAY; /* out of delay state */
  571.     if (pTcb->status == WIND_READY) /* taskDelay done */
  572. {
  573. #ifdef WV_INSTRUMENTATION
  574.      /* windview - level 2 event logging */
  575. EVT_TASK_1 (EVENT_WINDTICKUNDELAY, (int) pTcb); 
  576. #endif
  577. taskRtnValueSet (pTcb, OK); /* return OK */
  578. }
  579.     else if (pTcb->status & WIND_PEND) /* semaphore timeout */
  580. {
  581.                 /*
  582.                  * if the task was pended on a shared semaphore
  583.                  * windPendQRemove can return :
  584.                  * ERROR if lock cannot be taken
  585.                  * ALREADY_REMOVED if the shared tcb is already removed
  586.                  * from the pend Q on the give side but has not
  587.                  * shows up on this side.
  588.                  */
  589. #ifdef WV_INSTRUMENTATION
  590.  EVT_TASK_1 (EVENT_WINDTICKTIMEOUT, (int )pTcb); 
  591. #endif
  592.                 status = windPendQRemove (pTcb);        /* out of semaphore q */
  593.                 switch (status)
  594.                     {
  595.                     case ALREADY_REMOVED:
  596.                         {
  597.                         /* the semaphore was given in time, return OK */
  598.                         taskRtnValueSet (pTcb, OK);
  599.                         break;
  600.                         }
  601.                     case ERROR:
  602.                         {
  603.                         taskRtnValueSet (pTcb, ERROR);      /* return ERROR */
  604.                         pTcb->errorStatus = S_smObjLib_LOCK_TIMEOUT;
  605.                         break;
  606.                         }
  607.                     default:
  608.                         {
  609.                         taskRtnValueSet (pTcb, ERROR);  /* return ERROR */
  610.                         pTcb->errorStatus = S_objLib_OBJ_TIMEOUT;
  611.                         }
  612.                     }
  613. }
  614.     if (pTcb->status == WIND_READY) /* if ready, enqueue */
  615. Q_PUT (&readyQHead, pTcb, pTcb->priority);
  616.     }
  617. else /* must be a watchdog */
  618.     {
  619.     wdId = (WDOG *) ((int)pNode - OFFSET (WDOG, tickNode));
  620. #ifdef WV_INSTRUMENTATION
  621.          /* windview - level 2 event logging */
  622.     EVT_TASK_1 (EVENT_WINDTICKANNOUNCETMRWD, (int) wdId);
  623. #endif
  624.     wdId->status = WDOG_OUT_OF_Q; /* mark as out of q */
  625.     /* We get the watch dog routine and argument before testing
  626.      * deferStartCnt to avoid having to lock interrupts.  The RACE
  627.      * to worry about is a wdStart () or wdCancel () occuring after
  628.      * the test of deferStartCnt and before invoking the routine.
  629.      */
  630.     wdRtn = wdId->wdRoutine; /* get watch dog rtn */
  631.     wdArg = wdId->wdParameter; /* get watch dog arg */
  632.     intCnt ++;                                  /* fake ISR context */
  633.     if (wdId->deferStartCnt == 0)               /* check validity */
  634. (* wdRtn) (wdArg);                      /* invoke wdog rtn */
  635.             intCnt --;                                  /* unfake ISR context */
  636.     workQDoWork (); /* do deferred work */
  637.     }
  638. }
  639.     /* perform round robin scheduling if selected */
  640.     if ((roundRobinOn) && (taskIdCurrent->lockCnt == 0) &&
  641. (taskIdCurrent->status == WIND_READY) &&
  642. (++ taskIdCurrent->tslice >= roundRobinSlice))
  643. {
  644. #ifdef WV_INSTRUMENTATION
  645.      /* windview - level 2 event logging */
  646. EVT_TASK_0 (EVENT_WINDTICKANNOUNCETMRSLC); /* log event */
  647. #endif
  648. taskIdCurrent->tslice = 0; /* reset time slice  */
  649. Q_REMOVE (&readyQHead, taskIdCurrent); /* no Q_RESORT here! */
  650. Q_PUT (&readyQHead, taskIdCurrent, taskIdCurrent->priority);
  651. }
  652.     }
  653. /*******************************************************************************
  654. *
  655. * windDelay - put running task asleep for specified ticks
  656. *
  657. * Insert task in delay queue at correct spot dictated by the specified duration.
  658. *
  659. * RETURNS: OK
  660. *
  661. * NOMANUAL
  662. */
  663. STATUS windDelay
  664.     (
  665.     FAST int timeout
  666.     )
  667.     {
  668. #ifdef WV_INSTRUMENTATION
  669.     /* windview - level 2 event logging */
  670.     EVT_TASK_1 (EVENT_WINDDELAY, timeout);  /* log event */
  671. #endif
  672.     Q_REMOVE (&readyQHead, taskIdCurrent); /* out of ready queue */
  673.     if ((unsigned)(vxTicks + timeout) < vxTicks) /* rollover? */
  674. {
  675. Q_CALIBRATE (&tickQHead, ~vxTicks + 1);
  676. vxTicks = 0;
  677. }
  678.     Q_PUT (&tickQHead, &taskIdCurrent->tickNode, timeout + vxTicks);
  679.     taskIdCurrent->status |= WIND_DELAY; /* set delay status */
  680.     return (OK);
  681.     }
  682. /*******************************************************************************
  683. *
  684. * windUndelay - wake a sleeping task up
  685. *
  686. * Remove task from the delay queue and return to it ERROR.
  687. *
  688. * RETURNS: OK
  689. *
  690. * NOMANUAL
  691. */
  692. STATUS windUndelay
  693.     (
  694.     WIND_TCB *pTcb
  695.     )
  696.     {
  697.     if ((pTcb->status & WIND_DELAY) == 0) /* in not delayed then done */
  698. return (OK);
  699. #ifdef WV_INSTRUMENTATION
  700.     /* windview - level 2 event logging */
  701.     EVT_TASK_1 (EVENT_WINDUNDELAY, (int) pTcb);  /* log event */
  702. #endif
  703.     pTcb->status &= ~WIND_DELAY; /* undelay status */
  704.     Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from tick queue */
  705.     taskRtnValueSet (pTcb, ERROR); /* return ERROR */
  706.     pTcb->errorStatus = S_taskLib_TASK_UNDELAYED;
  707.     if (pTcb->status == WIND_READY) /* if ready, enqueue */
  708. Q_PUT (&readyQHead, pTcb, pTcb->priority);
  709.     return (OK);
  710.     }
  711. /*******************************************************************************
  712. *
  713. * windWdStart - start a watchdog timer
  714. *
  715. * This routine will start or restart a watchdog.  If the watchdog is already
  716. * in the queue, it is resorted to the appropriate timeout.  If there are
  717. * more windWdStart() jobs still in the kernel work queue, as counted by the
  718. * variable deferStartCnt, then no action is taken.
  719. *
  720. * RETURNS: OK.
  721. *
  722. * NOMANUAL
  723. */
  724. STATUS windWdStart
  725.     (
  726.     WDOG *wdId,         /* watch dog to start */
  727.     int   timeout       /* timeout in ticks */
  728.     )
  729.     {
  730.     int deferStartCnt; /* temp variable to hold deferStartCnt */
  731.     int level; 
  732. #ifdef WV_INSTRUMENTATION
  733.     /* windview - level 2 event logging */
  734.     EVT_TASK_1 (EVENT_WINDWDSTART, (int) wdId);  /* log event */
  735. #endif
  736.     /* Protect the decrement from interrupts to avoid the race condition
  737.        that spr 7070 describes */
  738.     level = intLock ();
  739. deferStartCnt = -- wdId->deferStartCnt;
  740.     intUnlock (level);
  741.     if (deferStartCnt == 0)
  742. {
  743. if ((unsigned)(vxTicks + timeout) < vxTicks) /* rollover? */
  744.     {
  745.     Q_CALIBRATE (&tickQHead, ~vxTicks + 1);
  746.     vxTicks = 0;
  747.     }
  748. if (wdId->status == WDOG_IN_Q) /* resort if in queue */
  749.     Q_RESORT (&tickQHead, &wdId->tickNode, timeout + vxTicks);
  750. else
  751.     Q_PUT (&tickQHead, &wdId->tickNode, timeout + vxTicks);
  752. wdId->status = WDOG_IN_Q;
  753. }
  754.     return (OK);
  755.     }
  756. /*******************************************************************************
  757. *
  758. * windWdCancel - cancel a watchdog timer
  759. *
  760. * This routine cancels a watchdog, removing it from the timer queue if needed.
  761. *
  762. * NOMANUAL
  763. */
  764. void windWdCancel
  765.     (
  766.     WDOG *wdId          /* watch dog to cancel */
  767.     )
  768.     {
  769. #ifdef WV_INSTRUMENTATION
  770.     /* windview - level 2 event logging */
  771.     EVT_TASK_1 (EVENT_WINDWDCANCEL, (int) wdId);  /* log event */
  772. #endif 
  773.     if (wdId->status == WDOG_IN_Q)
  774. {
  775. Q_REMOVE (&tickQHead, &wdId->tickNode); /* remove from queue */
  776. wdId->status = WDOG_OUT_OF_Q;
  777. }
  778.     }
  779. /*******************************************************************************
  780. *
  781. * windPendQGet - remove and next task on pend queue and make ready
  782. *
  783. * Take the next task on the specified pend queue and unpend it.  It will either
  784. * be ready or suspended.  If ready it is added to the ready queue.
  785. *
  786. * NOMANUAL
  787. */
  788. void windPendQGet
  789.     (
  790.     Q_HEAD *pQHead      /* pend queue to get first task off */
  791.     )
  792.     {
  793.     FAST WIND_TCB *pTcb = (WIND_TCB *) Q_GET (pQHead);
  794. #ifdef WV_INSTRUMENTATION
  795.     /* windview - level 2 event logging */
  796.     EVT_TASK_1 (EVENT_WINDPENDQGET, (int) pTcb);  /* log event */
  797. #endif
  798.     pTcb->status &= ~WIND_PEND; /* clear pended flag */
  799.     taskRtnValueSet (pTcb, OK); /* return OK */
  800.     if (pTcb->status & WIND_DELAY) /* task was timing out */
  801. {
  802. pTcb->status &= ~WIND_DELAY;
  803. Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  804. }
  805.     if (pTcb->status == WIND_READY) /* task is now ready */
  806. Q_PUT (&readyQHead, pTcb, pTcb->priority);
  807.     }
  808. /*******************************************************************************
  809. *
  810. * windReadyQPut - put a task on the ready queue
  811. *
  812. * This routine adds a task previously blocked on a shared
  813. * semaphore to the ready Queue.
  814. *
  815. * The shared TCB of this task has been removed from the shared semaphore
  816. * pending queue by the CPU that gives the semaphore.
  817. *
  818. * NOMANUAL
  819. */
  820. void windReadyQPut
  821.     (
  822.     WIND_TCB * pTcb              /* TCB to add to ready Q */
  823.     )
  824.     {
  825.     pTcb->status &= ~WIND_PEND;                 /* clear pended flag */
  826.     taskRtnValueSet (pTcb, OK);                 /* return OK */
  827.     if (pTcb->status & WIND_DELAY)              /* task was timing out */
  828.         {
  829.         pTcb->status &= ~WIND_DELAY;
  830.         Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  831.         }
  832.     if (pTcb->status == WIND_READY)             /* task is now ready */
  833.         Q_PUT (&readyQHead, pTcb, pTcb->priority);
  834.     }
  835. /*******************************************************************************
  836. *
  837. * windReadyQRemove - remove pend task from the ready Q
  838. *
  839. * This routines removes the current task from the pend. The task must have
  840. * been previously added to a shared semaphore pend Q by using  Q_PUT.
  841. * If the task is timing out, also add the task to the delay queue. 
  842. *
  843. * RETURNS: N/A
  844. *
  845. * NOMANUAL
  846. */
  847. void windReadyQRemove
  848.     (
  849.     Q_HEAD *pQHead,        /* pend queue to put taskIdCurrent on */
  850.     int    timeout         /* timeout in ticks */
  851.     )
  852.     {
  853.     Q_REMOVE (&readyQHead, taskIdCurrent);              /* out of ready q */
  854.     taskIdCurrent->status |= WIND_PEND;                 /* update status */
  855.     taskIdCurrent->pPendQ = pQHead;                     /* pQHead pended on */
  856.     if (timeout != WAIT_FOREVER)                        /* timeout specified? */
  857.         {
  858.         if ((unsigned)(vxTicks + timeout) < vxTicks)    /* rollover? */
  859.             {
  860.             Q_CALIBRATE (&tickQHead, ~vxTicks + 1);
  861.             vxTicks = 0;
  862.             }
  863.         Q_PUT (&tickQHead, &taskIdCurrent->tickNode, timeout + vxTicks);
  864.         taskIdCurrent->status |= WIND_DELAY;
  865.         }
  866.     }
  867. /*******************************************************************************
  868. *
  869. * windPendQFlush - flush all tasks off of pend queue making them ready
  870. *
  871. * Take all of the tasks on the specified pend queue and unpend them.  They will
  872. * either be ready or suspended.  All ready tasks will be added to the ready
  873. * queue.
  874. *
  875. * NOMANUAL
  876. */
  877. void windPendQFlush
  878.     (
  879.     Q_HEAD *pQHead      /* pend queue to flush tasks from */
  880.     )
  881.     {
  882.     FAST WIND_TCB *pTcb;
  883. #if FALSE
  884. #ifdef WV_INSTRUMENTATION
  885.     int level = 0;
  886. #endif
  887. #endif /* FALSE */
  888.     while ((pTcb = (WIND_TCB *) Q_GET (pQHead)) != NULL)/* get next task */
  889. {
  890. #ifdef WV_INSTRUMENTATION
  891. /* windview - level 2 event logging */
  892. EVT_TASK_1 (EVENT_WINDPENDQFLUSH, (int) pTcb); 
  893. #endif
  894. pTcb->status &= ~WIND_PEND; /* clear pended flag */
  895. taskRtnValueSet (pTcb, OK); /* return OK */
  896. if (pTcb->status & WIND_DELAY) /* task is timeout */
  897.     {
  898.     pTcb->status &= ~WIND_DELAY;
  899.     Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  900.     }
  901. if (pTcb->status == WIND_READY) /* task is now ready */
  902.     Q_PUT (&readyQHead, pTcb, pTcb->priority);
  903. }
  904.     }
  905. /*******************************************************************************
  906. *
  907. * windPendQPut - add current task to a pend queue
  908. *
  909. * Add a taskIdCurrent to a pend queue.  If the task is timing out, also add the
  910. * task to the delay queue.  If the NO_WAIT value is passed for a timeout,
  911. * return ERROR.
  912. *
  913. * RETURNS: OK, or ERROR if NO_WAIT timeout is specified.
  914. *
  915. * ERRNO: S_objLib_OBJ_UNAVAILABLE
  916. *
  917. * NOMANUAL
  918. */
  919. STATUS windPendQPut
  920.     (
  921.     FAST Q_HEAD *pQHead,        /* pend queue to put taskIdCurrent on */
  922.     FAST int    timeout         /* timeout in ticks */
  923.     )
  924.     {
  925.     if (timeout == NO_WAIT) /* NO_WAIT = no block */
  926. {
  927. errno = S_objLib_OBJ_UNAVAILABLE; /* resource gone */
  928. return (ERROR);
  929. }
  930. #ifdef WV_INSTRUMENTATION
  931.     /* windview - level 2 event logging */
  932.     EVT_TASK_0 (EVENT_WINDPENDQPUT);  /* log event */
  933. #endif
  934.     Q_REMOVE (&readyQHead, taskIdCurrent); /* out of ready q */
  935.     taskIdCurrent->status |= WIND_PEND; /* update status */
  936.     taskIdCurrent->pPendQ = pQHead; /* pQHead pended on */
  937.     Q_PUT (pQHead, taskIdCurrent, taskIdCurrent->priority);
  938.     if (timeout != WAIT_FOREVER) /* timeout specified? */
  939. {
  940. if ((unsigned)(vxTicks + timeout) < vxTicks) /* rollover? */
  941.     {
  942.     Q_CALIBRATE (&tickQHead, ~vxTicks + 1);
  943.     vxTicks = 0;
  944.     }
  945. Q_PUT (&tickQHead, &taskIdCurrent->tickNode, timeout + vxTicks);
  946. taskIdCurrent->status |= WIND_DELAY;
  947. }
  948.     return (OK);
  949.     }
  950. /*******************************************************************************
  951. *
  952. * windPendQRemove - move a task out of the pend queue
  953. *
  954. * This routine removes a task from a pend queue.
  955. *
  956. * RETURNS: OK
  957. *
  958. * NOMANUAL
  959. */
  960. STATUS windPendQRemove
  961.     (
  962.     WIND_TCB *pTcb              /* task to remove from pend queue */
  963.     )
  964.     {
  965.     int status = Q_REMOVE (pTcb->pPendQ, pTcb); /* out of pend queue */
  966.     /*
  967.      * When shared semaphore are used Q_REMOVE can return ERROR if lock
  968.      * cannot be taken, or ALREADY_REMOVED if the shared tcb is currently
  969.      * in the event list, ie removed from the shared semaphore pend Q.
  970.      */
  971.     pTcb->status   &= ~WIND_PEND; /* turn off pend bit */
  972.     pTcb->pPriMutex = NULL; /* clear pPriMutex */
  973.     if (pTcb->status & WIND_DELAY) /* task was timing out */
  974. {
  975. pTcb->status &= ~WIND_DELAY;
  976. Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  977. }
  978.     return (status);
  979.     }
  980. /*******************************************************************************
  981. *
  982. * windPendQTerminate - flush all tasks off of pend queue making them ready
  983. *
  984. * Take all of the tasks on the specified pend queue and unpend them.  They will
  985. * either be ready or suspended.  All ready tasks will be added to the ready
  986. * queue.  Unlike windPendQFlush (2), this routine returns the ERROR
  987. * S_objLib_OBJ_DELETED.
  988. *
  989. * NOMANUAL
  990. */
  991. void windPendQTerminate
  992.     (
  993.     Q_HEAD *pQHead      /* pend queue to terminate */
  994.     )
  995.     {
  996.     FAST WIND_TCB *pTcb;
  997.     while ((pTcb = (WIND_TCB *) Q_GET (pQHead)) != NULL)/* get next task */
  998. {
  999. #ifdef WV_INSTRUMENTATION
  1000.         /* windview - level 2 event logging */
  1001. EVT_TASK_1 (EVENT_WINDPENDQTERMINATE, (int) pTcb);
  1002. #endif
  1003. pTcb->status     &= ~WIND_PEND; /* clear pended flag */
  1004. pTcb->pPriMutex   = NULL; /* clear mutex pend */
  1005. pTcb->errorStatus = S_objLib_OBJ_DELETED; /* set error status */
  1006. taskRtnValueSet (pTcb, ERROR); /* return ERROR */
  1007. if (pTcb->status & WIND_DELAY) /* task is timeout */
  1008.     {
  1009.     pTcb->status &= ~WIND_DELAY;
  1010.     Q_REMOVE (&tickQHead, &pTcb->tickNode); /* remove from queue */
  1011.     }
  1012. if (pTcb->status == WIND_READY) /* task is now ready */
  1013.     Q_PUT (&readyQHead, pTcb, pTcb->priority);
  1014. }
  1015.     }