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

VxWorks

开发平台:

C/C++

  1. /* semMLib.c - mutual-exclusion semaphore library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02k,03may02,pcm  removed possible NULL dereference in semMCreate () (SPR 76721)
  8. 02j,19nov01,bwa  Corrected doc for semMCreate return value (SPR #71921).
  9. 02i,09nov01,dee  add CPU_FAMILY != COLDFIRE in portable test
  10. 02h,30oct01,bwa  Fixed semMGive() behaviour.
  11. 02g,07sep01,bwa  Added VxWorks events support.
  12. 02f,04sep98,cdp  make ARM CPUs with ARM_THUMB==TRUE use portable routines.
  13. 02f,03mar00,zl   merged SH support into T2
  14. 02f,18dec00,pes  Correct compiler warnings
  15. 02e,17feb98,cdp  undo 02d: put ARM back in list of optimised CPUs.
  16. 02d,21oct97,kkk  undo 02c, take out ARM from list of optimized CPUs.
  17. 02c,20may97,jpd  added ARM to list of optimised CPUs.
  18. 02b,15oct96,dgp  doc: add caveats on priority inversion per SPR #6884
  19. 02a,24jun96,sbs  made windview instrumentation conditionally compiled
  20. 01z,22oct95,jdi  doc: added bit values for semMCreate() options (SPR 4276).
  21. 01y,19mar95,dvs  removed tron references.
  22. 01x,03feb95,rhp  doc: propagate warning about semaphore deletion from semLib
  23. 01w,09jun93,hdn  added a support for I80X86
  24. 01z,14apr94,smb  fixed class dereferencing for instrumentation macros
  25. 01y,15mar94,smb  modified instrumentation macros
  26. 01x,24jan94,smb  added instrumentation macros
  27. 01w,10dec93,smb  added instrumentation
  28. 01v,23jan93,jdi  documentation cleanup for 5.1.
  29. 01u,13nov92,jcf  semMCreate call semMLibInit for robustness.
  30. 01t,02oct92,jcf  made semMGiveForce() work if called by owner.
  31. 01s,28jul92,jcf  semM{Create,Init} call semMLibInit for robustness.
  32. 01r,28jul92,jcf  changed semMTakeKern to semMPendQPut;semMTake uses semMPendQPut
  33. 01q,18jul92,smb  Changed errno.h to errnoLib.h.
  34. 01p,09jul92,rrr  changed xsignal.h to private/sigLibP.h
  35. 01o,04jul92,jcf  added semMLibInit() to fill in semLib tables.
  36. 01n,26may92,rrr  the tree shuffle
  37. 01m,27apr92,rrr  added signal restarting
  38. 01l,15sep91,ajm  added MIPS to list of optimized CPU's
  39. 01k,04oct91,rrr  passed through the ansification filter
  40.                   -changed functions to ansi style
  41.   -changed includes to have absolute path from h/
  42.   -fixed #else and #endif
  43.   -changed copyright notice
  44. 01j,26sep91,hdn  added conditional flag for TRON optimized code.
  45. 01i,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  46.  doc review by jcf.
  47. 01h,24mar91,jdi  documentation cleanup.
  48. 01g,16oct90,jcf  fixed priority inversion race in semMGive.
  49. 01f,05oct90,dnw  made semMInit() be NOMANUAL.
  50. 01e,30sep90,jcf  added semMGiveForce().
  51. 01d,03aug90,jcf  documentation.
  52. 01c,17jul90,dnw  changed to new objAlloc() call.
  53. 01b,05jul90,jcf  optimized version now available.
  54. 01a,20oct89,jcf  written based on v1b of semILib.
  55. */
  56. /*
  57. DESCRIPTION
  58. This library provides the interface to VxWorks mutual-exclusion
  59. semaphores.  Mutual-exclusion semaphores offer convenient options
  60. suited for situations requiring mutually exclusive access to resources.
  61. Typical applications include sharing devices and protecting data
  62. structures.  Mutual-exclusion semaphores are used by many higher-level
  63. VxWorks facilities.
  64. The mutual-exclusion semaphore is a specialized version of the binary
  65. semaphore, designed to address issues inherent in mutual exclusion, such
  66. as recursive access to resources, priority inversion, and deletion safety.
  67. The fundamental behavior of the mutual-exclusion semaphore is identical
  68. to the binary semaphore (see the manual entry for semBLib), except for
  69. the following restrictions:
  70.     - It can only be used for mutual exclusion.
  71.     - It can only be given by the task that took it.
  72.     - It may not be taken or given from interrupt level.
  73.     - The semFlush() operation is illegal.
  74. These last two operations have no meaning in mutual-exclusion situations.
  75. RECURSIVE RESOURCE ACCESS
  76. A special feature of the mutual-exclusion semaphore is that it may be
  77. taken "recursively," i.e., it can be taken more than once by the task that
  78. owns it before finally being released.  Recursion is useful for a set of
  79. routines that need mutually exclusive access to a resource, but may need
  80. to call each other.
  81. Recursion is possible because the system keeps track of which task
  82. currently owns a mutual-exclusion semaphore.  Before being released, a
  83. mutual-exclusion semaphore taken recursively must be given the same number
  84. of times it has been taken; this is tracked by means of a count which is
  85. incremented with each semTake() and decremented with each semGive().
  86. The example below illustrates recursive use of a mutual-exclusion semaphore.
  87. Function A requires access to a resource which it acquires by taking `semM';
  88. function A may also need to call function B, which also requires `semM':
  89. .CS
  90. .ne 3
  91.     SEM_ID semM;
  92.     semM = semMCreate (...);
  93. .ne 8
  94.     funcA ()
  95. {
  96. semTake (semM, WAIT_FOREVER);
  97. ...
  98. funcB ();
  99. ...
  100. semGive (semM);
  101. }
  102. .ne 6
  103.     funcB ()
  104. {
  105. semTake (semM, WAIT_FOREVER);
  106. ...
  107. semGive (semM);
  108. }
  109. .CE
  110. PRIORITY-INVERSION SAFETY
  111. If the option SEM_INVERSION_SAFE is selected, the library adopts a
  112. priority-inheritance protocol to resolve potential occurrences of
  113. "priority inversion," a problem stemming from the use semaphores for
  114. mutual exclusion.  Priority inversion arises when a higher-priority task
  115. is forced to wait an indefinite period of time for the completion of a
  116. lower-priority task.
  117. Consider the following scenario:  T1, T2, and T3 are tasks of high,
  118. medium, and low priority, respectively.  T3 has acquired some resource by
  119. taking its associated semaphore.  When T1 preempts T3 and contends for the
  120. resource by taking the same semaphore, it becomes blocked.  If we could be
  121. assured that T1 would be blocked no longer than the time it normally takes
  122. T3 to finish with the resource, the situation would not be problematic.
  123. However, the low-priority task is vulnerable to preemption by medium-priority
  124. tasks; a preempting task, T2, could inhibit T3 from relinquishing the resource.
  125. This condition could persist, blocking T1 for an indefinite period of time.
  126. The priority-inheritance protocol solves the problem of priority inversion
  127. by elevating the priority of T3 to the priority of T1 during the time T1 is
  128. blocked on T3.  This protects T3, and indirectly T1, from preemption by T2.
  129. Stated more generally, the priority-inheritance protocol assures that
  130. a task which owns a resource will execute at the priority of the highest
  131. priority task blocked on that resource.  Once the task priority has been
  132. elevated, it remains at the higher level until all mutual-exclusion semaphores
  133. that the task owns are released; then the task returns to its normal, or 
  134. standard, priority.  Hence, the "inheriting" task is protected from preemption 
  135. by any intermediate-priority tasks.
  136. The priority-inheritance protocol also takes into consideration a task's
  137. ownership of more than one mutual-exclusion semaphore at a time.  Such a
  138. task will execute at the priority of the highest priority task blocked on
  139. any of its owned resources.  The task will return to its normal priority
  140. only after relinquishing all of its mutual-exclusion semaphores that have
  141. the inversion-safety option enabled.
  142. SEMAPHORE DELETION
  143. The semDelete() call terminates a semaphore and deallocates any
  144. associated memory.  The deletion of a semaphore unblocks tasks pended
  145. on that semaphore; the routines which were pended return ERROR.  Take
  146. special care when deleting mutual-exclusion semaphores to avoid
  147. deleting a semaphore out from under a task that already owns (has
  148. taken) that semaphore.  Applications should adopt the protocol of only
  149. deleting semaphores that the deleting task owns.
  150. TASK-DELETION SAFETY
  151. If the option SEM_DELETE_SAFE is selected, the task owning the semaphore
  152. will be protected from deletion as long as it owns the semaphore.  This
  153. solves another problem endemic to mutual exclusion.  Deleting a task
  154. executing in a critical region can be catastrophic.  The resource could be
  155. left in a corrupted state and the semaphore guarding the resource would be
  156. unavailable, effectively shutting off all access to the resource.
  157. As discussed in taskLib, the primitives taskSafe() and taskUnsafe()
  158. offer one solution, but as this type of protection goes hand in hand with
  159. mutual exclusion, the mutual-exclusion semaphore provides the option
  160. SEM_DELETE_SAFE, which enables an implicit taskSafe() with each semTake(),
  161. and a taskUnsafe() with each semGive().  This convenience is also more
  162. efficient, as the resulting code requires fewer entrances to the kernel.
  163. CAVEATS
  164. There is no mechanism to give back or reclaim semaphores automatically when
  165. tasks are suspended or deleted.  Such a mechanism, though desirable, is not
  166. currently feasible.  Without explicit knowledge of the state of the guarded
  167. resource or region, reckless automatic reclamation of a semaphore could
  168. leave the resource in a partial state.  Thus if a task ceases execution
  169. unexpectedly, as with a bus error, currently owned semaphores will not be
  170. given back, effectively leaving a resource permanently unavailable.  The
  171. SEM_DELETE_SAFE option partially protects an application, to the extent
  172. that unexpected deletions will be deferred until the resource is released.
  173. Because the priority of a task which has been elevated by the taking of a
  174. mutual-exclusion semaphore remains at the higher priority until all
  175. mutexes held by that task are released, unbounded priority inversion situations
  176. can result when nested mutexes are involved.  If nested mutexes are required,
  177. consider the following alternatives:
  178. .iP 1. 4
  179. Avoid overlapping critical regions.
  180. .iP 2. 
  181. Adjust priorities of tasks so that there are no tasks at intermediate
  182. priority levels.
  183. .iP 3. 
  184. Adjust priorities of tasks so that priority inheritance protocol is not
  185. needed.
  186. .iP 4. 
  187. Manually implement a static priority ceiling protocol using a 
  188. non-inversion-save mutex.  This involves setting all blockers on a mutex 
  189. to the ceiling priority, then taking the mutex.  After semGive, set the 
  190. priorities back to the base priority. Note that this implementation 
  191. reduces the queue to a fifo queue.
  192. .LP
  193. INTERNAL:
  194. WINDVIEW INSTRUMENTATION
  195. Level 1:
  196. semMCreate() causes EVENT_SEMMCREATE
  197. semMGiveForce() causes EVENT_SEMMGIVEFORCE
  198. Level 2:
  199. N/A
  200. Level 3:
  201. N/A
  202. INCLUDE FILES: semLib.h
  203. SEE ALSO: semLib, semBLib, semCLib,
  204. .pG "Basic OS"
  205. */
  206. #include "vxWorks.h"
  207. #include "errnoLib.h"
  208. #include "taskLib.h"
  209. #include "intLib.h"
  210. #include "eventLib.h"
  211. #include "private/eventLibP.h"
  212. #include "private/sigLibP.h"
  213. #include "private/objLibP.h"
  214. #include "private/semLibP.h"
  215. #include "private/windLibP.h"
  216. #include "private/workQLibP.h"
  217. #include "private/eventP.h"
  218. /* optimized version available for 680X0, MIPS, i86, SH, */
  219. /* COLDFIRE and ARM (excluding Thumb) */
  220. #if (defined(PORTABLE) || 
  221.      ((CPU_FAMILY != MC680X0) && 
  222.       (CPU_FAMILY != MIPS) && 
  223.       (CPU_FAMILY != I80X86) && 
  224.       (CPU_FAMILY != SH) && 
  225.       (CPU_FAMILY != COLDFIRE) && 
  226.       (CPU_FAMILY != ARM)) || 
  227.      ((CPU_FAMILY == ARM) && ARM_THUMB))
  228. #define semMLib_PORTABLE
  229. #endif
  230. /* globals */
  231. int semMGiveKernWork; /* parameter space for semMGiveKern() */
  232. /* locals */
  233. LOCAL BOOL semMLibInstalled; /* protect from muliple inits */
  234. /*******************************************************************************
  235. *
  236. * semMLibInit - initialize the binary semaphore management package
  237. * SEE ALSO: semLibInit(1).
  238. * NOMANUAL
  239. */
  240. STATUS semMLibInit (void)
  241.     {
  242.     if (!semMLibInstalled)
  243. {
  244. semGiveTbl [SEM_TYPE_MUTEX] = (FUNCPTR) semMGive;
  245. semTakeTbl [SEM_TYPE_MUTEX] = (FUNCPTR) semMTake;
  246. if (semLibInit () == OK)
  247.     semMLibInstalled = TRUE;
  248. }
  249.     return ((semMLibInstalled) ? OK : ERROR);
  250.     }
  251. /*******************************************************************************
  252. *
  253. * semMCreate - create and initialize a mutual-exclusion semaphore
  254. *
  255. * This routine allocates and initializes a mutual-exclusion semaphore.  The
  256. * semaphore state is initialized to full.
  257. *
  258. * Semaphore options include the following:
  259. * .iP "SEM_Q_PRIORITY  (0x1)" 8
  260. * Queue pended tasks on the basis of their priority.
  261. * .iP "SEM_Q_FIFO  (0x0)"
  262. * Queue pended tasks on a first-in-first-out basis.
  263. * .iP "SEM_DELETE_SAFE  (0x4)"
  264. * Protect a task that owns the semaphore from unexpected deletion.  This
  265. * option enables an implicit taskSafe() for each semTake(), and an implicit
  266. * taskUnsafe() for each semGive().
  267. * .iP "SEM_INVERSION_SAFE  (0x8)"
  268. * Protect the system from priority inversion.  With this option, the task
  269. * owning the semaphore will execute at the highest priority of the tasks
  270. * pended on the semaphore, if it is higher than its current priority.  This
  271. * option must be accompanied by the SEM_Q_PRIORITY queuing mode.
  272. * .iP "SEM_EVENTSEND_ERR_NOTIFY (0x10)"
  273. * When the semaphore is given, if a task is registered for events and the
  274. * actual sending of events fails, a value of ERROR is returned and the errno
  275. * is set accordingly. This option is off by default.
  276. * .LP
  277. *
  278. * RETURNS: The semaphore ID, or NULL if the semaphore cannot be created.
  279. *
  280. * ERRNO
  281. * .iP "S_semLib_INVALID_OPTION"
  282. * Invalid option was passed to semMCreate.
  283. * .iP "S_memLib_NOT_ENOUGH_MEMORY"
  284. * Not enough memory available to create the semaphore.
  285. * .LP
  286. *
  287. * SEE ALSO: semLib, semBLib, taskSafe(), taskUnsafe()
  288. */
  289. SEM_ID semMCreate
  290.     (
  291.     int options                 /* mutex semaphore options */
  292.     )
  293.     {
  294.     SEM_ID semId;
  295.     if ((!semMLibInstalled) && (semMLibInit () != OK)) /* initialize package */
  296.         return (NULL);
  297.     if ((semId = (SEM_ID) objAlloc (semClassId)) == NULL)
  298. return (NULL);
  299.     /* initialize allocated semaphore */
  300.     if (semMInit (semId, options) != OK)
  301. {
  302. objFree (semClassId, (char *) semId);
  303. return (NULL);
  304. }
  305. #ifdef WV_INSTRUMENTATION
  306.     /* windview - level 1 event logging */
  307.     EVT_OBJ_3 (OBJ, semId, semClassId,
  308.        EVENT_SEMMCREATE, semId, options, semId->state);
  309. #endif
  310.     return (semId);
  311.     }
  312. /*******************************************************************************
  313. *
  314. * semMInit - initialize a mutual-exclusion semaphore
  315. *
  316. * The initialization of a static mutual exclusion semaphore, or a mutual
  317. * exclusion semaphore embedded in some larger object need not deal
  318. * with allocation.  This routine may be called to initialize such a
  319. * semaphore.  The semaphore state is initialized to the full state.
  320. *
  321. * Mutual exclusion semaphore options include the queuing style for blocked
  322. * tasks.  Tasks may be queued on the basis of their priority or
  323. * first-in-first-out.  These options are SEM_Q_PRIORITY and SEM_Q_FIFO
  324. * respectively.
  325. *
  326. * The SEM_DELETE_SAFE option protects the task that currently owns the
  327. * semaphore from unexpected deletion.  This option enables an implicit
  328. * taskSafe() on each semTake(), and an implicit taskUnsafe() of every semGive().
  329. *
  330. * The SEM_INVERSION_SAFE option protects the system from priority inversion.
  331. * This option must be accompanied by the SEM_Q_PRIORITY queuing mode.  With
  332. * this option selected, the task owning the semaphore will execute at the
  333. * highest priority of the tasks pended on the semaphore if it is higher than
  334. * its current priority.
  335. *
  336. * RETURNS: OK, or ERROR if semaphore could not be initialized.
  337. *
  338. * ERRNO: S_semLib_INVALID_OPTION
  339. *
  340. * SEE ALSO: semLib, semBLib, semMCreate(), taskSafe(), taskUnsafe()
  341. *
  342. * NOMANUAL
  343. */
  344. STATUS semMInit
  345.     (
  346.     SEMAPHORE * pSemaphore,     /* pointer to mutex semaphore to initialize */
  347.     int         options         /* mutex semaphore options */
  348.     )
  349.     {
  350.     if ((!semMLibInstalled) && (semMLibInit () != OK)) /* initialize package */
  351. return (ERROR);
  352.     if ((options & SEM_INVERSION_SAFE) && ((options & SEM_Q_MASK)==SEM_Q_FIFO))
  353. {
  354. errno = S_semLib_INVALID_OPTION;
  355. return (ERROR);
  356. }
  357.     if (semQInit (pSemaphore, options) != OK)
  358. return (ERROR);
  359.     return (semMCoreInit (pSemaphore, options));
  360.     }
  361. /*******************************************************************************
  362. *
  363. * semMCoreInit - initialize a mutex semaphore with queue already initialized
  364. *
  365. * To initialize a semaphore with some special queuing algorithm, this routine
  366. * is used.  This routine will initialize a mutual exclusion semaphore without
  367. * initializing the queue.
  368. *
  369. * NOMANUAL
  370. */
  371. STATUS semMCoreInit
  372.     (
  373.     SEMAPHORE   *pSemaphore,    /* pointer to mutex semaphore to initialize */
  374.     int         options         /* mutex semaphore options */
  375.     )
  376.     {
  377.     pSemaphore->semOwner = NULL; /* no owner */
  378.     pSemaphore->recurse  = 0; /* init take recurse count */
  379.     pSemaphore->options  = options; /* initialize options */
  380.     pSemaphore->semType  = SEM_TYPE_MUTEX; /* type is mutex */
  381.     eventInit (&pSemaphore->events); /* initialize events */
  382. #ifdef WV_INSTRUMENTATION
  383.     /* windview - connect instrumented class for level 1 event logging */
  384.     if (wvObjIsEnabled)
  385.         objCoreInit (&pSemaphore->objCore, semInstClassId);
  386.     else
  387.         objCoreInit (&pSemaphore->objCore, semClassId);
  388. #else
  389.     objCoreInit (&pSemaphore->objCore, semClassId);
  390. #endif
  391.     return (OK);
  392.     }
  393. #ifdef semMLib_PORTABLE
  394. /*******************************************************************************
  395. *
  396. * semMGive - give a semaphore
  397. *
  398. * Gives the semaphore.  If a higher priority task has already taken
  399. * the semaphore (so that it is now pended waiting for it), that task
  400. * will now become ready to run, and preempt the task that does the semGive().
  401. * If the semaphore is already full (it has been given but not taken) this
  402. * call is essentially a no-op.
  403. *
  404. * If deletion safe option is enabled, an implicit taskUnsafe() operation will
  405. * occur.
  406. *
  407. * If priority inversion safe option is enabled, and this is the last priority
  408. * inversion safe semaphore to be released, the calling task will revert to
  409. * its normal priority.
  410. *
  411. * WARNING
  412. * This routine may not be used from interrupt level.
  413. *
  414. * ERRNO: S_semLib_INVALID_OPERATION
  415. *
  416. * INTERNAL
  417. * The use of the variables kernWork and semMGiveKernWork looks pretty lame.  It
  418. * is, in fact, necessary to facilitate the optimized version of this routine.
  419. * An optimized version would utilize a register for kernWork and stick the
  420. * value in semMGiveKernWork as a parameter to semMGiveKern().  This form of
  421. * parameter passing saves costly stack manipulation.
  422. *
  423. * NOMANUAL
  424. */
  425. STATUS semMGive
  426.     (
  427.     FAST SEM_ID semId   /* semaphore ID to give */
  428.     )
  429.     {
  430.     FAST int level;
  431.     FAST int kernWork = 0;
  432.     if (INT_RESTRICT () != OK) /* restrict isr use */
  433. return (ERROR);
  434.     level = intLock (); /* LOCK INTERRUPTS */
  435.     if (OBJ_VERIFY (semId, semClassId) != OK) /* check validity */
  436. {
  437. intUnlock (level);
  438. return (ERROR);
  439. }
  440.     if (taskIdCurrent != semId->semOwner) /* check for ownership */
  441. {
  442. intUnlock (level);
  443. errnoSet (S_semLib_INVALID_OPERATION);
  444. return (ERROR);
  445. }
  446.     if (semId->recurse > 0) /* check recurse count */
  447. {
  448. semId->recurse --; /* decrement recurse count */
  449. intUnlock (level);
  450. return (OK);
  451. }
  452.     if ((semId->options & SEM_INVERSION_SAFE) &&
  453. (-- taskIdCurrent->priMutexCnt == 0))
  454.         {
  455. if (taskIdCurrent->priority != taskIdCurrent->priNormal)
  456.     kernWork |= SEM_M_PRI_RESORT;
  457. }
  458.     if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) != NULL)
  459. kernWork |= SEM_M_Q_GET;
  460.     else if (semId->events.taskId != (int)NULL)
  461. kernWork |= SEM_M_SEND_EVENTS;
  462.     if ((semId->options & SEM_DELETE_SAFE) &&
  463.   (-- taskIdCurrent->safeCnt == 0) &&
  464. (Q_FIRST (&taskIdCurrent->safetyQHead) != NULL))
  465. kernWork |= SEM_M_SAFE_Q_FLUSH;
  466.     if (kernWork == 0)
  467. {
  468. intUnlock (level); /* UNLOCK INTERRUPTS */
  469. return (OK);
  470. }
  471.     kernelState = TRUE; /* KERNEL ENTER */
  472.     intUnlock (level); /* UNLOCK INTERRUPTS */
  473.     semMGiveKernWork = kernWork; /* setup the work to do */
  474.     return (semMGiveKern (semId)); /* do the work */
  475.     }
  476. /*******************************************************************************
  477. *
  478. * semMTake - take a semaphore
  479. *
  480. * Takes the semaphore.  If the semaphore is empty, i.e., it has not been given
  481. * since the last semTake() or semInit(), this task will become pended until
  482. * the semaphore becomes available by some other task doing a semGive()
  483. * of it.  If the semaphore is already available, this call will empty
  484. * the semaphore, so that no other task can take it until this task gives
  485. * it back, and this task will continue running.
  486. *
  487. * If deletion safe option is enabled, an implicit taskSafe() operation will
  488. * occur.
  489. *
  490. * If priority inversion safe option is enabled, and the calling task blocks,
  491. * and the priority of the calling task is greater than the semaphore owner,
  492. * the owner will inherit the caller's priority.
  493. *
  494. * WARNING
  495. * This routine may not be used from interrupt level.
  496. *
  497. * NOMANUAL
  498. */
  499. STATUS semMTake
  500.     (
  501.     FAST SEM_ID semId,  /* semaphore ID to take */
  502.     int timeout         /* timeout in ticks */
  503.     )
  504.     {
  505.     int level;
  506.     int status;
  507.     if (INT_RESTRICT () != OK)
  508. return (ERROR);
  509. again:
  510.     level = intLock (); /* LOCK INTERRUPTS */
  511.     if (OBJ_VERIFY (semId, semClassId) != OK)
  512. {
  513. intUnlock (level); /* UNLOCK INTERRUPTS */
  514. return (ERROR);
  515. }
  516.     if (semId->semOwner == NULL)
  517. {
  518. semId->semOwner = taskIdCurrent; /* update semaphore state */
  519. if (semId->options & SEM_INVERSION_SAFE)
  520.     taskIdCurrent->priMutexCnt ++; /* update inherit count */
  521. if (semId->options & SEM_DELETE_SAFE)
  522.     taskIdCurrent->safeCnt ++; /* update safety count */
  523. intUnlock (level); /* UNLOCK INTERRUPTS */
  524. return (OK);
  525. }
  526.     if (semId->semOwner == taskIdCurrent) /* check for recursion */
  527. {
  528. semId->recurse ++; /* keep recursion count */
  529. intUnlock (level); /* UNLOCK INTERRUPTS */
  530. return (OK);
  531. }
  532.     kernelState = TRUE; /* KERNEL ENTER */
  533.     intUnlock (level); /* UNLOCK INTERRUPTS */
  534.     if (semMPendQPut (semId, timeout) != OK)
  535. {
  536. windExit (); /* windPendQPut failed */
  537. return (ERROR);
  538. }
  539.     if ((status = windExit ()) == RESTART) /* KERNEL EXIT */
  540. {
  541. timeout = SIG_TIMEOUT_RECALC(timeout);
  542. goto again; /* we got signalled */
  543. }
  544.     return (status);
  545.     }
  546. #endif /* semMLib_PORTABLE */
  547. /*******************************************************************************
  548. *
  549. * semMGiveForce - give a mutual-exclusion semaphore without restrictions
  550. *
  551. * This routine gives a mutual-exclusion semaphore, regardless of semaphore
  552. * ownership.  It is intended as a debugging aid only.
  553. *
  554. * The routine is particularly useful when a task dies while holding some
  555. * mutual-exclusion semaphore, because the semaphore can be resurrected.  The
  556. * routine will give the semaphore to the next task in the pend queue or make
  557. * the semaphore full if no tasks are pending.  In effect, execution will
  558. * continue as if the task owning the semaphore had actually given the
  559. * semaphore.
  560. *
  561. * CAVEATS
  562. * This routine should be used only as a debugging aid, when the condition of
  563. * the semaphore is known.
  564. *
  565. * RETURNS: OK, or ERROR if the semaphore ID is invalid.
  566. *
  567. * SEE ALSO: semGive()
  568. */
  569. STATUS semMGiveForce
  570.     (
  571.     FAST SEM_ID semId   /* semaphore ID to give */
  572.     )
  573.     {
  574.     STATUS status = OK;
  575.     int oldErrno = errno;
  576.     if (INT_RESTRICT () != OK) /* restrict isr use */
  577. return (ERROR);
  578.     if (OBJ_VERIFY (semId, semClassId) != OK) /* check validity */
  579. return (ERROR);
  580. #ifdef WV_INSTRUMENTATION
  581.     /* windview - level 1 event logging */
  582.     EVT_OBJ_3 (OBJ, semId, semClassId,
  583.        EVENT_SEMMGIVEFORCE, semId, semId->options, semId->state);
  584. #endif
  585.     /* if semaphore is not taken, nothing has to be done. */
  586.     if (semId->semOwner == NULL)
  587. return OK;
  588.     /* first see if we are giving away one of calling task's semaphores */
  589.     if (semId->semOwner == taskIdCurrent) /* give semaphore until avail */
  590. {
  591. while (semId->semOwner == taskIdCurrent)/* loop until recurse == 0 */
  592.     semGive (semId); /* give semaphore */
  593. return (OK); /* done */
  594. }
  595.     /* give another task's semaphore away.  Djkstra be damned... */
  596.     kernelState = TRUE; /* KERNEL ENTER */
  597.     semId->recurse = 0; /* initialize recurse count */
  598.     if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) != NULL)
  599. {
  600. #ifdef WV_INSTRUMENTATION
  601.      /* windview - level 2 event logging */
  602. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  603. #endif
  604. windPendQGet (&semId->qHead); /* unblock receiver */
  605. semId->semOwner->pPriMutex = NULL; /* receiver no longer pended */
  606. if (semId->options & SEM_DELETE_SAFE)
  607.     semId->semOwner->safeCnt ++; /* increment receiver safety */
  608. if (semId->options & SEM_INVERSION_SAFE)
  609.     semId->semOwner->priMutexCnt ++; /* update inherit count */
  610. }
  611.     else
  612. {
  613. if (semId->events.taskId != (int)NULL) /* sem is free, send events */
  614.     {
  615.     if (eventRsrcSend (semId->events.taskId,
  616.        semId->events.registered) != OK)
  617. {
  618. if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0)
  619.     {
  620.     status = ERROR;
  621.     }
  622. semId->events.taskId = (int)NULL;
  623. }
  624.     else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0)
  625. semId->events.taskId = (int)NULL;
  626.     }
  627. }
  628.     if (status == ERROR)
  629. {
  630. windExit (); /* KERNEL EXIT */
  631. errnoSet (S_eventLib_EVENTSEND_FAILED);
  632. }
  633.     else
  634. {
  635. errnoSet (oldErrno);
  636. return (windExit ()); /* KERNEL EXIT */
  637. }
  638.     return (status);
  639.     }
  640. /*******************************************************************************
  641. *
  642. * semMGiveKern - put current task on mutex semaphore pend queue
  643. *
  644. * This routine is called if something of consequence occured in giving the
  645. * mutual exclusion semaphore that involved more lengthy processing.  Things
  646. * of consequence are: task to be unblocked, priority to be uninherited, or
  647. * task safety queue of deleters to be flushed.
  648. *
  649. * INTERNAL
  650. * The use of the variables kernWork and semMGiveKernWork looks pretty lame.
  651. * It is, in fact, necessary to facilitate the optimized version of this routine.
  652. * An optimized version would utilize a register for kernWork and stick the
  653. * value in semMGiveKernWork as a parameter to semMGiveKern().  This form of
  654. * parameter passing saves costly stack manipulation.
  655. *
  656. * NOMANUAL
  657. */
  658. STATUS semMGiveKern
  659.     (
  660.     FAST SEM_ID semId   /* semaphore ID to take */
  661.     )
  662.     {
  663.     STATUS evStatus;
  664.     STATUS retStatus = OK;
  665.     int oldErrno = errno;
  666.     if (semMGiveKernWork & SEM_M_Q_GET)
  667. {
  668. #ifdef WV_INSTRUMENTATION
  669.      /* windview - level 2 event logging */
  670. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  671. #endif
  672. windPendQGet (&semId->qHead); /* unblock receiver */
  673. semId->semOwner->pPriMutex = NULL; /* receiver no longer pended */
  674. if (semId->options & SEM_DELETE_SAFE)
  675.     semId->semOwner->safeCnt ++; /* increment receiver safety */
  676. if (semId->options & SEM_INVERSION_SAFE)
  677. semId->semOwner->priMutexCnt ++; /* update inherit count */
  678. }
  679.     if (semMGiveKernWork & SEM_M_PRI_RESORT)
  680. {
  681. windPrioritySet (taskIdCurrent, taskIdCurrent->priNormal);
  682. }
  683.     if (semMGiveKernWork & SEM_M_SAFE_Q_FLUSH)
  684. {
  685. #ifdef WV_INSTRUMENTATION
  686.      /* windview - level 2 event logging */
  687. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  688. #endif
  689. windPendQFlush (&taskIdCurrent->safetyQHead);
  690. }
  691.     if ((semMGiveKernWork & SEM_M_SEND_EVENTS) != 0x0) /* send events */
  692. {
  693. evStatus = eventRsrcSend (semId->events.taskId,
  694.           semId->events.registered);
  695. if (evStatus != OK)
  696.     {
  697.     if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0)
  698. {
  699. oldErrno = S_eventLib_EVENTSEND_FAILED;
  700. retStatus = ERROR;
  701. }
  702.     semId->events.taskId = (int)NULL;
  703.     }
  704. else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0)
  705.     semId->events.taskId = (int)NULL;
  706. }
  707.     if (retStatus == ERROR)
  708. {
  709. windExit ();
  710. errnoSet (oldErrno);
  711. }
  712.     else
  713. {
  714. errnoSet (oldErrno);
  715. retStatus = windExit (); /* KERNEL EXIT */
  716. }
  717.     return (retStatus);
  718.     }
  719. /*******************************************************************************
  720. *
  721. * semMPendQPut - put current task on mutex semaphore pend queue
  722. *
  723. * This routine is called if the mutex semaphore is empty and the caller must
  724. * pend.  It is called inside the kernel with kernelState == TRUE!  It is
  725. * pulled out of semMTake so optimized versions need not bother with the
  726. * following code.
  727. *
  728. * RETURNS: OK, or ERROR if windPendQPut failed.
  729. * NOMANUAL
  730. */
  731. STATUS semMPendQPut
  732.     (
  733.     FAST SEM_ID semId,  /* semaphore ID to take */
  734.     int timeout         /* timeout in ticks */
  735.     )
  736.     {
  737. #ifdef WV_INSTRUMENTATION
  738.     /* windview - level 2 event logging */
  739.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, semId);
  740. #endif
  741.     if (windPendQPut (&semId->qHead, timeout) != OK)
  742. return (ERROR);
  743.     /* if taskIdCurrent is of a higher priority than the task that owns
  744.      * this semaphore, reprioritize the owner.
  745.      */
  746.     if (semId->options & SEM_INVERSION_SAFE)
  747. {
  748. taskIdCurrent->pPriMutex = semId; /* track mutex we pend on */
  749.         if (taskIdCurrent->priority < semId->semOwner->priority)
  750.     {
  751.     windPrioritySet (semId->semOwner, taskIdCurrent->priority);
  752.     }
  753. }
  754.     return (OK);
  755.     }