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

VxWorks

开发平台:

C/C++

  1. /* semBLib.c - binary semaphore library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02h,03may02,pcm  removed possible NULL dereference in semBCreate () (SPR 76721)
  8. 02g,09nov01,dee  add CPU_FAMILY != COLDFIRE in portable test
  9. 02f,18oct01,bwa  Fixed problem when the semaphore could be deleted while
  10.                  sending events.
  11. 02e,06sep01,bwa  Added VxWorks events support.
  12. 02d,04sep98,cdp  make ARM CPUs with ARM_THUMB==TRUE use portable routines.
  13. 02d,03mar00,zl   merged SH support into T2
  14. 02c,17feb98,cdp  undo 02b: put ARM back in list of optimised CPUs.
  15. 02b,21oct97,kkk  undo 02a, take out ARM from list of optimized CPUs.
  16. 02a,19may97,jpd  added ARM to list of optimised CPUs.
  17. 01z,24jun96,sbs  made windview instrumentation conditionally compiled
  18. 01y,22oct95,jdi  doc: added bit values for semBCreate() options (SPR 4276).
  19. 01w,19mar95,dvs  removed tron references.
  20. 01v,09jun93,hdn  added a support for I80X86
  21. 01y,14apr94,smb  fixed class dereferencing for instrumentation macros
  22. 01x,15mar94,smb  modified instrumentation macros
  23. 01w,24jan94,smb  added instrumentation macros
  24. 01v,10dec93,smb  added instrumentation
  25. 01u,23jan93,jdi  documentation cleanup for 5.1.
  26. 01t,13nov92,jcf  semBCreate call semBLibInit for robustness.
  27. 01s,28jul92,jcf  semB{Create,Init} call semBLibInit for robustness.
  28. 01r,09jul92,rrr  changed xsignal.h to private/sigLibP.h
  29. 01q,04jul92,jcf  tables now start as null to reduce coupling; private headers
  30. 01p,26may92,rrr  the tree shuffle
  31. 01o,27apr92,rrr  added signal restarting
  32. 01n,15sep91,ajm  added MIPS to list of optimized CPU's
  33. 01m,04oct91,rrr  passed through the ansification filter
  34.                   -changed functions to ansi style
  35.   -changed includes to have absolute path from h/
  36.   -fixed #else and #endif
  37.   -changed VOID to void
  38.   -changed copyright notice
  39. 01l,26sep91,hdn  added conditional flag for TRON optimized code.
  40. 01k,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  41.  doc review by jcf.
  42. 01j,25mar91,del  fixed bug introduced in 02i that wouldn't allow build.
  43. 01i,24mar91,jdi  documentation cleanup.
  44. 01h,05oct90,dnw  made semBInit() be NOMANUAL.
  45. 01g,29aug90,jcf  documentation.
  46. 01f,03aug90,jcf  documentation.
  47. 01e,17jul90,dnw  changed to new objAlloc() call
  48. 01d,05jul90,jcf  optimized version now available.
  49. 01c,26jun90,jcf  merged to one semaphore class.
  50. 01b,11may90,jcf  fixed up PORTABLE definition.
  51. 01a,20oct89,jcf  written based on v1g of semLib.
  52. */
  53. /*
  54. DESCRIPTION
  55. This library provides the interface to VxWorks binary semaphores.
  56. Binary semaphores are the most versatile, efficient, and conceptually
  57. simple type of semaphore.  They can be used to: (1) control mutually
  58. exclusive access to shared devices or data structures, or (2) synchronize
  59. multiple tasks, or task-level and interrupt-level processes.  Binary
  60. semaphores form the foundation of numerous VxWorks facilities.
  61. A binary semaphore can be viewed as a cell in memory whose contents are in
  62. one of two states, full or empty.  When a task takes a binary semaphore,
  63. using semTake(), subsequent action depends on the state of the semaphore:
  64. .IP (1) 4
  65. If the semaphore is full, the semaphore is made empty, and the calling task
  66. continues executing.
  67. .IP (2)
  68. If the semaphore is empty, the task will be blocked, pending the
  69. availability of the semaphore.  If a timeout is specified and the timeout
  70. expires, the pended task will be removed from the queue of pended tasks
  71. and enter the ready state with an ERROR status.  A pended task
  72. is ineligible for CPU allocation.  Any number of tasks may be pended
  73. simultaneously on the same binary semaphore.
  74. .LP
  75. When a task gives a binary semaphore, using semGive(), the next available
  76. task in the pend queue is unblocked.  If no task is pending on this
  77. semaphore, the semaphore becomes full.  Note that if a semaphore is given,
  78. and a task is unblocked that is of higher priority than the task that called
  79. semGive(), the unblocked task will preempt the calling task.
  80. MUTUAL EXCLUSION
  81. To use a binary semaphore as a means of mutual exclusion, first create it
  82. with an initial state of full.  For example:
  83. .CS
  84. .ne 4
  85.     SEM_ID semMutex;
  86.     /@ create a binary semaphore that is initially full @/
  87.     semMutex = semBCreate (SEM_Q_PRIORITY, SEM_FULL);
  88. .CE
  89. Then guard a critical section or resource by taking the semaphore with
  90. semTake(), and exit the section or release the resource by giving
  91. the semaphore with semGive().  For example:
  92. .CS
  93. .ne 4
  94.     semTake (semMutex, WAIT_FOREVER);
  95.         ...  /@ critical region, accessible only by one task at a time @/
  96.     
  97.     semGive (semMutex);
  98. .CE
  99. While there is no restriction on the same semaphore being given, taken, or
  100. flushed by multiple tasks, it is important to ensure the proper
  101. functionality of the mutual-exclusion construct.  While there is no danger
  102. in any number of processes taking a semaphore, the giving of a semaphore
  103. should be more carefully controlled.  If a semaphore is given by a task that
  104. did not take it, mutual exclusion could be lost.
  105. SYNCHRONIZATION
  106. To use a binary semaphore as a means of synchronization, create it
  107. with an initial state of empty.  A task blocks by taking a semaphore
  108. at a synchronization point, and it remains blocked until the semaphore is given
  109. by another task or interrupt service routine.
  110. Synchronization with interrupt service routines is a particularly common need.
  111. Binary semaphores can be given, but not taken, from interrupt level.  Thus, a
  112. task can block at a synchronization point with semTake(), and an interrupt
  113. service routine can unblock that task with semGive().
  114. In the following example, when init() is called, the binary semaphore is
  115. created, an interrupt service routine is attached to an event, and a task
  116. is spawned to process the event.  Task 1 will run until it calls semTake(),
  117. at which point it will block until an event causes the interrupt service
  118. routine to call semGive().  When the interrupt service routine completes,
  119. task 1 can execute to process the event.
  120. .CS
  121. .ne 8
  122.     SEM_ID semSync;    /@ ID of sync semaphore @/
  123.     init ()
  124. {
  125. intConnect (..., eventInterruptSvcRout, ...);
  126. semSync = semBCreate (SEM_Q_FIFO, SEM_EMPTY);
  127. taskSpawn (..., task1);
  128. }
  129. .ne 6
  130.     task1 ()
  131. {
  132. ...
  133. semTake (semSync, WAIT_FOREVER);    /@ wait for event @/
  134. ...    /@ process event @/
  135. }
  136. .ne 6
  137.     eventInterruptSvcRout ()
  138. {
  139. ...
  140. semGive (semSync);    /@ let task 1 process event @/
  141. ...
  142. }
  143. .CE
  144. A semFlush() on a binary semaphore will atomically unblock all pended
  145. tasks in the semaphore queue, i.e., all tasks will be unblocked at once,
  146. before any actually execute.
  147. CAVEATS
  148. There is no mechanism to give back or reclaim semaphores automatically when
  149. tasks are suspended or deleted.  Such a mechanism, though desirable, is not
  150. currently feasible.  Without explicit knowledge of the state of the guarded
  151. resource or region, reckless automatic reclamation of a semaphore could
  152. leave the resource in a partial state.  Thus, if a task ceases execution
  153. unexpectedly, as with a bus error, currently owned semaphores will not be
  154. given back, effectively leaving a resource permanently unavailable.  The
  155. mutual-exclusion semaphores provided by semMLib offer protection from
  156. unexpected task deletion.
  157. INTERNAL:
  158. WINDVIEW INSTRUMENTATION
  159. Level 1:
  160. semBCreate() causes EVENT_SEMBCREATE
  161. Level 2 (portable only):
  162. semGive() causes EVENT_OBJ_SEMGIVE
  163. semTake() causes EVENT_OBJ_SEMTAKE
  164. Level 3:
  165. N/A
  166. INCLUDE FILES: semLib.h
  167. SEE ALSO: semLib, semCLib, semMLib,
  168. .pG "Basic OS"
  169. */
  170. #include "vxWorks.h"
  171. #include "errno.h"
  172. #include "taskLib.h"
  173. #include "intLib.h"
  174. #include "errnoLib.h"
  175. #include "eventLib.h"
  176. #include "private/eventLibP.h"
  177. #include "private/sigLibP.h"
  178. #include "private/objLibP.h"
  179. #include "private/semLibP.h"
  180. #include "private/windLibP.h"
  181. #include "private/eventP.h"
  182. /* optimized version available for 680X0, MIPS, I80X86, SH, */
  183. /* COLDFIRE, ARM (excluding Thumb) */
  184. #if (defined(PORTABLE) || 
  185.      ((CPU_FAMILY != MC680X0) && 
  186.       (CPU_FAMILY != MIPS) && 
  187.       (CPU_FAMILY != I80X86) && 
  188.       (CPU_FAMILY != SH) && 
  189.       (CPU_FAMILY != COLDFIRE) && 
  190.       (CPU_FAMILY != ARM)) || 
  191.      ((CPU_FAMILY == ARM) && ARM_THUMB))
  192. #define semBLib_PORTABLE
  193. #endif
  194. /* locals */
  195. LOCAL BOOL semBLibInstalled; /* protect from muliple inits */
  196. /*******************************************************************************
  197. *
  198. * semBLibInit - initialize the binary semaphore management package
  199. * SEE ALSO: semLibInit(1).
  200. * NOMANUAL
  201. */
  202. STATUS semBLibInit (void)
  203.     {
  204.     if (!semBLibInstalled)
  205. {
  206. semGiveTbl [SEM_TYPE_BINARY] = (FUNCPTR) semBGive;
  207. semTakeTbl [SEM_TYPE_BINARY] = (FUNCPTR) semBTake;
  208. semFlushTbl [SEM_TYPE_BINARY] = (FUNCPTR) semQFlush;
  209. semGiveDeferTbl [SEM_TYPE_BINARY] = (FUNCPTR) semBGiveDefer;
  210. semFlushDeferTbl [SEM_TYPE_BINARY] = (FUNCPTR) semQFlushDefer;
  211. if (semLibInit () == OK)
  212.     semBLibInstalled = TRUE;
  213. }
  214.     return ((semBLibInstalled) ? OK : ERROR);
  215.     }
  216. /*******************************************************************************
  217. *
  218. * semBCreate - create and initialize a binary semaphore
  219. *
  220. * This routine allocates and initializes a binary semaphore.  The semaphore
  221. * is initialized to the <initialState> of either SEM_FULL (1) or SEM_EMPTY (0).
  222. *
  223. * The <options> parameter specifies the queuing style for blocked tasks.
  224. * Tasks can be queued on a priority basis or a first-in-first-out basis.
  225. * These options are SEM_Q_PRIORITY (0x1) and SEM_Q_FIFO (0x0), respectively.
  226. * That parameter also specifies if semGive() should return ERROR when
  227. * the semaphore fails to send events. This option is turned off by default;
  228. * it is activated by doing a bitwise-OR of SEM_EVENTSEND_ERR_NOTIFY (0x10)
  229. * with the queuing style of the semaphore.
  230. *
  231. *
  232. * RETURNS: The semaphore ID, or NULL if memory cannot be allocated.
  233. */
  234. SEM_ID semBCreate
  235.     (
  236.     int         options,                /* semaphore options */
  237.     SEM_B_STATE initialState            /* initial semaphore state */
  238.     )
  239.     {
  240.     SEM_ID semId;
  241.     if ((!semBLibInstalled) && (semBLibInit () != OK)) /* initialize package */
  242. return (NULL);
  243.     if ((semId = (SEM_ID) objAlloc (semClassId)) == NULL)
  244. return (NULL);
  245.     /* initialize allocated semaphore */
  246.     if (semBInit (semId, options, initialState) != OK)
  247. {
  248. objFree (semClassId, (char *) semId);
  249. return (NULL);
  250. }
  251. #ifdef WV_INSTRUMENTATION
  252.     /* windview - level 1 event logging */
  253.     EVT_OBJ_3 (OBJ, semId, semClassId,
  254.        EVENT_SEMBCREATE, semId, options, semId->state);
  255. #endif
  256.     return (semId);
  257.     }
  258. /*******************************************************************************
  259. *
  260. * semBInit - initialize a declared binary semaphore
  261. *
  262. * The initialization of a static binary semaphore, or a binary semaphore
  263. * embedded in some larger object need not deal with allocation.
  264. * This routine may be called to initialize such a semaphore.  The semaphore
  265. * is initialized to the specified initial state of either SEM_FULL or SEM_EMPTY.
  266. *
  267. * Binary semaphore options include the queuing style for blocked tasks.
  268. * Tasks can be queued on the basis of their priority or first-in-first-out.
  269. * These options are SEM_Q_PRIORITY and SEM_Q_FIFO respectively.
  270. *
  271. * SEE ALSO: semBCreate()
  272. *
  273. * NOMANUAL
  274. */
  275. STATUS semBInit
  276.     (
  277.     SEMAPHORE  *pSemaphore,             /* pointer to semaphore to initialize */
  278.     int         options,                /* semaphore options */
  279.     SEM_B_STATE initialState            /* initial semaphore state */
  280.     )
  281.     {
  282.     if ((!semBLibInstalled) && (semBLibInit () != OK)) /* initialize package */
  283. return (ERROR);
  284.     if (semQInit (pSemaphore, options) != OK) /* initialize queue */
  285. return (ERROR);
  286.     return (semBCoreInit (pSemaphore, options, initialState));
  287.     }
  288. /*******************************************************************************
  289. *
  290. * semBCoreInit - initialize a binary semaphore with queue already initialized
  291. *
  292. * To initialize a semaphore with some special queuing algorithm, this routine
  293. * is used.  This routine will initialize a binary semaphore without
  294. * initializing the queue.
  295. *
  296. * ERRNO: S_semLib_INVALID_OPTION, S_semLib_INVALID_STATE
  297. *
  298. * NOMANUAL
  299. */
  300. STATUS semBCoreInit
  301.     (
  302.     SEMAPHORE  *pSemaphore,             /* pointer to semaphore to initialize */
  303.     int         options,                /* semaphore options */
  304.     SEM_B_STATE initialState            /* initial semaphore state */
  305.     )
  306.     {
  307.     if ((options & SEM_INVERSION_SAFE) || (options & SEM_DELETE_SAFE))
  308. {
  309. errno = S_semLib_INVALID_OPTION;
  310. return (ERROR);
  311. }
  312.     switch (initialState)
  313. {
  314. case SEM_EMPTY:
  315.     pSemaphore->semOwner = taskIdCurrent; /* semaphore empty */
  316.     break;
  317. case SEM_FULL:
  318.     pSemaphore->semOwner = NULL; /* semaphore full */
  319.     break;
  320. default:
  321.     errno = S_semLib_INVALID_STATE;
  322.     return (ERROR);
  323. }
  324.     pSemaphore->recurse = 0; /* no recursive takes */
  325.     pSemaphore->options = options; /* stow away options */
  326.     pSemaphore->semType = SEM_TYPE_BINARY; /* type is binary */
  327.     eventInit (&pSemaphore->events); /* initialize events */
  328. #ifdef WV_INSTRUMENTATION
  329.     /* windview - connect instrumented class for level 1 event logging */
  330.     if (wvObjIsEnabled)
  331.         objCoreInit (&pSemaphore->objCore, semInstClassId);
  332.     else 
  333. #endif
  334.     objCoreInit (&pSemaphore->objCore, semClassId); /* initialize core */
  335.     return (OK);
  336.     }
  337. #ifdef semBLib_PORTABLE
  338. /*******************************************************************************
  339. *
  340. * semBGive - give semaphore
  341. *
  342. * Gives the semaphore.  If a higher priority task has already taken
  343. * the semaphore (so that it is now pended waiting for it), that task
  344. * will now become ready to run, and preempt the task that does the semGive().
  345. * If the semaphore is already full (it has been given but not taken) this
  346. * call is essentially a no-op.
  347. *
  348. * NOMANUAL
  349. */
  350. STATUS semBGive
  351.     (
  352.     SEM_ID semId        /* semaphore ID to give */
  353.     )
  354.     {
  355.     int level = intLock (); /* LOCK INTERRUPTS */
  356.     WIND_TCB * pOwner;
  357.     if (OBJ_VERIFY (semId, semClassId) != OK)
  358. {
  359. intUnlock (level); /* UNLOCK INTERRUPTS */
  360. return (ERROR);
  361. }
  362.     pOwner = semId->semOwner;
  363.     if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) == NULL)
  364. {
  365. int     oldErrno;
  366. STATUS  evStatus;
  367. STATUS  retStatus;
  368. retStatus = OK;
  369. /* check change of state; if so, send events */
  370. if ((semId->events.taskId != (int)NULL) && (pOwner != NULL))
  371.     {
  372.     kernelState = TRUE;
  373.     intUnlock (level); /* UNLOCK INTERRUPTS */
  374.     oldErrno = errno;
  375.     evStatus = eventRsrcSend(semId->events.taskId,
  376.      semId->events.registered);
  377.     if (evStatus != OK)
  378. {
  379. if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0)
  380.     {
  381.     retStatus = ERROR;
  382.     oldErrno = S_eventLib_EVENTSEND_FAILED;
  383.     }
  384. semId->events.taskId = (int)NULL;
  385. }
  386.     else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0)
  387. semId->events.taskId = (int)NULL;
  388.     windExit ();
  389.     errno = oldErrno;
  390.     return (retStatus);
  391.     }
  392. else
  393.     intUnlock (level);
  394. }
  395.     else
  396. {
  397. kernelState = TRUE; /* KERNEL ENTER */ 
  398. intUnlock (level); /* UNLOCK INTERRUPTS */
  399. #ifdef WV_INSTRUMENTATION
  400. /* windview - level 2 event logging */
  401. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  402. #endif
  403. windPendQGet (&semId->qHead); /* unblock a task */
  404. windExit (); /* KERNEL EXIT */
  405. }
  406.     return (OK);
  407.     }
  408. /*******************************************************************************
  409. *
  410. * semBTake - take semaphore
  411. *
  412. * Takes the semaphore.  If the semaphore is empty, i.e., it has not been given
  413. * since the last semTake() or semInit(), this task will become pended until
  414. * the semaphore becomes available by some other task doing a semGive()
  415. * of it.  If the semaphore is already available, this call will empty
  416. * the semaphore, so that no other task can take it until this task gives
  417. * it back, and this task will continue running.
  418. *
  419. * WARNING
  420. * This routine may not be used from interrupt level.
  421. *
  422. * NOMANUAL
  423. */
  424. STATUS semBTake
  425.     (
  426.     SEM_ID semId,       /* semaphore ID to take */
  427.     int timeout         /* timeout in ticks */
  428.     )
  429.     {
  430.     int level;
  431.     int status;
  432.     if (INT_RESTRICT () != OK)
  433. return (ERROR);
  434. again:
  435.     level = intLock (); /* LOCK INTERRUPTS */
  436.     if (OBJ_VERIFY (semId, semClassId) != OK)
  437. {
  438. intUnlock (level); /* UNLOCK INTERRUPTS */
  439. return (ERROR);
  440. }
  441.     if (semId->semOwner == NULL)
  442. {
  443. semId->semOwner = taskIdCurrent; /* update semaphore state */
  444. intUnlock (level); /* UNLOCK INTERRUPTS */
  445. return (OK);
  446. }
  447.     kernelState = TRUE; /* KERNEL ENTER */
  448.     intUnlock (level); /* UNLOCK INTERRUPTS */
  449. #ifdef WV_INSTRUMENTATION
  450.     /* windview - level 2 event logging */
  451.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, semId);
  452. #endif
  453.     if (windPendQPut (&semId->qHead, timeout) != OK)
  454. {
  455. windExit (); /* KERNEL EXIT */
  456. return (ERROR);
  457. }
  458.     if ((status = windExit ()) == RESTART) /* KERNEL EXIT */
  459. {
  460. timeout = SIG_TIMEOUT_RECALC(timeout);
  461. goto again;
  462. }
  463.     return (status);
  464.     }
  465. #endif /* semBLib_PORTABLE */
  466. /*******************************************************************************
  467. *
  468. * semBGiveDefer - give semaphore as deferred work
  469. *
  470. * Gives the semaphore.  If a higher priority task has already taken
  471. * the semaphore (so that it is now pended waiting for it), that task
  472. * will now become ready to run, and preempt the task that does the semGive().
  473. * If the semaphore is already full (it has been given but not taken) this
  474. * call is essentially a no-op.
  475. *
  476. * NOMANUAL
  477. */
  478. void semBGiveDefer
  479.     ( SEM_ID semId        /* semaphore ID to give */
  480.     )
  481.     {
  482.     WIND_TCB * pOwner = semId->semOwner;
  483.     if ((semId->semOwner = (WIND_TCB *) Q_FIRST (&semId->qHead)) != NULL)
  484. {
  485. #ifdef WV_INSTRUMENTATION
  486.      /* windview - level 2 event logging */
  487. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  488. #endif
  489. windPendQGet (&semId->qHead); /* unblock a task */
  490. }
  491.     else /* check for change of state, send events if registered */
  492. {
  493. if ((semId->events.taskId != (int)NULL) && (pOwner != NULL))
  494.     {
  495.     if (eventRsrcSend(semId->events.taskId,
  496.       semId->events.registered) != OK)
  497. {
  498. semId->events.taskId = (int)NULL;
  499. }
  500.     else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0 )
  501. semId->events.taskId = (int)NULL;
  502.     }
  503. }
  504.     }