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

VxWorks

开发平台:

C/C++

  1. /* taskLib.c - task management library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 05o,15may02,pcm  added check for valid priority level in taskInit() (SPR 77368)
  8. 05n,04jan02,hbh  Increased default extra stack size for simulators.
  9. 05m,09nov01,jhw  Revert WDB_INFO to be inside WIND_TCB.
  10. 05l,05nov01,gls  added initialization of pPthread in taskInit
  11. 05k,17oct01,jhw  Move WDB_INFO outside of WIND_TCB in task mem partition.
  12. 05j,11oct01,cjj  removed Am29k support.  Added documentation to taskSpawn()
  13.  regarding the use of VX_FP_TASK.
  14. 05i,10oct01,pcm  added note to taskIdVerify () about exceptions (SPR 31496)
  15. 05h,09oct01,bwa  Added event field initialization.
  16. 05g,20sep01,aeg  added init of pSelectContext and pWdbInfo in taskInit().
  17. 05f,13jul01,kab  Cleanup for merge to mainline
  18. 05e,14mar01,pcs  Added code for ALTIVEC awareness.
  19. 05d,18dec00,pes  Correct compiler warnings
  20. 05d,03mar00,zl   merged SH support into T2
  21. 05c,12mar99,dbs  add COM task-local storage to TCB
  22. 05b,09mar98,cym  increasing stack size for SIMNT.
  23. 05a,05nov98,fle  doc : allowed link to taskInfo library by putting it in bold
  24. 04g,04sep98,cdp  force entry-point in TCB to have bit zero clear for all Thumb.
  25. 04f,25sep98,cym  removed 04f.
  26. 04e,06may98,cym  changed taskDestroy for SIMNT to use the calling context.
  27. 04d,22jul96,jmb  merged ease patch,  don't reinitialize excInfo on taskRestart.
  28. 04c,12jan98,dbt  modified for new debugger scheme.
  29. 04b,08jul97,dgp  doc: correct typo per SPR 7769
  30. 04b,22aug97,cdp  force entry point in TCB to have bit zero clear for Thumb.
  31. 04a,29oct96,dgp  doc: correct spelling of checkStack() in taskSpawn()
  32. 03z,16oct96,dgp  doc: add errnos for user-visible routines per SPR 6893
  33. 03y,09oct06,dgp  doc: correct taskInit() description of *pStackBase - SPR 6828
  34. 03x,08aug96,dbt  Modified taskRestart to handle task name>20 bytes (SPR #3445).
  35. 03w,24jul96,dbt  Initialized exception info for I960 in taskInit (SPR #3092).
  36. 03v,22jul96,jmb  merged ease patch,  don't reinitialize excInfo on taskRestart.
  37. 03u,27jun96,dbt  doc : added taskLock & taskUnlock not callable from
  38.  interrupt service routines (SPR #2568).
  39.  Updated copyright.
  40. 03t,24jun96,sbs  made windview instrumentation conditionally compiled
  41. 03u,13jun96,ism  increased stack size again
  42. 03t,13feb96,ism  bumped stack size for SIMSOLARIS created tasks
  43. 03s,25jan96,ism  cleanup for vxsim/solaris.
  44. 03r,23oct95,jdi  doc: added bit values for taskSpawn() options (SPR 4276).
  45. 03q,14oct95,jdi  doc: removed SEE ALSO to vxTaskEntry(), which is not published.
  46. 03p,26may95,ms  initialize WDB fields in the TCB
  47.    + rrr
  48. 03p,30oct95,ism  added SIMSPARCSOLARIS support
  49. 03o,16jan95,rhp  added expl of taskID for taskInit(), taskActivate() (SPR#3923)
  50. 03n,10nov94,ms   bumped stack size for all spawned SIMHPPA tasks.
  51. 03m,28jul94,dvs  added reset of pTaskLastFpTcb in taskDestroy. (SPR #3033)
  52. 03l,02dec93,pme  added am29K family stack support.
  53. 03k,20jul94,ms   undid some of 03j for VxSim/HPPA. Bumped restartTaskStackSize.
  54. 03j,28jan94,gae  vxsim fixes for bumping stack on sysFlag & clearing excInfo.
  55. 03n,19oct94,rdc  bug in eventlogging in taskDestroy.
  56.  added lockCnt to EVT_CTX_TASKINFO.
  57. 03m,14apr94,smb  modified EVT_OBJ_* macros again
  58. 03l,15mar94,smb  modified EVT_OBJ_* macros
  59. 03k,24jan94,smb  added instrumentation macros
  60. 03j,10dec93,smb  added instrumentation
  61. 03i,16sep93,jmm  added check in taskPrioritySet() to ensure priority is 0-255
  62. 03h,01mar93,jdi  doc: reinstated VX_UNBREAKABLE as publishable option, per kdl;
  63.  addition to taskDelay() as per rrr.
  64. 03g,27feb93,jcf  fixed race in taskDestroy() with masking signals.
  65. 03f,15feb93,jdi  fixed taskSpawn() to mention fixed argument requirement.
  66. 03e,10feb93,jdi  doc review by jcf; corrected spelling of stdlib.h.
  67. 03d,04feb93,jdi  documentation cleanup; SPR#1365: added VX_DEALLOC_STACK
  68.  to doc for taskSpawn().
  69. 03c,01oct92,jcf  removed deadlock with deletion of deletion safe tasks.
  70. 03b,29sep92,pme  removed failure notification in taskDestroy.
  71. 03a,31aug92,rrr  fixed taskDelay to set errno to EINTR if a signal occurs.
  72. 02z,23aug92,jcf  moved info routines to taskInfo.c.  changed bzero to bfill.
  73. 02y,02aug92,jcf  initialized pExcRegSet (taskInit) utilized in taskRegSet().
  74. 02x,29jul92,jcf  taskDestroy suspends victim; padding to account for mem tags;
  75.  package initialization with taskInit; documentation.
  76. 02w,27jul92,jcf  cleanup.
  77. 02v,24jul92,yao  changed to use STACK_ROUND_UP instead MEM_ROUND_UP in 
  78.  taskStackAllot().  bzeroed dbgInfo in taskInit().
  79. 02u,23jul92,yao  removed initialization of pDbgState.
  80. 02t,23jul92,rrr  rounded the sizeof the TCB up to the requirements of rounding
  81.                  of the stack.
  82. 02s,23jul92,ajm  moved _sig_timeout_recalc from sigLib to shrink proms
  83. 02r,21jul92,pme  changed shared TCB free management.
  84.                  added smObjTaskDeleteFailRtn.
  85. 02q,19jul92,pme  added shared memory objects support.
  86. 02p,19jul92,smb  Added some ANSI documentation.
  87. 02o,09jul92,rrr  changed xsignal.h to private/sigLibP.h
  88. 02n,04jul92,jcf  changed algorithm of taskDestroy/taskRestart to avoid excJobAdd
  89.  tid is now valid for delete hooks.
  90.  stack is now not filled optionally.
  91.  show/info routines removed.
  92. 02m,30jun92,yao  changed to init pDbgState for all architectures.
  93. 02l,26jun92,jwt  restored 02k changes; cleaned up compiler warnings.
  94. 02k,16jun92,jwt  made register display four across; fixed rrr version numbers.
  95. 02j,26may92,rrr  the tree shuffle
  96. 02i,30apr92,rrr  added signal restarting
  97. 02h,18mar92,yao  removed macro MEM_ROUND_UP.  removed conditional definition
  98.  STACK_GROWS_DOWN/UP.  abstracted taskStackAllot() from
  99.  taskArchLib.c.  removed unneccesary if conditionals for
  100.  calls to taskRegsInit() in taskInit().  changed taskRegsShow()
  101.  to be within 80 columns per line.
  102. 02g,12mar92,yao  added taskRegsShow().  changed copyright notice.
  103. 02f,04oct91,rrr  passed through the ansification filter
  104.                   -changed functions to ansi style
  105.   -changed includes to have absolute path from h/
  106.   -fixed #else and #endif
  107.   -changed VOID to void
  108.   -changed copyright notice
  109. 02e,11sep91,hdn  Init pDbgState for TRON.
  110. 02d,21aug91,ajm  made MIPS stacksize bounded on 8 bytes for varargs.
  111. 02c,14aug91,del  padded qInit and excJobAdd call's with 0's.
  112.  Init pDbgState for I960 only.
  113. 02b,10jun91,gae  fixed typo in taskOptionString to not say VX_FP_STACK.
  114. 02a,23may91,jwt  modifed roundup from 4 to 8 bytes for SPARC only.
  115. 01z,26apr91,hdn  added conditional checks for TRON architecture.
  116. 01y,20apr91,del  fixed bug in taskInfoGet() for checking the stack high mark.
  117.  For STACK_GROWS_UP (i960) version.
  118. 01x,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  119.  doc review by dnw.
  120. 01w,31mar91,del  added I960 specifics.
  121. 01v,24mar91,jdi  documentation cleanup.
  122. 01u,25oct90,dnw  made taskTerminate() NOMANUAL.
  123. 01t,05oct90,dnw  added forward declarations.
  124. 01s,30sep90,jcf  added taskDeleteForce().
  125. 01r,31aug90,jcf  documentation.
  126. 01q,30jul90,jcf  changed task{Lock,Unlock,Safe,Unsafe} to return STATUS
  127. 01p,17jul90,dnw  changed to call to objAlloc() to objAllocExtra().
  128. 01o,13jul90,rdc  taskInit zeros environment var and select stuff in tcb.
  129. 01n,05jul90,jcf  added STACK_GROWS_XX to resolve stack growth direction issues.
  130.  renamed stack variables.
  131.  changed taskSuspend to disregard task deletion safety.
  132. 01m,26jun90,jcf  added taskStackAllot()
  133.  changed taskNames to use taskStackAllot()
  134.  removed taskFppHook.
  135.  general cleanup.
  136. 01l,15apr90,jcf  changed nameForNameless from task<%d> to t<%d>
  137. 01k,28aug89,jcf  modified to version 2.0 of wind.
  138. 01j,09aug89,gae  undid varargs stuff.
  139. 01i,28apr89,mcl  added some initializations in WIND_TCB (applies to
  140.    both SPARC & 68k); fixes alignment check in taskIdVerify.
  141. 01h,07apr89,mcl  SPARC floating point.
  142. 01g,12dec88,ecs  gave it some sparc.
  143.  added include of varargs.h.
  144. 01f,19nov88,jcf  taskDelay can not be called from interrupt level.
  145.                    task ids of zero are translated to taskCurrentId here now.
  146. 01e,23sep88,gae  documentation touchup.
  147. 01d,07sep88,gae  documentation.
  148. 01c,23aug88,gae  documentation.
  149. 01b,20jul88,jcf  clean up.
  150. 01a,10mar88,jcf  written.
  151. */
  152. /*
  153. DESCRIPTION
  154. This library provides the interface to the VxWorks task management facilities.
  155. Task control services are provided by the VxWorks kernel, which is comprised
  156. of kernelLib, taskLib, semLib, tickLib, msgQLib, and `wdLib'.  Programmatic
  157. access to task information and debugging features is provided by `taskInfo'.
  158. Higher-level task information display routines are provided by `taskShow'.
  159. TASK CREATION
  160. Tasks are created with the general-purpose routine taskSpawn().  Task
  161. creation consists of the following:  allocation of memory for the stack
  162. and task control block (WIND_TCB), initialization of the WIND_TCB, and
  163. activation of the WIND_TCB.  Special needs may require the use of the
  164. lower-level routines taskInit() and taskActivate(), which are the underlying
  165. primitives of taskSpawn().
  166. Tasks in VxWorks execute in the most privileged state of the underlying
  167. architecture.  In a shared address space, processor privilege offers no
  168. protection advantages and actually hinders performance.
  169. There is no limit to the number of tasks created in VxWorks, as long as
  170. sufficient memory is available to satisfy allocation requirements.
  171. The routine sp() is provided in usrLib as a convenient abbreviation for
  172. spawning tasks.  It calls taskSpawn() with default parameters.
  173. TASK DELETION
  174. If a task exits its "main" routine, specified during task creation, the
  175. kernel implicitly calls exit() to delete the task.  Tasks can be
  176. explicitly deleted with the taskDelete() or exit() routine.
  177. Task deletion must be handled with extreme care, due to the inherent
  178. difficulties of resource reclamation.  Deleting a task that owns a
  179. critical resource can cripple the system, since the resource may no longer
  180. be available.  Simply returning a resource to an available state is not a
  181. viable solution, since the system can make no assumption as to the state
  182. of a particular resource at the time a task is deleted.
  183. The solution to the task deletion problem lies in deletion protection,
  184. rather than overly complex deletion facilities.  Tasks may be protected
  185. from unexpected deletion using taskSafe() and taskUnsafe().  While a task
  186. is safe from deletion, deleters will block until it is safe to proceed.
  187. Also, a task can protect itself from deletion by taking a mutual-exclusion
  188. semaphore created with the SEM_DELETE_SAFE option, which enables an implicit
  189. taskSafe() with each semTake(), and a taskUnsafe() with each semGive()
  190. (see semMLib for more information).
  191. Many VxWorks system resources are protected in this manner, and
  192. application designers may wish to consider this facility where dynamic
  193. task deletion is a possibility.
  194. The sigLib facility may also be used to allow a task to
  195. execute clean-up code before actually expiring.
  196. TASK CONTROL
  197. Tasks are manipulated by means of an ID that is returned when a task is
  198. created.  VxWorks uses the convention that specifying a task ID of NULL
  199. in a task control function signifies the calling task.
  200. The following routines control task state:  taskResume(), taskSuspend(),
  201. taskDelay(), taskRestart(), taskPrioritySet(), and taskRegsSet().
  202. TASK SCHEDULING
  203. VxWorks schedules tasks on the basis of priority.  Tasks may have
  204. priorities ranging from 0, the highest priority, to 255, the lowest
  205. priority.  The priority of a task in VxWorks is dynamic, and an existing
  206. task's priority can be changed using taskPrioritySet().
  207. INTERNAL:
  208. WINDVIEW INSTRUMENTATION
  209. Level 1:
  210. taskInit() causes EVENT_TASKSPAWN
  211. taskDestroy() causes EVENT_TASKDESTROY
  212. taskSuspend() causes EVENT_TASKSUSPEND
  213. taskResume() causes EVENT_TASKRESUME
  214. taskPrioritySet() causes EVENT_TASKPRIORITYSET
  215. taskUnsafe() causes EVENT_TASKUNSAFE
  216. Level 2:
  217. taskDestroy() causes EVENT_OBJ_TASK
  218. taskUnlock() causes EVENT_OBJ_TASK
  219. taskUnsafe() causes EVENT_OBJ_TASK
  220. Level 3:
  221. taskInit() causes EVENT_TASKNAME
  222. taskUnlock() causes EVENT_TASKUNLOCK
  223. INCLUDE FILES: taskLib.h
  224. SEE ALSO: `taskInfo', taskShow, taskHookLib, taskVarLib, semLib, semMLib, 
  225. kernelLib,
  226. .pG "Basic OS"
  227. */
  228. #include "vxWorks.h"
  229. #include "errno.h"
  230. #include "semLib.h"
  231. #include "string.h"
  232. #include "regs.h"
  233. #include "intLib.h"
  234. #include "taskArchLib.h"
  235. #include "stdio.h"
  236. #include "memLib.h"
  237. #include "qFifoGLib.h"
  238. #include "sysLib.h" /* CPU==SIM* */
  239. #include "private/eventLibP.h"
  240. #include "private/sigLibP.h"
  241. #include "private/classLibP.h"
  242. #include "private/objLibP.h"
  243. #include "private/smObjLibP.h"
  244. #include "private/smFixBlkLibP.h"
  245. #include "private/taskLibP.h"
  246. #include "private/kernelLibP.h"
  247. #include "private/workQLibP.h"
  248. #include "private/windLibP.h"
  249. #include "private/eventP.h"
  250. /* locals */
  251. LOCAL OBJ_CLASS taskClass; /* task object class */
  252. LOCAL int nameForNameless; /* name for nameless tasks */
  253. LOCAL BOOL taskLibInstalled; /* protect from double inits */
  254. /* globals */
  255. FUNCPTR smObjTcbFreeRtn; /* shared TCB free routine */
  256. FUNCPTR smObjTcbFreeFailRtn; /* shared TCB free fail rtn */
  257. FUNCPTR smObjTaskDeleteFailRtn; /* windDelete free fail rtn */
  258. FUNCPTR taskBpHook; /* hook for VX_UNBREAKABLE */
  259. FUNCPTR taskCreateTable   [VX_MAX_TASK_CREATE_RTNS + 1];
  260. FUNCPTR taskSwitchTable   [VX_MAX_TASK_SWITCH_RTNS + 1];
  261. FUNCPTR  taskDeleteTable   [VX_MAX_TASK_DELETE_RTNS + 1];
  262. FUNCPTR  taskSwapTable     [VX_MAX_TASK_SWAP_RTNS   + 1];
  263. int taskSwapReference [VX_MAX_TASK_SWAP_RTNS   + 1];
  264. WIND_TCB * taskIdCurrent; /* current task ID */
  265. CLASS_ID taskClassId    = &taskClass; /* task class ID */
  266. char * namelessPrefix = "t"; /* nameless prefix */
  267. char * restartTaskName = "tRestart"; /* restart name */
  268. int restartTaskPriority = 0; /* restart priority */
  269. int restartTaskStackSize = 6000; /* default stack size */
  270. int restartTaskOptions = VX_NO_STACK_FILL | VX_UNBREAKABLE;
  271. BOOL taskPriRangeCheck = TRUE; /* limit priorities to 0-255 */
  272. WIND_TCB * pTaskLastFpTcb          = NULL; /* pTcb for fppSwapHook */
  273. WIND_TCB * pTaskLastDspTcb         = NULL; /* pTcb for dspSwapHook */
  274. #ifdef _WRS_ALTIVEC_SUPPORT
  275. WIND_TCB *      pTaskLastAltivecTcb     = NULL; /* pTcb for altivecSwapHook */
  276. #endif  /* _WRS_ALTIVEC_SUPPORT */
  277. #ifdef WV_INSTRUMENTATION
  278. /* instrumentation declarations */
  279. LOCAL OBJ_CLASS taskInstClass; /* task object class */
  280. CLASS_ID  taskInstClassId  = &taskInstClass; /* instrumented task */
  281. #endif
  282. /* forward declarations */
  283. int taskCreat ();
  284. WIND_TCB * taskTcb (); /* get pTcb from tid */
  285. /*******************************************************************************
  286. *
  287. * taskLibInit - initialize kernel task library
  288. *
  289. * INTERNAL
  290. * Tasks are a class of object in VxWorks.  This routine initializes the task
  291. * task class object.  Once initialized, tasks can be created/deleted/etc via
  292. * objLib.  No other task related routine may be executed prior to the call
  293. * to this routine.  The sizeof the WIND_TCB is goosed up by 16 bytes
  294. * bytes so we can protect the starting portion of a task's tcb during 
  295. * deletion, in the case of STACK_GROWS_UP, or a portion of the top of the 
  296. * task's top of stack in the case of STACK_GROWS_DOWN.  This portion is 
  297. * clobbered with a FREE_BLOCK during objFree().
  298. *
  299. * NOMANUAL
  300. */
  301. STATUS taskLibInit (void)
  302.     {
  303.     if ((!taskLibInstalled) &&
  304.         (classInit (taskClassId, STACK_ROUND_UP(sizeof(WIND_TCB) + 16),
  305.                     OFFSET(WIND_TCB, objCore), (FUNCPTR) taskCreat,
  306.                     (FUNCPTR) taskInit, (FUNCPTR) taskDestroy) == OK))
  307.         {
  308. #ifdef WV_INSTRUMENTATION
  309. taskClassId->initRtn = taskInstClassId;
  310. classInstrument (taskClassId, taskInstClassId);
  311. #endif
  312.         taskLibInstalled = TRUE;
  313.         }
  314.     return ((taskLibInstalled) ? OK : ERROR);
  315.     }
  316. /*******************************************************************************
  317. *
  318. * taskSpawn - spawn a task
  319. *
  320. * This routine creates and activates a new task with a specified priority
  321. * and options and returns a system-assigned ID.  See taskInit() and
  322. * taskActivate() for the building blocks of this routine.
  323. *
  324. * A task may be assigned a name as a debugging aid.  This name will appear
  325. * in displays generated by various system information facilities such as
  326. * i().  The name may be of arbitrary length and content, but the current
  327. * VxWorks convention is to limit task names to ten characters and prefix
  328. * them with a "t".  If <name> is specified as NULL, an ASCII name will be
  329. * assigned to the task of the form "t<n>" where <n> is an integer which
  330. * increments as new tasks are spawned.
  331. *
  332. * The only resource allocated to a spawned task is a stack of a specified
  333. * size <stackSize>, which is allocated from the system memory partition.
  334. * Stack size should be an even integer.  A task control block (TCB) is
  335. * carved from the stack, as well as any memory required by the task name.
  336. * The remaining memory is the task's stack and every byte is filled with the
  337. * value 0xEE for the checkStack() facility.  See the manual entry for
  338. * checkStack() for stack-size checking aids.
  339. *
  340. * The entry address <entryPt> is the address of the "main" routine of the task.
  341. * The routine will be called once the C environment has been set up.
  342. * The specified routine will be called with the ten given arguments.
  343. * Should the specified main routine return, a call to exit() will
  344. * automatically be made.
  345. *
  346. * Note that ten (and only ten) arguments must be passed for the
  347. * spawned function.
  348. *
  349. * Bits in the options argument may be set to run with the following modes:
  350. * .iP "VX_FP_TASK  (0x0008)" 8
  351. * execute with floating-point coprocessor support.  A task which performs
  352. * floating point operations or calls any functions which either return
  353. * or take a floating point value as arguments must be created with this 
  354. * option.  Some routines perform floating point operations internally.
  355. * The VxWorks documentation for these clearly state the need to use
  356. * the VX_FP_TASK option.
  357. * .iP "VX_PRIVATE_ENV  (0x0080)"
  358. * include private environment support (see envLib).
  359. * .iP "VX_NO_STACK_FILL  (0x0100)"
  360. * do not fill the stack for use by checkStack().
  361. * .iP "VX_UNBREAKABLE  (0x0002)"
  362. * do not allow breakpoint debugging.
  363. * .LP
  364. * See the definitions in taskLib.h.
  365. *
  366. * RETURNS: The task ID, or ERROR if memory is insufficient or the task
  367. * cannot be created.
  368. *
  369. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_ID_ERROR,
  370. *        S_smObjLib_NOT_INITIALIZED, S_memLib_NOT_ENOUGH_MEMORY,
  371. *        S_memLib_BLOCK_ERROR, S_taskLib_ILLEGAL_PRIORITY
  372. *
  373. * SEE ALSO: taskInit(), taskActivate(), sp(),
  374. * .pG "Basic OS"
  375. *
  376. * VARARGS5
  377. */
  378. int taskSpawn
  379.     (
  380.     char          *name,        /* name of new task (stored at pStackBase) */
  381.     int           priority,     /* priority of new task */
  382.     int           options,      /* task option word */
  383.     int           stackSize,    /* size (bytes) of stack needed plus name */
  384.     FUNCPTR       entryPt,      /* entry point of new task */
  385.     int           arg1,         /* 1st of 10 req'd task args to pass to func */
  386.     int           arg2,
  387.     int           arg3,
  388.     int           arg4,
  389.     int           arg5,
  390.     int           arg6,
  391.     int           arg7,
  392.     int           arg8,
  393.     int           arg9,
  394.     int           arg10 
  395.     )
  396.     {
  397.     int tid = taskCreat (name, priority, options, stackSize, entryPt, arg1,
  398.                          arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
  399.     if (tid == (int)NULL) /* create failed */
  400. return (ERROR);
  401.     taskActivate (tid); /* activate task */
  402.     return (tid); /* return task ID */
  403.     }
  404. /*******************************************************************************
  405. *
  406. * taskCreat - allocate and initialize a task without activation
  407. *
  408. * This routine allocates and initializes a new task with the given priority,
  409. * ID, and options.
  410. *
  411. * argument <name>
  412. * A task may be given a name as a debugging aid.  This name will show up in
  413. * various system information facilities suchas i().  The name may be of
  414. * arbitrary length and content, but the current VxWorks convention is to limit
  415. * task names to ten characters and prefix them with a `t'.  If the task name
  416. * is specified as NULL, an ASCII name will be given to the task of the form
  417. * `t<n>' where <n> is number which increments as tasks are spawned.
  418. *
  419. * argument <priority>
  420. * VxWorks schedules tasks on the basis of priority.  Tasks may have priorities
  421. * ranging from 0, the highest priority, to 255, the lowest priority.  VxWorks
  422. * system tasks execute with priorities in the range 0 to 50.  The priority
  423. * of a task in VxWorks in dynamic and one may change an existing task's priority
  424. * with taskPrioritySet().
  425. *
  426. * Tasks in VxWorks always run in the most privileged mode of the CPU.  In
  427. * a shared address space, processor privilege offers no protection advantages
  428. * and actually hinders performance.
  429. *
  430. * argument <options>
  431. * Bits in the options argument may be set to run with the following modes.
  432. * .CS
  433. * VX_UNBREAKABLE -  don't allow break point debugging
  434. * VX_FP_TASK -  execute with coprocessor support
  435. * VX_DSP_TASK -  execute with dsp support
  436. * VX_ALTIVEC_TASK -  execute with Alitvec support
  437. * VX_STDIO -  execute with standard I/O support
  438. * .CE
  439. * See definitions in taskLib.h.
  440. *
  441. * argument <stackSize>
  442. * The only resource allocated to a spawned task is a stack of the specified
  443. * size which is allocated from the memory pool.  Stack size should be even.
  444. * A task control block (TCB) is carved from the stack, as well as a task
  445. * debug structure WDB_INFO and any memory required by the task's name.
  446. * The remaining memory is the task's stack. Every byte of the stack is 
  447. * filled with the value 0xEE for the checkStack() facility. See checkStack()
  448. * for stack size checking aids.
  449. *
  450. * The task stack memory map is: 
  451. *
  452. * For _STACK_GROWS_DOWN:
  453. *
  454. * .CS
  455. *         - HIGH MEMORY -
  456. *     ------------------------
  457. *     |                      |
  458. *     |       WIND_TCB       |
  459. *     |                      |
  460. *     ------------------------ <--- pStackBase, pTcb
  461. *     |////// 16 bytes //////|
  462. *     |                      |  (16 bytes clobbered during objFree()
  463. *     |                      |  in taskDestroy are not accounted for)
  464. *     |                      |
  465. *     |      TASK STACK      |
  466. *     |                      |
  467. *     |                      |
  468. *     |                      |
  469. *     ------------------------ <--- pTaskMem
  470. *         - LOW  MEMORY -
  471. * .CE
  472. *
  473. * For _STACK_GROWS_UP:
  474. *
  475. * .CS
  476. *          - HIGH MEMORY -
  477. *     ------------------------
  478. *     |                      |
  479. *     |                      |
  480. *     |                      |
  481. *     |      TASK STACK      |
  482. *     |                      |
  483. *     |                      |
  484. *     |                      |
  485. *     ------------------------ <--- pStackBase
  486. *     |                      |
  487. *     |       WIND_TCB       |
  488. *     |                      |
  489. *     ------------------------ <--- pTcb
  490. *     |////// 16 bytes //////|  (clobbered during objFree of taskDestroy)
  491. *     ------------------------ <--- pTaskMem
  492. *          - LOW  MEMORY -
  493. * .CE
  494. *
  495. * argument <entryPt>
  496. * The entry address is the address of the `main' routine of the task.  The
  497. * routine will be called once the C environment has been set up by
  498. * vxTaskEntry().  Should the specified main routine return, vxTaskEntry() will
  499. * automatically call exit().  The specified routine will be called with the
  500. * ten given arguments.
  501. *
  502. * See taskSpawn() for creating tasks with activation.
  503. *
  504. * See taskInit() for initializing tasks with pre-allocated stacks.
  505. *
  506. * RETURNS: Task ID, or NULL if out of memory or unable to create task.
  507. *
  508. * SEE ALSO: "Basic OS", taskInit(), taskActivate(), taskSpawn()
  509. *
  510. * VARARGS5
  511. * NOMANUAL
  512. */
  513. int taskCreat
  514.     (
  515.     char          *name,        /* name of new task (stored at pStackBase) */
  516.     int           priority,     /* priority of new task */
  517.     int           options,      /* task option word */
  518.     int           stackSize,    /* size (bytes) of stack needed */
  519.     FUNCPTR       entryPt,      /* entry point of new task */
  520.     int           arg1,         /* task argument one */
  521.     int           arg2,         /* task argument two */
  522.     int           arg3,         /* task argument three */
  523.     int           arg4,         /* task argument four */
  524.     int           arg5,         /* task argument five */
  525.     int           arg6,         /* task argument six */
  526.     int           arg7,         /* task argument seven */
  527.     int           arg8,         /* task argument eight */
  528.     int           arg9,         /* task argument nine */
  529.     int           arg10         /* task argument ten */
  530.     )
  531.     {
  532.     char newName[20]; /* place to keep name for nameless tasks */
  533.     char * pTaskMem; /* pointer to task memory */
  534.     char * pStackBase; /* bottom of stack (higher memory address) */
  535.     WIND_TCB * pTcb; /* tcb pointer */
  536.     char * pBufStart; /* points to temp name buffer start */
  537.     char * pBufEnd; /* points to temp name buffer end */
  538.     char temp; /* working character */
  539.     int value; /* working value to convert to ascii */
  540.     int nPreBytes; /* nameless prefix string length */
  541.     int nBytes   = 0; /* working nameless name string length */
  542.     static char digits [] = "0123456789";
  543.     if (name == NULL) /* name nameless w/o sprintf */
  544. {
  545. strcpy (newName, namelessPrefix); /* copy in prefix */
  546. nBytes    = strlen (newName); /* calculate prefix length */
  547. nPreBytes = nBytes; /* remember prefix strlen() */
  548. value   = ++ nameForNameless; /* bump the nameless count */
  549. do /* crank out digits backwards */
  550.     {
  551.     newName [nBytes++] = digits [value % 10];
  552.     value /= 10; /* next digit */
  553.     }
  554. while (value != 0); /* until no more digits */
  555. pBufStart = newName + nPreBytes; /* start reverse after prefix */
  556.      pBufEnd   = newName + nBytes - 1; /* end reverse at EOS */
  557. while (pBufStart < pBufEnd) /* reverse the digits */
  558.     {
  559.     temp = *pBufStart;
  560.     *pBufStart = *pBufEnd;
  561.     *pBufEnd = temp;
  562.     pBufEnd--;
  563.     pBufStart++;
  564.     }
  565. newName[nBytes] = EOS; /* EOS terminate string */
  566. name = newName; /* taskInit copies to task */
  567. }
  568. #if CPU==SIMSPARCSUNOS || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS
  569.     if (sysFlags & SYSFLG_DEBUG)
  570. stackSize *= 2;
  571. #endif /* CPU==SIMSPARCSUNOS || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS */
  572. #if     (CPU==SIMNT || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS)
  573.     /*
  574.      * SIMHPPA and SIMSPARCSOLARIS take interrupts on the current 
  575.      * task stack.
  576.      * Moreover SIMNT and SIMSPARCSOLARIS use the current task stack for 
  577.      * WINDOWS/UNIX system calls.
  578.      * Bump all task stack sizes here to compensate, this way
  579.      * when new vxWorks system tasks are added we won't need
  580.      * to constantly readjust their default stack sizes.
  581.      * Set this value to 12k which seems enough to prevent stackoverflow.
  582.      */
  583.     stackSize += 0x3000;
  584. #endif  /* CPU == SIMNT || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS */
  585.     /* round stacksize up */
  586.     stackSize = STACK_ROUND_UP (stackSize);
  587.     /* 
  588.      * Allocate the WIND_TCB object, plus additional bytes for
  589.      * the task stack from the task memory partition.
  590.      * The 16 bytes of clobbered data is accounted for in the WIND_TCB object.
  591.      */
  592.     pTaskMem = (char *) objAllocExtra
  593.          (
  594.     taskClassId,
  595.     (unsigned) (stackSize),
  596.     (void **) NULL
  597.     );
  598.     if (pTaskMem == NULL)
  599. return ((int)NULL); /* allocation failed */
  600. #if (_STACK_DIR == _STACK_GROWS_DOWN)
  601.     /*
  602.      * A portion of the very top of the stack is clobbered with a FREE_BLOCK
  603.      * in the objFree() associated with taskDestroy().  There is no adverse
  604.      * consequence of this, and is thus not accounted for.
  605.      */
  606.     pStackBase = pTaskMem + stackSize; /* grows down from WIND_TCB */
  607.     pTcb = (WIND_TCB *) pStackBase;
  608. #else /* _STACK_GROWS_UP */
  609.     /*
  610.      * To protect a portion of the WIND_TCB that is clobbered with a FREE_BLOCK
  611.      * in the objFree() associated with taskDestroy(), we goose the base of
  612.      * tcb by 16 bytes.
  613.      */
  614.     pTcb = (WIND_TCB *) (pTaskMem + 16);
  615.     pStackBase = STACK_ROUND_UP (pTaskMem + 16 + sizeof(WIND_TCB));
  616. #endif
  617.     options    |= VX_DEALLOC_STACK; /* set dealloc option bit */
  618.     if (taskInit (pTcb, name, priority, options, pStackBase, stackSize, entryPt,
  619.           arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
  620. != OK)
  621. {
  622. objFree (taskClassId, pTaskMem);
  623. return ((int)NULL);
  624. }
  625.     return ((int) pTcb); /* return task ID */
  626.     }
  627. /*******************************************************************************
  628. *
  629. * taskInit - initialize a task with a stack at a specified address
  630. *
  631. * This routine initializes user-specified regions of memory for a task stack
  632. * and control block instead of allocating them from memory as taskSpawn()
  633. * does.  This routine will utilize the specified pointers to the WIND_TCB
  634. * and stack as the components of the task.  This allows, for example, the
  635. * initialization of a static WIND_TCB variable.  It also allows for special
  636. * stack positioning as a debugging aid.
  637. *
  638. * As in taskSpawn(), a task may be given a name.  While taskSpawn()
  639. * automatically names unnamed tasks, taskInit() permits the existence of
  640. * tasks without names.  The task ID required by other task routines
  641. * is simply the address <pTcb>, cast to an integer.
  642. *
  643. * Note that the task stack may grow up or down from pStackBase, depending on
  644. * the target architecture.
  645. *
  646. * Other arguments are the same as in taskSpawn().  Unlike taskSpawn(),
  647. * taskInit() does not activate the task.  This must be done by calling
  648. * taskActivate() after calling taskInit().
  649. *
  650. * Normally, tasks should be started using taskSpawn() rather than taskInit(),
  651. * except when additional control is required for task memory allocation or
  652. * a separate task activation is desired.
  653. *
  654. * RETURNS: OK, or ERROR if the task cannot be initialized.
  655. *
  656. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_ID_ERROR,
  657. *  S_taskLib_ILLEGAL_PRIORITY
  658. *
  659. * SEE ALSO: taskActivate(), taskSpawn()
  660. *
  661. * VARARGS7
  662. */
  663. STATUS taskInit
  664.     (
  665.     FAST WIND_TCB *pTcb,        /* address of new task's TCB */
  666.     char          *name,        /* name of new task (stored at pStackBase) */
  667.     int           priority,     /* priority of new task */
  668.     int           options,      /* task option word */
  669.     char          *pStackBase,  /* base of new task's stack */
  670.     int           stackSize,    /* size (bytes) of stack needed */
  671.     FUNCPTR       entryPt,      /* entry point of new task */
  672.     int           arg1,         /* first of ten task args to pass to func */
  673.     int           arg2,
  674.     int           arg3,
  675.     int           arg4,
  676.     int           arg5,
  677.     int           arg6,
  678.     int           arg7,
  679.     int           arg8,
  680.     int           arg9,
  681.     int           arg10 
  682.     )
  683.     {
  684.     FAST int   ix; /* index for create hooks */
  685.     int        pArgs [MAX_TASK_ARGS]; /* 10 arguments to new task */
  686.     unsigned taskNameLen; /* string length of task name */
  687.     char       *taskName = NULL; /* assume nameless */
  688.     if (INT_RESTRICT () != OK) /* restrict ISR from calling */
  689. return (ERROR);
  690.     if (taskPriRangeCheck)
  691. {
  692. if ((priority & 0xffffff00) != 0) /* ! (0 <= x <= 255) */
  693.     {
  694.     errno = S_taskLib_ILLEGAL_PRIORITY;
  695.     return (ERROR);
  696.     }
  697. }
  698.     if ((!taskLibInstalled) && (taskLibInit () != OK))
  699. return (ERROR); /* package init problem */
  700.     /* get arguments into indigenous variables */
  701.     pArgs[0] = arg1; pArgs[1] = arg2; pArgs[2] = arg3; pArgs[3] = arg4;
  702.     pArgs[4] = arg5; pArgs[5] = arg6; pArgs[6] = arg7;
  703.     pArgs[7] = arg8; pArgs[8] = arg9;
  704.     pArgs[9] = arg10;
  705.     /* initialize task control block (in order) */
  706.     pTcb->options       = options; /* options */
  707.     pTcb->status = WIND_SUSPEND; /* initially suspended */
  708.     pTcb->priority = priority; /* set priority */
  709.     pTcb->priNormal = priority; /* set standard priority */
  710.     pTcb->priMutexCnt = 0; /* no mutex owned */
  711.     pTcb->pPriMutex = NULL; /* not blocked on pri mutex */
  712.     pTcb->lockCnt = 0;   /* task w/o preemption lock */
  713.     pTcb->tslice = 0; /* no round robin */
  714.     pTcb->swapInMask = 0; /* no swap-in hooks */
  715.     pTcb->swapOutMask   = 0; /* no swap-out hooks */
  716.     pTcb->pPendQ   = NULL; /* initialize ptr to pend q */
  717.     pTcb->safeCnt = 0;   /* initialize safe count */
  718.     /* initialize safety q head */
  719.     qInit (&pTcb->safetyQHead, Q_PRI_LIST, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
  720. #if ((CPU_FAMILY == ARM) && ARM_THUMB)
  721.     pTcb->entry         = (FUNCPTR)((UINT32)entryPt & ~1); /* entry address */
  722. #else
  723.     pTcb->entry         = entryPt; /* entry address */
  724. #endif
  725.     pTcb->pStackBase = pStackBase; /* initialize stack base */
  726.     pTcb->pStackLimit   = pStackBase + stackSize*_STACK_DIR;
  727.     pTcb->pStackEnd = pTcb->pStackLimit;
  728.     if (!(options & VX_NO_STACK_FILL)) /* fill w/ 0xee for checkStack*/
  729. #if (_STACK_DIR == _STACK_GROWS_DOWN)
  730. bfill (pTcb->pStackLimit, stackSize, 0xee);
  731. #else /* (_STACK_DIR == _STACK_GROWS_UP) */
  732. bfill (pTcb->pStackBase, stackSize, 0xee);
  733. #endif /* (_STACK_DIR == _STACK_GROWS_UP) */
  734.     taskRegsInit (pTcb, pStackBase); /* initialize register set */
  735.     pTcb->errorStatus   = OK; /* errorStatus */
  736.     pTcb->exitCode = OK; /* field for exit () */
  737.     pTcb->pSignalInfo   = NULL; /* ptr to signal context */
  738.     pTcb->pSelectContext= NULL; /* context not allocated yet */
  739.     pTcb->ppEnviron = NULL; /* global environment vars */
  740.     pTcb->taskTicks     = 0; /* profiling for spyLib */
  741.     pTcb->taskIncTicks  = 0; /* profiling for spyLib */
  742. #if CPU_FAMILY!=I960
  743.     pTcb->excInfo.valid = 0; /* exception info is invalid */
  744. #else /* CPU_FAMILY == I960 */
  745.     pTcb->excInfo.eiType = 0;
  746. #endif /* CPU_FAMILY!=I960 */
  747.     pTcb->pTaskVar      = NULL; /* list of task variables */
  748.     pTcb->pRPCModList = NULL; /* rpc module statics context */
  749.     pTcb->pFpContext    = NULL; /* floating point context */
  750.     pTcb->pDspContext   = NULL; /* dsp context */
  751.     for (ix = 0; ix < 3; ++ix)
  752. {
  753. pTcb->taskStd[ix]    = ix; /* stdin/stdout/stderr fds */
  754. pTcb->taskStdFp[ix]  = NULL; /* stdin/stdout/stderr fps */
  755. }
  756.     pTcb->pSmObjTcb = NULL; /* no shared TCB for now */
  757.     pTcb->windxLock = (int)NULL;
  758.     pTcb->pComLocal = NULL;
  759.     pTcb->pExcRegSet = NULL;
  760.     bzero ((char*)&(pTcb->events), sizeof(EVENTS));/* clear events structure */
  761.     pTcb->reserved1 = (int)NULL;
  762.     pTcb->reserved2 = (int)NULL;
  763.     pTcb->spare1 = (int)NULL;
  764.     pTcb->spare2 = (int)NULL;
  765.     pTcb->spare3 = (int)NULL;
  766.     pTcb->spare4 = (int)NULL;
  767.     pTcb->pPthread = NULL;
  768.    
  769.     pTcb->wdbInfo.wdbState = 0;
  770.     pTcb->wdbInfo.bpAddr = 0;
  771.     pTcb->wdbInfo.wdbExitHook = NULL;
  772.     taskArgsSet (pTcb, pStackBase, pArgs); /* initialize task arguments */
  773. #ifdef WV_INSTRUMENTATION
  774.     /* windview instrumentation */
  775.     /* windview - level 1 event logging
  776.      * The objCore has not been initialised yet so this must be done
  777.      * by hand.
  778.      */
  779.     EVT_OBJ_TASKSPAWN (EVENT_TASKSPAWN, (int) pTcb, priority,
  780.                      stackSize, (int) entryPt, options);
  781.     /* windview - The parser must be able to link a name with a task id. */
  782.     EVT_CTX_TASKINFO (EVENT_TASKNAME, WIND_SUSPEND,
  783.                        pTcb->priority, pTcb->lockCnt, (int) pTcb, name);
  784. #endif
  785.     kernelState = TRUE; /* KERNEL ENTER */
  786.     windSpawn (pTcb); /* spawn the task */
  787. #ifdef WV_INSTRUMENTATION
  788.     /* windview - connect the instrumented class for level 1 event logging */
  789.     if (wvObjIsEnabled)
  790.         objCoreInit (&pTcb->objCore, taskInstClassId);
  791.     else
  792. #endif
  793. objCoreInit (&pTcb->objCore, taskClassId); /* validate task ID */
  794.     windExit (); /* KERNEL EXIT */
  795.     if (name != NULL) /* copy name if not nameless */
  796. {
  797. taskNameLen = (unsigned) (strlen (name) + 1);
  798. taskName    = (char *) taskStackAllot ((int) pTcb, taskNameLen);
  799. strcpy (taskName, name); /* copy the name onto stack */
  800. }
  801.     pTcb->name = taskName; /* name of this task */
  802.     for (ix = 0; ix < VX_MAX_TASK_CREATE_RTNS; ++ix)
  803. {
  804. if (taskCreateTable[ix] != NULL)
  805.     (*taskCreateTable[ix]) (pTcb);
  806. }
  807.     return (OK); /* return task ID */
  808.     }
  809. /*******************************************************************************
  810. *
  811. * taskActivate - activate a task that has been initialized
  812. *
  813. * This routine activates tasks created by taskInit().  Without activation, a
  814. * task is ineligible for CPU allocation by the scheduler.
  815. * The <tid> (task ID) argument is simply the address of the WIND_TCB
  816. * for the task (the taskInit() <pTcb> argument), cast to an integer:
  817. * .CS
  818. * tid = (int) pTcb;
  819. * .CE
  820. *
  821. * The taskSpawn() routine is built from taskActivate() and taskInit().
  822. * Tasks created by taskSpawn() do not require explicit task activation.
  823. *
  824. * RETURNS: OK, or ERROR if the task cannot be activated.
  825. *
  826. * SEE ALSO: taskInit()
  827. */
  828. STATUS taskActivate
  829.     (
  830.     int tid                     /* task ID of task to activate */
  831.     )
  832.     {
  833.     return (taskResume (tid)); /* taskActivate == taskResume */
  834.     }
  835. /*******************************************************************************
  836. *
  837. * exit - exit a task  (ANSI)
  838. *
  839. * This routine is called by a task to cease to exist as a task.  It is
  840. * called implicitly when the "main" routine of a spawned task is exited.
  841. * The <code> parameter will be stored in the WIND_TCB for
  842. * possible use by the delete hooks, or post-mortem debugging.
  843. *
  844. * ERRNO:  N/A
  845. *
  846. * SEE ALSO: taskDelete(),
  847. * .I "American National Standard for Information Systems -"
  848. * .I "Programming Language - C, ANSI X3.159-1989: Input/Output (stdlib.h),"
  849. * .pG "Basic OS"
  850. */
  851. void exit
  852.     (
  853.     int code            /* code stored in TCB for delete hooks */
  854.     )
  855.     {
  856.     taskIdCurrent->exitCode = code; /* store the exit code */
  857.     taskLock (); /* LOCK PREEMPTION */
  858.     taskIdCurrent->options |= VX_UNBREAKABLE; /* mark as unbreakable */
  859.     if (taskBpHook != NULL) /* call the debugger hook */
  860. (* taskBpHook) (taskIdCurrent); /* to remove all breakpoints */
  861.     taskUnlock (); /* UNLOCK PREEMPTION */
  862.     taskDestroy (0, TRUE, WAIT_FOREVER, FALSE); /* self destruct */
  863.     }
  864. /*******************************************************************************
  865. *
  866. * taskDelete - delete a task
  867. *
  868. * This routine causes a specified task to cease to exist and deallocates the
  869. * stack and WIND_TCB memory resources.  Upon deletion, all routines specified
  870. * by taskDeleteHookAdd() will be called in the context of the deleting task.
  871. * This routine is the companion routine to taskSpawn().
  872. *
  873. * RETURNS: OK, or ERROR if the task cannot be deleted.
  874. *
  875. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_DELETED
  876. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_ID_ERROR
  877. *
  878. * SEE ALSO: excLib, taskDeleteHookAdd(), taskSpawn(),
  879. * .pG "Basic OS"
  880. */
  881. STATUS taskDelete
  882.     (
  883.     int tid                     /* task ID of task to delete */
  884.     )
  885.     {
  886.     return (taskDestroy (tid, TRUE, WAIT_FOREVER, FALSE));
  887.     }
  888. /*******************************************************************************
  889. *
  890. * taskDeleteForce - delete a task without restriction
  891. *
  892. * This routine deletes a task even if the task is protected from deletion.  
  893. * It is similar to taskDelete().  Upon deletion, all routines
  894. * specified by taskDeleteHookAdd() will be called in the context of the
  895. * deleting task.
  896. *
  897. * CAVEATS
  898. * This routine is intended as a debugging aid, and is generally inappropriate
  899. * for applications.  Disregarding a task's deletion protection could leave the
  900. * the system in an unstable state or lead to system deadlock.
  901. *
  902. * The system does not protect against simultaneous taskDeleteForce() calls.
  903. * Such a situation could leave the system in an unstable state.
  904. *
  905. * RETURNS: OK, or ERROR if the task cannot be deleted.
  906. *
  907. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_DELETED,
  908. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_ID_ERROR
  909. *
  910. * SEE ALSO: taskDeleteHookAdd(), taskDelete()
  911. */
  912. STATUS taskDeleteForce
  913.     (
  914.     int tid                     /* task ID of task to delete */
  915.     )
  916.     {
  917.     return (taskDestroy (tid, TRUE, WAIT_FOREVER, TRUE));
  918.     }
  919. /*******************************************************************************
  920. *
  921. * taskTerminate - terminate a task
  922. *
  923. * This routine causes a task to cease to exist but does not deallocate the
  924. * stack or WIND_TCB memory.  During termination, all routines specified by
  925. * taskDeleteHookAdd() will be called in the context of the deleting task.
  926. * This routine serves as the companion routine to taskInit().  To delete a
  927. * task created by taskSpawn(), see taskDelete().
  928. *
  929. * If a task attempts to terminate itself, the termination and the delete hooks
  930. * are performed in the context of the exception task.
  931. *
  932. * RETURNS: OK, or ERROR if task cannot be terminated.
  933. *
  934. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_DELETED,
  935. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_ID_ERROR
  936. *
  937. * SEE ALSO: excLib, taskDeleteHookAdd(), taskDelete(),
  938. * .pG "Basic OS"
  939. *
  940. * NOMANUAL
  941. */
  942. STATUS taskTerminate
  943.     (
  944.     int tid                     /* task ID of task to delete */
  945.     )
  946.     {
  947.     return (taskDestroy (tid, FALSE, WAIT_FOREVER, FALSE));
  948.     }
  949. /*******************************************************************************
  950. *
  951. * taskDestroy - destroy a task
  952. *
  953. * This routine causes the specified task to cease to exist and, if successful,
  954. * optionally frees the memory associated with the task's stack and
  955. * WIND_TCB.  This call forms the foundation to the routines taskDelete() and
  956. * taskTerminate().  Upon destruction, all routines specified by
  957. * taskDeleteHookAdd() will be called in the context of the destroying task.
  958. *
  959. * If a task attempts to destroy itself, the destruction and the delete hooks
  960. * are performed in the context of the exception task.
  961. *
  962. * RETURNS: OK, or ERROR if task cannot be destroyed.
  963. *
  964. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_DELETED,
  965. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_ID_ERROR
  966. *
  967. * SEE ALSO: excLib, taskDeleteHookAdd(), taskTerminate(), taskDelete()
  968. *
  969. * NOMANUAL
  970. */
  971. STATUS taskDestroy
  972.     (
  973.     int  tid,                   /* task ID of task to delete */
  974.     BOOL dealloc,               /* deallocate associated memory */
  975.     int  timeout,               /* time willing to wait */
  976.     BOOL forceDestroy           /* force deletion if protected */
  977.     )
  978.     {
  979.     FAST int   ix; /* delete hook index */
  980.     FAST WIND_TCB *pTcb; /* convenient pointer to WIND_TCB */
  981.     FAST int      lock; /* to lock interrupts */
  982.     int   status; /* windDelete return status */
  983.     if (INT_RESTRICT () != OK) /* no ISR use */
  984. return (ERROR);
  985.     if (tid == 0)
  986. pTcb = taskIdCurrent; /* suicide */
  987.     else
  988. pTcb = (WIND_TCB *) tid; /* convenient pointer */
  989. #ifdef WV_INSTRUMENTATION
  990.     /* windview - level 1 event logging */
  991.     EVT_OBJ_2 (TASK, pTcb, taskClassId, EVENT_TASKDESTROY, pTcb, pTcb->safeCnt);
  992. #endif
  993.     if ((pTcb == taskIdCurrent) && (_func_excJobAdd != NULL))
  994. {
  995. /* If exception task is available, delete task from its context.
  996.  * While suicides are supported without an exception task, it seems
  997.  * safer to utilize another context for deletion.
  998.  */
  999. while (pTcb->safeCnt > 0) /* make task unsafe */
  1000.     TASK_UNSAFE ();
  1001. _func_excJobAdd (taskDestroy, (int)pTcb, dealloc, NO_WAIT, FALSE);
  1002. FOREVER
  1003.     taskSuspend (0); /* wait to die */
  1004. }
  1005. again:
  1006.     lock = intLock (); /* LOCK INTERRTUPTS */
  1007.     if (TASK_ID_VERIFY (pTcb) != OK) /* valid task ID? */
  1008. {
  1009. intUnlock (lock); /* UNLOCK INTERRUPTS */
  1010. return (ERROR);
  1011. }
  1012.     /*
  1013.      * Mask all signals of pTcb (may be suicide)
  1014.      * This is the same as calling sigfillset(&pTcb->pSignalInfo->sigt_blocked)
  1015.      * without the call to sigLib
  1016.      */
  1017.     if (pTcb->pSignalInfo != NULL)
  1018. pTcb->pSignalInfo->sigt_blocked = 0xffffffff;
  1019.     while ((pTcb->safeCnt > 0) ||
  1020.    ((pTcb->status == WIND_READY) && (pTcb->lockCnt > 0)))
  1021. {
  1022. kernelState = TRUE; /* KERNEL ENTER */
  1023. intUnlock (lock); /* UNLOCK INTERRUPTS */
  1024. if ((forceDestroy) || (pTcb == taskIdCurrent))
  1025.     {
  1026.     pTcb->safeCnt = 0; /* unprotect */
  1027.     pTcb->lockCnt = 0; /* unlock */
  1028.     if (Q_FIRST (&pTcb->safetyQHead) != NULL) /* flush safe queue */
  1029.                 {
  1030. #ifdef WV_INSTRUMENTATION
  1031.                 /* windview - level 2 event logging */
  1032.                 EVT_TASK_1 (EVENT_OBJ_TASK, pTcb);
  1033. #endif
  1034.                 windPendQFlush (&pTcb->safetyQHead);
  1035.                 }
  1036.     windExit (); /* KERNEL EXIT */
  1037.     }
  1038. else /* wait to destroy */
  1039.     {
  1040. #ifdef WV_INSTRUMENTATION
  1041.             /* windview - level 2 event logging */
  1042.             EVT_TASK_1 (EVENT_OBJ_TASK, pTcb);  /* log event */
  1043. #endif
  1044.     if (windPendQPut (&pTcb->safetyQHead, timeout) != OK)
  1045. {
  1046. windExit (); /* KERNEL EXIT */
  1047. return (ERROR);
  1048. }
  1049.     switch (windExit())
  1050. {
  1051. case RESTART :
  1052.     /* Always go back and reverify, this is because we have
  1053.      * been running in a signal handler for who knows how long.
  1054.      */
  1055.     timeout = SIG_TIMEOUT_RECALC(timeout);
  1056.     goto again;
  1057. case ERROR : /* timed out */
  1058.     return (ERROR);
  1059. default : /* we were flushed */
  1060.     break;
  1061. }
  1062.     /* All deleters of safe tasks block here.  When the safeCnt goes
  1063.      * back to zero (or we taskUnlock) the deleters will be unblocked
  1064.      * and the highest priority task among them will be elected to
  1065.      * complete the deletion.  All unelected deleters will ultimately
  1066.      * find the ID invalid, and return ERROR when they proceed from
  1067.      * here.  The complete algorithm is summarized below.
  1068.      */
  1069.      }
  1070. lock = intLock (); /* LOCK INTERRTUPTS */
  1071. if (TASK_ID_VERIFY (pTcb) != OK)
  1072.     {
  1073.     intUnlock (lock); /* UNLOCK INTERRUPTS */
  1074.     errno = S_objLib_OBJ_DELETED;
  1075.     return (ERROR);
  1076.     }
  1077. }
  1078.     /* We can now assert that one and only one task has been elected to
  1079.      * perform the actual deletion.  The elected task may even be the task
  1080.      * to be deleted in the case of suicide.  To guarantee all other tasks
  1081.      * flushed from the safe queue receive an ERROR notification, the
  1082.      * elected task reprotects the victim from deletion.
  1083.      * 
  1084.      * A task flushed from the safe queue checks if the task ID is invalid,
  1085.      * which would mean the deletion is completed.  If, on the other hand,
  1086.      * the task ID is valid, one of two possibilities exist.  One outcome is
  1087.      * the flushed task performs the test condition in the while statement
  1088.      * above and finds the safe count equal to zero.  In this case the
  1089.      * flushed task is the elected deleter.
  1090.      * 
  1091.      * The second case is that the safe count is non-zero.  The only way the
  1092.      * safe count can be non zero after being flushed from the delete queue
  1093.      * is if the elected deleter blocked before completing the deletion or
  1094.      * the victim managed to legitimately taskSafe() itself in one way or
  1095.      * another.  A deleter can block because before performing the deletion
  1096.      * and hence task ID invalidation, the deleter must call the delete
  1097.      * hooks that possibly deallocate memory which involves taking a
  1098.      * semaphore.  So observe that nothing prevents the deleter from being
  1099.      * preempted by some other task which might also try a deletion on the
  1100.      * same victim.  We need not account for this case in any special way
  1101.      * because the task will atomically find the ID valid but the safe count
  1102.      * non zero and thus block on the safe queue.  It is therefore
  1103.      * impossible for two deletions to occur on the same task being killed
  1104.      * by one or more deleters.
  1105.      * 
  1106.      * We must also protect the deleter from being deleted by utilizing
  1107.      * taskSafe().  When a safe task is deleting itself the safe count is
  1108.      * set equal to zero, and other deleters are flushed from the safe
  1109.      * queue.  From this point on the algorithm remains the same.
  1110.      * 
  1111.      * The only special problem a suicide presents is deallocating the
  1112.      * memory associated with the task.  When we free the memory, we must
  1113.      * prevent any preemption from occuring, thus opening up an opportunity
  1114.      * for the memory to be allocated out from under us and corrupted.  We
  1115.      * lock preemption before the objFree() call.  The task may block
  1116.      * waiting for the partition, but once access is gained no further
  1117.      * preemption will occur.  An alternative to locking preemption is to
  1118.      * lock the partition by taking the partition's semaphore.  If the
  1119.      * partition utilizes mutex semaphores which permit recursive access, this
  1120.      * alternative seems attractive.  However, the memory manager will utilize
  1121.      * binary semaphores when scaled down.  With a fixed duration memPartFree()
  1122.      * algorithm, a taskLock() does not seem excessive compared to a more
  1123.      * intimate coupling with memPartLib.
  1124.      * 
  1125.      * One final complication exists before task invalidation and kernel
  1126.      * queue removal can be completed.  If we enter the kernel and
  1127.      * invalidate the task ID, there is a brief opportunity for an ISR to
  1128.      * add work to the kernel work queue referencing the soon to be defunct
  1129.      * task ID.  To prevent this we lock interrupts before invalidating the
  1130.      * task ID, and then enter the kernel.  Conclusion of the algorithm
  1131.      * consists of removing the task from the kernel queues, flushing the
  1132.      * unelected deleters to receive ERROR notification, exiting the kernel,
  1133.      * and finally restoring the deleter to its original state with
  1134.      * taskUnsafe(), and taskUnlock().
  1135.      */
  1136.     TASK_SAFE (); /* protect deleter */
  1137.     pTcb->safeCnt ++; /* reprotect victim */
  1138.     if (pTcb != taskIdCurrent) /* if not a suicide */
  1139. {
  1140. kernelState = TRUE; /* ENTER KERNEL */
  1141. intUnlock (lock); /* UNLOCK INTERRUPTS */
  1142. windSuspend (pTcb); /* suspend victim */
  1143. windExit (); /* EXIT KERNEL */
  1144. }
  1145.     else
  1146. intUnlock (lock); /* UNLOCK INTERRUPTS */
  1147.     /* run the delete hooks in the context of the deleting task */
  1148.     for (ix = 0; ix < VX_MAX_TASK_DELETE_RTNS; ++ix)
  1149. if (taskDeleteTable[ix] != NULL)
  1150.     (*taskDeleteTable[ix]) (pTcb);
  1151.     TASK_LOCK (); /* LOCK PREEMPTION */
  1152.     if ((dealloc) && (pTcb->options & VX_DEALLOC_STACK))
  1153.         {
  1154. if (pTcb == (WIND_TCB *) rootTaskId)
  1155.     memAddToPool (pRootMemStart, rootMemNBytes);/* add root into pool */
  1156. else
  1157. #if  (_STACK_DIR == _STACK_GROWS_DOWN)
  1158.     /*
  1159.      * A portion of the very top of the stack is clobbered with a
  1160.      * FREE_BLOCK in the objFree() associated with taskDestroy(). 
  1161.      * There is no adverse consequence of this, and is thus not 
  1162.      * accounted for.
  1163.      */
  1164.     objFree (taskClassId, pTcb->pStackEnd);
  1165. #else /* _STACK_GROWS_UP */
  1166.     /*
  1167.      * To protect a portion of the WIND_TCB that is clobbered with a
  1168.      * FREE_BLOCK in this objFree() we previously goosed up the base of
  1169.      * tcb by 16 bytes.
  1170.      */
  1171.     objFree (taskClassId, (char *) pTcb - 16);
  1172. #endif
  1173. }
  1174.     lock = intLock (); /* LOCK INTERRUPTS */
  1175.     objCoreTerminate (&pTcb->objCore); /* INVALIDATE TASK */
  1176.     kernelState = TRUE; /* KERNEL ENTER */
  1177.     intUnlock (lock); /* UNLOCK INTERRUPTS */
  1178.     status = windDelete (pTcb); /* delete task */
  1179.     /* 
  1180.      * If the task being deleted is the last Fp task from fppSwapHook then
  1181.      * reset pTaskLastFpTcb. 
  1182.      */
  1183.     if (pTcb == pTaskLastFpTcb)
  1184.      pTaskLastFpTcb = NULL;
  1185.     /*
  1186.      * If the task being deleted is the last DSP task from dspSwapHook then
  1187.      * reset pTaskLastDspTcb.
  1188.      */
  1189.     if (pTcb == pTaskLastDspTcb)
  1190.      pTaskLastDspTcb = NULL;
  1191. #ifdef _WRS_ALTIVEC_SUPPORT
  1192.     /*
  1193.      * If the task being deleted is the last Altivec task from 
  1194.      * altivecSwapHook then reset pTaskLastAltivecTcb.
  1195.      */
  1196.     if (pTcb == pTaskLastAltivecTcb)
  1197.         pTaskLastAltivecTcb = NULL;
  1198. #endif /* _WRS_ALTIVEC_SUPPORT */
  1199.     /*
  1200.      * Now if the task has used shared memory objects the following 
  1201.      * can happen :
  1202.      *
  1203.      * 1) windDelete has return OK indicating that the task 
  1204.      * was not pending on a shared semaphore or was pending on a
  1205.      * shared semaphore but its shared TCB has been removed from the
  1206.      * shared semaphore pendQ.  In that case we simply give the 
  1207.      * shared TCB back to the shared TCB partition.
  1208.      * If an error occurs while giving back the shared TCB a warning
  1209.      * message in sent to the user saying the shared TCB is lost.
  1210.      *
  1211.      * 2) windDelete has return ALREADY_REMOVED indicating that the task
  1212.      * was pending on a shared semaphore but its shared TCB has already
  1213.      * been removed from the shared semaphore pendQ by another CPU.
  1214.      * Its shared TCB is now in this CPU event list but has not yet
  1215.      * shown-up.  In that case we don't free the shared TCB now since
  1216.      * it will screw up the CPU event list, the shared TCB will be freed
  1217.      * by smObjEventProcess when it will show-up.
  1218.      *
  1219.      * 3) This is the worst case, windDelete has return ERROR
  1220.      * indicating that the task was pending on a shared semaphore 
  1221.      * and qFifoRemove has failed when trying to get the lock to
  1222.      * the shared semaphore structure.
  1223.      * In that case the shared semaphore pendQ is in an inconsistant
  1224.      * state because it still contains a shared TCB of task which
  1225.      * no longer exist.  We send a message to the user saying
  1226.      * that access to a shared structure has failed.
  1227.      */
  1228.      /* no failure notification until we have a better solution */
  1229.     if (pTcb->pSmObjTcb != NULL) /* sm tcb to free? */
  1230. {
  1231. if (status == OK)
  1232.     { /* free sm tcb */
  1233.     (*smObjTcbFreeRtn) (pTcb->pSmObjTcb);
  1234.     }
  1235. }
  1236.     if (Q_FIRST (&pTcb->safetyQHead) != NULL) /*flush any deleters */
  1237.         {
  1238. #ifdef WV_INSTRUMENTATION
  1239.         /* windview - level 2 event logging */
  1240.         EVT_TASK_1 (EVENT_OBJ_TASK, pTcb);      /* log event */
  1241. #endif
  1242.         windPendQFlush (&pTcb->safetyQHead);
  1243.         }
  1244.     windExit (); /* KERNEL EXIT */
  1245.     /* we won't get here if we committed suicide */
  1246.     taskUnlock (); /* UNLOCK PREEMPTION */
  1247.     taskUnsafe (); /* TASK UNSAFE */
  1248.     return (OK);
  1249.     }
  1250. /*******************************************************************************
  1251. *
  1252. * taskSuspend - suspend a task
  1253. *
  1254. * This routine suspends a specified task.  A task ID of zero results in
  1255. * the suspension of the calling task.  Suspension is additive, thus tasks
  1256. * can be delayed and suspended, or pended and suspended.  Suspended, delayed
  1257. * tasks whose delays expire remain suspended.  Likewise, suspended,
  1258. * pended tasks that unblock remain suspended only.
  1259. *
  1260. * Care should be taken with asynchronous use of this facility.  The specified
  1261. * task is suspended regardless of its current state.  The task could, for
  1262. * instance, have mutual exclusion to some system resource, such as the network * or system memory partition.  If suspended during such a time, the facilities
  1263. * engaged are unavailable, and the situation often ends in deadlock.
  1264. *
  1265. * This routine is the basis of the debugging and exception handling packages.
  1266. * However, as a synchronization mechanism, this facility should be rejected 
  1267. * in favor of the more general semaphore facility.
  1268. *
  1269. * RETURNS: OK, or ERROR if the task cannot be suspended.
  1270. *
  1271. * ERRNO: S_objLib_OBJ_ID_ERROR
  1272. *
  1273. */
  1274. STATUS taskSuspend
  1275.     (
  1276.     int tid             /* task ID of task to suspend */
  1277.     )
  1278.     {
  1279. #ifdef WV_INSTRUMENTATION
  1280.     int realTid = (tid == 0 ? (int) taskIdCurrent : tid);
  1281.     /* windview - level 1 event logging */
  1282.     EVT_OBJ_1 (TASK, (WIND_TCB *)realTid, taskClassId, EVENT_TASKSUSPEND, realTid);
  1283. #endif
  1284.     if (kernelState) /* defer work if in kernel */
  1285. {
  1286. if ((tid == 0) || (TASK_ID_VERIFY ((void *)tid) != OK))
  1287.     return (ERROR);
  1288. workQAdd1 ((FUNCPTR)windSuspend, tid); /* add work to kernel work q */
  1289. return (OK);
  1290. }
  1291.     if (tid == 0)
  1292. tid = (int) taskIdCurrent;
  1293.     kernelState = TRUE; /* KERNEL ENTER */
  1294.     if (TASK_ID_VERIFY ((void *)tid) != OK) /* verify task */
  1295. {
  1296. windExit (); /* KERNEL EXIT */
  1297. return (ERROR);
  1298. }
  1299.     windSuspend ((WIND_TCB *) tid); /* suspend a task */
  1300.     windExit (); /* KERNEL EXIT */
  1301.     return (OK);
  1302.     }
  1303. /*******************************************************************************
  1304. *
  1305. * taskResume - resume a task
  1306. *
  1307. * This routine resumes a specified task.  Suspension is cleared, and
  1308. * the task operates in the remaining state.
  1309. *
  1310. * RETURNS: OK, or ERROR if the task cannot be resumed.
  1311. *
  1312. * ERRNO: S_objLib_OBJ_ID_ERROR
  1313. *
  1314. */
  1315. STATUS taskResume
  1316.     (
  1317.     int tid                     /* task ID of task to resume */
  1318.     )
  1319.     {
  1320. #ifdef WV_INSTRUMENTATION
  1321.     /* windview - level 1 event logging */
  1322.     EVT_OBJ_2 (TASK, (WIND_TCB *)tid, taskClassId,
  1323.        EVENT_TASKRESUME, tid, ((WIND_TCB *)tid)->priority);
  1324. #endif
  1325.     if (kernelState) /* defer work if in kernel */
  1326. {
  1327. if ((tid == 0) || (TASK_ID_VERIFY ((void *)tid) != OK))
  1328.     return (ERROR);
  1329. #if CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS
  1330. bzero ((char *) &((WIND_TCB *) tid)->excInfo, sizeof (EXC_INFO));
  1331. #endif /* CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS */
  1332. workQAdd1 ((FUNCPTR)windResume, tid); /* add work to kernel work q */
  1333. return (OK);
  1334. }
  1335.     if (tid == 0) /* zero is calling task */
  1336. return (OK); /* presumably we're running */
  1337.     kernelState = TRUE; /* KERNEL ENTER */
  1338.     if (TASK_ID_VERIFY ((void *)tid) != OK) /* check for invalid ID */
  1339. {
  1340. windExit (); /* KERNEL EXIT */
  1341. return (ERROR);
  1342. }
  1343. #if CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS
  1344. bzero ((char *) &((WIND_TCB *) tid)->excInfo, sizeof (EXC_INFO));
  1345. #endif /* CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS */
  1346.     windResume ((WIND_TCB *) tid); /* resume task */
  1347.     windExit (); /* KERNEL EXIT */
  1348.     return (OK);
  1349.     }
  1350. /*******************************************************************************
  1351. *
  1352. * taskRestart - restart a task
  1353. *
  1354. * This routine "restarts" a task.  The task is first terminated, and then
  1355. * reinitialized with the same ID, priority, options, original entry point,
  1356. * stack size, and parameters it had when it was terminated.  Self-restarting
  1357. * of a calling task is performed by the exception task.  The shell utilizes
  1358. * this routine to restart itself when aborted.
  1359. *
  1360. * NOTE
  1361. * If the task has modified any of its start-up parameters, the restarted
  1362. * task will start with the changed values.
  1363. *
  1364. * RETURNS: OK, or ERROR if the task ID is invalid
  1365. * or the task could not be restarted.
  1366. *
  1367. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_DELETED,
  1368. *        S_objLib_OBJ_UNAVAILABLE, S_objLib_OBJ_ID_ERROR,
  1369. *        S_smObjLib_NOT_INITIALIZED, S_memLib_NOT_ENOUGH_MEMORY,
  1370. *        S_memLib_BLOCK_ERROR, S_taskLib_ILLEGAL_PRIORITY
  1371. *
  1372. */
  1373. STATUS taskRestart
  1374.     (
  1375.     int tid                     /* task ID of task to restart */
  1376.     )
  1377.     {
  1378.     char *name; /* task name */
  1379.     ULONG priority; /* priority of task */
  1380.     int options; /* task options */
  1381.     char *pStackBase; /* bottom of stack */
  1382.     int stackSize; /* stack size */
  1383.     FUNCPTR entry; /* entry point of task */
  1384.     int pArgs[MAX_TASK_ARGS]; /* task's arguments */
  1385.     BOOL error; /* TRUE if ERROR */
  1386.     char *rename = NULL; /* place to keep rename */
  1387.     int sizeName; /* size of task name */
  1388.     WIND_TCB *pTcb; /* pointer to task control block */
  1389.     if (INT_RESTRICT () != OK) /* no ISR use */
  1390. return (ERROR);
  1391.     if ((tid == 0) || (tid == (int)taskIdCurrent))
  1392. {
  1393. /* self restart not possible because we have we have no context
  1394.  * from which to sucessfully terminate or reinitialize ourself.
  1395.  * We defer all self restarts to the exception task.
  1396.  * To self restart within a critical section, we must TASK_UNSAFE ()
  1397.  * until the safeCnt == 0.  Otherwise, the excTask would block
  1398.  * forever trying to terminate us.
  1399.  */
  1400. while (taskIdCurrent->safeCnt > 0) /* make task unsafe */
  1401.     TASK_UNSAFE ();
  1402. #if CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS
  1403. bzero ((char *) &taskIdCurrent->excInfo, sizeof (EXC_INFO));
  1404. #endif /* CPU==SIMSPARCSUNOS || CPU==SIMSPARCSOLARIS */
  1405. taskSpawn (restartTaskName, restartTaskPriority, restartTaskOptions,
  1406.    restartTaskStackSize, taskRestart, (int) taskIdCurrent,
  1407.    0, 0, 0, 0, 0, 0, 0, 0, 0);
  1408. FOREVER
  1409.     taskSuspend (0); /* wait for restart */
  1410. }
  1411.     /* the rest of this routine will only be executed by a task other than
  1412.      * the one being restarted.
  1413.      */
  1414.     if ((pTcb = taskTcb (tid)) == NULL) /* valid task ID? */
  1415. return (ERROR);
  1416.     priority    = pTcb->priNormal; /* get the normal priority */
  1417.     options = pTcb->options; /* get the current options */
  1418.     entry = pTcb->entry; /* get the entry point */
  1419.     pStackBase = pTcb->pStackBase; /* get the bottom of stack */
  1420.     stackSize = (pTcb->pStackEnd - pTcb->pStackBase)*_STACK_DIR;
  1421.     taskArgsGet (pTcb, pStackBase, pArgs); /* get the arguments */
  1422.     /* If task was named, its name was alloted from the task stack.  So we
  1423.      * get a local copy from the stack so it won't be clobbered during task
  1424.      * initialization.
  1425.      */
  1426.     if ((name = pTcb->name) != NULL)
  1427. {
  1428. sizeName = strlen(name) + 1;
  1429. rename = malloc(sizeName);
  1430. if (rename != NULL)
  1431.     strcpy (rename, name); /* copy out name */
  1432. name = rename; /* name points at name copy */
  1433. }
  1434.     TASK_SAFE (); /* TASK SAFE */
  1435.     if (taskTerminate (tid) != OK) /* terminate the task */
  1436. {
  1437. TASK_UNSAFE (); /* TASK UNSAFE */
  1438. return (ERROR);
  1439. }
  1440.     /* Reinitialize task with original name, stack, priority, options,
  1441.      * arguments, and entry point.  Then activate it.
  1442.      */
  1443. #if CPU==SIMSPARCSUNOS || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS
  1444.     bzero ((char *) &pTcb->excInfo, sizeof (EXC_INFO));
  1445. #endif /* CPU==SIMSPARCSUNOS || CPU==SIMHPPA || CPU==SIMSPARCSOLARIS */
  1446.     error = ((taskInit (pTcb, name, (int)priority, options, pStackBase,
  1447. stackSize, entry, pArgs[0], pArgs[1], pArgs[2],
  1448. pArgs[3], pArgs[4], pArgs[5], pArgs[6], pArgs[7],
  1449. pArgs[8], pArgs[9]) != OK) ||
  1450.      (taskActivate ((int) pTcb) != OK));
  1451.     TASK_UNSAFE (); /* TASK UNSAFE */
  1452.     free (rename);
  1453.     return ((error) ? ERROR : OK);
  1454.     }
  1455. /*******************************************************************************
  1456. *
  1457. * taskPrioritySet - change the priority of a task
  1458. *
  1459. * This routine changes a task's priority to a specified priority.
  1460. * Priorities range from 0, the highest priority, to 255, the lowest priority.
  1461. *
  1462. * RETURNS: OK, or ERROR if the task ID is invalid.
  1463. *
  1464. * ERRNO: S_taskLib_ILLEGAL_PRIORITY, S_objLib_OBJ_ID_ERROR
  1465. *
  1466. * SEE ALSO: taskPriorityGet()
  1467. */
  1468. STATUS taskPrioritySet
  1469.     (
  1470.     int tid,                    /* task ID */
  1471.     int newPriority             /* new priority */
  1472.     )
  1473.     {
  1474. #ifdef WV_INSTRUMENTATION
  1475.     int realTid = (tid == 0 ? (int) taskIdCurrent : tid);
  1476.     /* windview - level 1 event logging */
  1477.     EVT_OBJ_3 (TASK, (WIND_TCB *)realTid, taskClassId, EVENT_TASKPRIORITYSET,
  1478. realTid, newPriority, ((WIND_TCB *)realTid)->priority);
  1479. #endif
  1480.     /* make sure priority is in range 0-255 */
  1481.     if (taskPriRangeCheck)
  1482. {
  1483.         if ((newPriority & 0xffffff00) != 0) /* ! (0 <= x <= 255) */
  1484.     {
  1485.     errno = S_taskLib_ILLEGAL_PRIORITY;
  1486.     return (ERROR);
  1487.     }
  1488. }
  1489.     if (kernelState) /* already in kernel? */
  1490.         {
  1491. if ((tid == 0) ||
  1492.     (TASK_ID_VERIFY ((void *)tid) != OK)) /* verify task ID */
  1493.     return (ERROR);
  1494.         workQAdd2 ((FUNCPTR)windPriNormalSet, tid, newPriority);
  1495. return (OK);
  1496. }
  1497.     if (tid == 0)
  1498. tid = (int) taskIdCurrent;
  1499.     kernelState = TRUE; /* KERNEL ENTER */
  1500.     if (TASK_ID_VERIFY ((void *)tid) != OK) /* verify task ID */
  1501. {
  1502. windExit (); /* KERNEL EXIT */
  1503. return (ERROR);
  1504. }
  1505.     windPriNormalSet ((WIND_TCB *) tid, (UINT) newPriority);
  1506.     windExit (); /* KERNEL EXIT */
  1507.     return (OK);
  1508.     }
  1509. /*******************************************************************************
  1510. *
  1511. * taskPriorityGet - examine the priority of a task
  1512. *
  1513. * This routine determines the current priority of a specified task.
  1514. * The current priority is copied to the integer pointed to by <pPriority>.
  1515. *
  1516. * RETURNS: OK, or ERROR if the task ID is invalid.
  1517. *
  1518. * ERRNO: S_objLib_OBJ_ID_ERROR
  1519. *
  1520. * SEE ALSO: taskPrioritySet()
  1521. */
  1522. STATUS taskPriorityGet
  1523.     (
  1524.     int tid,                    /* task ID */
  1525.     int *pPriority              /* return priority here */
  1526.     )
  1527.     {
  1528.     WIND_TCB *pTcb = taskTcb (tid);
  1529.     if (pTcb == NULL) /* invalid task ID */
  1530. return (ERROR);
  1531.     *pPriority = (int) pTcb->priority;
  1532.     return (OK);
  1533.     }
  1534. /*******************************************************************************
  1535. *
  1536. * taskLock - disable task rescheduling
  1537. *
  1538. * This routine disables task context switching.  The task that calls this
  1539. * routine will be the only task that is allowed to execute, unless the task
  1540. * explicitly gives up the CPU by making itself no longer ready.  Typically
  1541. * this call is paired with taskUnlock(); together they surround a critical
  1542. * section of code.  These preemption locks are implemented with a counting
  1543. * variable that allows nested preemption locks.  Preemption will not be
  1544. * unlocked until taskUnlock() has been called as many times as taskLock().
  1545. *
  1546. * This routine does not lock out interrupts; use intLock() to lock out
  1547. * interrupts.
  1548. *
  1549. * A taskLock() is preferable to intLock() as a means of mutual exclusion,
  1550. * because interrupt lock-outs add interrupt latency to the system.
  1551. *
  1552. * A semTake() is preferable to taskLock() as a means of mutual exclusion,
  1553. * because preemption lock-outs add preemptive latency to the system.
  1554. *
  1555. * The taskLock() routine is not callable from interrupt service routines.
  1556. *
  1557. * RETURNS: OK or ERROR.
  1558. *
  1559. * ERRNO: S_objLib_OBJ_ID_ERROR, S_intLib_NOT_ISR_CALLABLE
  1560. *
  1561. * SEE ALSO: taskUnlock(), intLock(), taskSafe(), semTake()
  1562. */
  1563. STATUS taskLock (void)
  1564.     {
  1565.     TASK_LOCK(); /* increment lock cnt */
  1566.     return (OK);
  1567.     }
  1568. /*******************************************************************************
  1569. *
  1570. * taskUnlock - enable task rescheduling
  1571. *
  1572. * This routine decrements the preemption lock count.  Typically this call is
  1573. * paired with taskLock() and concludes a critical section of code.
  1574. * Preemption will not be unlocked until taskUnlock() has been called as many
  1575. * times as taskLock().  When the lock count is decremented to zero, any tasks
  1576. * that were eligible to preempt the current task will execute.
  1577. *
  1578. * The taskUnlock() routine is not callable from interrupt service routines.
  1579. *
  1580. * RETURNS: OK or ERROR.
  1581. *
  1582. * ERRNO: S_intLib_NOT_ISR_CALLABLE
  1583. *
  1584. * SEE ALSO: taskLock()
  1585. */
  1586. STATUS taskUnlock (void)
  1587.     {
  1588.     FAST WIND_TCB *pTcb = taskIdCurrent;
  1589. #ifdef WV_INSTRUMENTATION
  1590.     /* windview - level 3 event logging */
  1591.     EVT_CTX_0 (EVENT_TASKUNLOCK);
  1592. #endif
  1593.     if ((pTcb->lockCnt > 0) && ((-- pTcb->lockCnt) == 0)) /* unlocked? */
  1594. {
  1595. kernelState = TRUE; /* KERNEL ENTER */
  1596. if ((Q_FIRST (&pTcb->safetyQHead) != NULL) && (pTcb->safeCnt == 0))
  1597.             {
  1598. #ifdef WV_INSTRUMENTATION
  1599.     /* windview - level 2 event logging */
  1600.     EVT_TASK_1 (EVENT_OBJ_TASK, pTcb); /* log event */
  1601. #endif
  1602.             windPendQFlush (&pTcb->safetyQHead);        /* flush safe queue */
  1603.             }
  1604. windExit (); /* KERNEL EXIT */
  1605. }
  1606.     return (OK);
  1607.     }
  1608. /*******************************************************************************
  1609. *
  1610. * taskSafe - make the calling task safe from deletion
  1611. *
  1612. * This routine protects the calling task from deletion.  Tasks that attempt
  1613. * to delete a protected task will block until the task is made unsafe, using
  1614. * taskUnsafe().  When a task becomes unsafe, the deleter will be unblocked
  1615. * and allowed to delete the task.
  1616. *
  1617. * The taskSafe() primitive utilizes a count to keep track of nested
  1618. * calls for task protection.  When nesting occurs, the task
  1619. * becomes unsafe only after the outermost taskUnsafe() is executed.
  1620. *
  1621. * RETURNS: OK.
  1622. *
  1623. * SEE ALSO: taskUnsafe(),
  1624. * .pG "Basic OS"
  1625. */
  1626. STATUS taskSafe (void)
  1627.     {
  1628.     TASK_SAFE (); /* increment safe cnt */
  1629.     return (OK);
  1630.     }
  1631. /*******************************************************************************
  1632. *
  1633. * taskUnsafe - make the calling task unsafe from deletion
  1634. *
  1635. * This routine removes the calling task's protection from deletion.  Tasks
  1636. * that attempt to delete a protected task will block until the task is unsafe.
  1637. * When a task becomes unsafe, the deleter will be unblocked and allowed to
  1638. * delete the task.
  1639. *
  1640. * The taskUnsafe() primitive utilizes a count to keep track of nested
  1641. * calls for task protection.  When nesting occurs, the task
  1642. * becomes unsafe only after the outermost taskUnsafe() is executed.
  1643. *
  1644. * RETURNS: OK.
  1645. *
  1646. * SEE ALSO: taskSafe(),
  1647. * .pG "Basic OS"
  1648. */
  1649. STATUS taskUnsafe (void)
  1650.     {
  1651.     FAST WIND_TCB *pTcb = taskIdCurrent;
  1652. #ifdef WV_INSTRUMENTATION
  1653.     /* windview - level 1 event logging */
  1654.     EVT_OBJ_2 (TASK, pTcb, taskClassId, EVENT_TASKUNSAFE, pTcb, pTcb->safeCnt);
  1655. #endif
  1656.     if ((pTcb->safeCnt > 0) && ((-- pTcb->safeCnt) == 0)) /* unsafe? */
  1657. {
  1658. kernelState = TRUE; /* KERNEL ENTER */
  1659.         if (Q_FIRST (&pTcb->safetyQHead) != NULL) /* deleter waiting? */
  1660.             {
  1661. #ifdef WV_INSTRUMENTATION
  1662.     /* windview - level 2 event logging */
  1663.     EVT_TASK_1 (EVENT_OBJ_TASK, pTcb);     /* log event */
  1664. #endif
  1665.             windPendQFlush (&pTcb->safetyQHead);
  1666.             }
  1667. windExit (); /* KERNEL EXIT */
  1668. }
  1669.     return (OK);
  1670.     }
  1671. /*******************************************************************************
  1672. *
  1673. * taskDelay - delay a task from executing
  1674. *
  1675. * This routine causes the calling task to relinquish the CPU for the duration
  1676. * specified (in ticks).  This is commonly referred to as manual rescheduling,
  1677. * but it is also useful when waiting for some external condition that does not
  1678. * have an interrupt associated with it.
  1679. *
  1680. * If the calling task receives a signal that is not being blocked or ignored,
  1681. * taskDelay() returns ERROR and sets `errno' to EINTR after the signal
  1682. * handler is run.
  1683. *
  1684. * RETURNS: OK, or ERROR if called from interrupt level or if the calling task
  1685. * receives a signal that is not blocked or ignored.
  1686. *
  1687. * ERRNO: S_intLib_NOT_ISR_CALLABLE, EINTR
  1688. *
  1689. */
  1690. STATUS taskDelay
  1691.     (
  1692.     int ticks           /* number of ticks to delay task */
  1693.     )
  1694.     {
  1695.     STATUS status;
  1696.    
  1697. #ifdef WV_INSTRUMENTATION
  1698.     int tid = (int) taskIdCurrent;
  1699. #endif
  1700.     if (INT_RESTRICT () != OK) /* restrict ISR use */
  1701. return (ERROR);
  1702. #ifdef WV_INSTRUMENTATION
  1703.     /* windview - level 1 event logging */
  1704.     EVT_OBJ_1 (TASK, ((WIND_TCB *)tid), taskClassId, EVENT_TASKDELAY, ticks);
  1705. #endif
  1706.     kernelState = TRUE; /* KERNEL ENTER */
  1707.     if (ticks == NO_WAIT)  /* NO_WAIT = resort in ready q*/
  1708. {
  1709. Q_REMOVE (&readyQHead, taskIdCurrent); /* Q_RESORT incorrect here */
  1710. Q_PUT (&readyQHead, taskIdCurrent, taskIdCurrent->priority);
  1711. }
  1712.     else
  1713. windDelay (ticks); /* grab tick winks */
  1714.     if ((status = windExit()) == RESTART)       /* KERNEL EXIT */
  1715. {
  1716. status = ERROR;
  1717. errno = EINTR;
  1718. }
  1719.     return (status);
  1720.     }
  1721. /*******************************************************************************
  1722. *
  1723. * taskUndelay - wake up a sleeping task
  1724. *
  1725. * This routine removes the specified task from the delay queue.  The sleeping
  1726. * task will be returned ERROR.
  1727. *
  1728. * RETURNS: OK, or ERROR if the task ID is invalid or the task not delayed.
  1729. *
  1730. * NOMANUAL
  1731. */
  1732. STATUS taskUndelay
  1733.     (
  1734.     int tid             /* task to wakeup */
  1735.     )
  1736.     {
  1737.     if (kernelState)
  1738. {
  1739. if (TASK_ID_VERIFY ((void *)tid) != OK) /* verify task ID */
  1740.     return (ERROR);
  1741. workQAdd1 (windUndelay, tid); /* defer undelay */
  1742. return (OK);
  1743. }
  1744.     kernelState = TRUE; /* KERNEL ENTER */
  1745.     if (TASK_ID_VERIFY ((void *)tid) != OK) /* check for bad ID */
  1746. {
  1747. windExit (); /* KERNEL EXIT */
  1748. return (ERROR);
  1749. }
  1750.     windUndelay ((WIND_TCB *) tid); /* wake up task */
  1751.     windExit (); /* KERNEL EXIT */
  1752.     return (OK);
  1753.     }
  1754. /*******************************************************************************
  1755. *
  1756. * taskIdSelf - get the task ID of a running task
  1757. *
  1758. * This routine gets the task ID of the calling task.  The task ID will be
  1759. * invalid if called at interrupt level.
  1760. *
  1761. * RETURNS: The task ID of the calling task.
  1762. */
  1763. int taskIdSelf (void)
  1764.     {
  1765.     return ((int)taskIdCurrent);
  1766.     }
  1767. /*******************************************************************************
  1768. *
  1769. * taskIdVerify - verify the existence of a task
  1770. *
  1771. * This routine verifies the existence of a specified task by validating the
  1772. * specified ID as a task ID.  Note that an exception occurs if the task ID
  1773. * parameter points to an address not located in physical memory.
  1774. *
  1775. * RETURNS: OK, or ERROR if the task ID is invalid.
  1776. *
  1777. * ERRNO: S_objLib_OBJ_ID_ERROR
  1778. */
  1779. STATUS taskIdVerify
  1780.     (
  1781.     int tid     /* task ID */
  1782.     )
  1783.     {
  1784.     return (TASK_ID_VERIFY ((void *)tid));
  1785.     }
  1786. /*******************************************************************************
  1787. *
  1788. * taskTcb - get the task control block for a task ID
  1789. *
  1790. * This routine returns a pointer to the task control block (WIND_TCB) for a
  1791. * specified task.  Although all task state information is contained in the
  1792. * TCB, users must not modify it directly.  To change registers, for instance,
  1793. * use taskRegsSet() and taskRegsGet().
  1794. *
  1795. * RETURNS: A pointer to a WIND_TCB, or NULL if the task ID is invalid.
  1796. *
  1797. * ERRNO: S_objLib_OBJ_ID_ERROR
  1798. */
  1799. WIND_TCB *taskTcb
  1800.     (
  1801.     int tid                     /* task ID */
  1802.     )
  1803.     {
  1804.     if (tid == 0)
  1805. tid = (int)taskIdCurrent; /* 0 tid means self */
  1806.     if (TASK_ID_VERIFY ((void *)tid) != OK) /* verify task ID */
  1807. return (NULL);
  1808.     return ((WIND_TCB *) tid); /* tid == pTcb */
  1809.     }
  1810. /*******************************************************************************
  1811. *
  1812. * taskStackAllot - allot memory from caller's stack
  1813. *
  1814. * This routine allots the specified amount of memory from the end of the
  1815. * caller's stack.  This is a non-blocking operation.  This routine is utilized
  1816. * by task create hooks to allocate any additional memory they need.  The memory
  1817. * cannot be added back to the stack.  It will be reclaimed as part of the
  1818. * reclamation of the task stack when the task is deleted.
  1819. *
  1820. * Note that a stack crash will overwrite the allotments made from this routine
  1821. * because all portions are carved from the end of the stack.
  1822. *
  1823. * This routine will return NULL if requested size exceeds available stack
  1824. * memory.
  1825. *
  1826. * RETURNS: pointer to block, or NULL if unsuccessful.
  1827. *
  1828. * NOMANUAL
  1829. */
  1830. void *taskStackAllot
  1831.     (
  1832.     int      tid,               /* task whose stack will be allotted from */
  1833.     unsigned nBytes             /* number of bytes to allot */
  1834.     )
  1835.     {
  1836.     char     *pStackPrevious;
  1837.     WIND_TCB *pTcb = taskTcb (tid);
  1838.     nBytes = STACK_ROUND_UP (nBytes); /* round up request */
  1839.     if ((pTcb == NULL) ||
  1840. (nBytes > (pTcb->pStackLimit - pTcb->pStackBase) * _STACK_DIR))
  1841. {
  1842. return (NULL);
  1843. }
  1844.     pStackPrevious = pTcb->pStackLimit; /* allot from end of stack */
  1845. #if (_STACK_DIR == _STACK_GROWS_DOWN)
  1846.     pTcb->pStackLimit += nBytes; /* move up end of stack */
  1847.     return ((void *)pStackPrevious);
  1848. #else /* _STACK_GROWS_UP */
  1849.     pTcb->pStackLimit -= nBytes; /* move down end of stack */
  1850.     return ((void *)pTcb->pStackLimit);
  1851. #endif /* _STACK_GROWS_UP */
  1852.     }