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

VxWorks

开发平台:

C/C++

  1. /* semCLib.c - counting semaphore library */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02e,03may02,pcm  removed possible NULL dereference in semCCreate () (SPR 76721)
  8. 02d,09nov01,dee  add CPU_FAMILY != COLDFIRE in portable test
  9. 02c,18oct01,bwa  Fixed problem when the semaphore could be deleted while
  10.                  sending events.
  11. 02b,07sep01,bwa  Added VxWorks events support.
  12. 02a,04sep98,cdp  make ARM CPUs with ARM_THUMB==TRUE use portable routines.
  13. 02a,03mar00,zl   merged SH support into T2
  14. 01z,17feb98,cdp  undo 01y: put ARM back in list of optimised CPUs.
  15. 01y,21oct97,kkk  undo 01x, take out ARM from list of optimized CPUs.
  16. 01x,20may97,jpd  added ARM to list of optimised CPUs.
  17. 01w,24jun96,sbs  made windview instrumentation conditionally compiled
  18. 01v,22oct95,jdi  doc: added bit values for semCCreate() options (SPR 4276).
  19. 01u,19mar95,dvs  removing tron references.
  20. 01t,09jun93,hdn  added a support for I80X86
  21. 01w,14apr94,smb  fixed class dereferencing for instrumentation macros
  22. 01v,15mar94,smb  modified instrumentation macros
  23. 01u,24jan94,smb  added instrumentation macros
  24. 01t,10dec93,smb  added instrumentation
  25. 01s,20jan93,jdi  documentation cleanup for 5.1.
  26. 01r,13nov92,jcf  semCCreate call semCLibInit for robustness.
  27. 01q,28jul92,jcf  semC{Create,Init} call semCLibInit for robustness.
  28. 01p,09jul92,rrr  changed xsignal.h to private/sigLibP.h
  29. 01o,04jul92,jcf  added semCLibInit() to fill in semLib tables.
  30. 01n,26may92,rrr  the tree shuffle
  31. 01m,27apr92,rrr  added signal restarting
  32. 01l,15sep91,ajm  added MIPS to list of optimized CPU's
  33. 01k,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. 01j,26sep91,hdn  added conditional flag for TRON optimized code.
  40. 01i,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  41.  doc review by jcf.
  42. 01h,24mar91,jdi  documentation cleanup.
  43. 01g,05oct90,dnw  made semCInit() be NOMANUAL.
  44. 01f,29aug90,jcf  documentation.
  45. 01e,03aug90,jcf  documentation.
  46. 01d,17jul90,dnw  changed to new objAlloc() call.
  47. 01c,05jul90,jcf  optimized version now available.
  48. 01b,26jun90,jcf  merged into one semaphore class.
  49. 01a,20oct89,jcf  written based on v1g of semLib.
  50. */
  51. /*
  52. DESCRIPTION
  53. This library provides the interface to VxWorks counting
  54. semaphores.  Counting semaphores are useful for guarding multiple
  55. instances of a resource.
  56. A counting semaphore may be viewed as a cell in memory whose contents
  57. keep track of a count.  When a task takes a counting semaphore, using
  58. semTake(), subsequent action depends on the state of the count:
  59. .IP (1) 4
  60. If the count is non-zero, it is decremented and the calling task
  61. continues executing.
  62. .IP (2)
  63. If the count is zero, the task will be blocked, pending the availability
  64. of the semaphore.  If a timeout is specified and the timeout expires, the
  65. pended task will be removed from the queue of pended tasks and enter the
  66. ready state with an ERROR status.  A pended task is ineligible for CPU
  67. allocation.  Any number of tasks may be pended simultaneously on the same
  68. counting semaphore.
  69. .LP
  70. When a task gives a semaphore, using semGive(), the next available task in
  71. the pend queue is unblocked.  If no task is pending on this semaphore, the
  72. semaphore count is incremented.  Note that if a semaphore is given, and a
  73. task is unblocked that is of higher priority than the task that called
  74. semGive(), the unblocked task will preempt the calling task.
  75. A semFlush() on a counting semaphore will atomically unblock all pended
  76. tasks in the semaphore queue.  So all tasks will be made ready before any
  77. task actually executes.  The count of the semaphore will remain unchanged.
  78. INTERRUPT USAGE
  79. Counting semaphores may be given but not taken from interrupt level.
  80. CAVEATS
  81. There is no mechanism to give back or reclaim semaphores automatically when
  82. tasks are suspended or deleted.  Such a mechanism, though desirable, is not
  83. currently feasible.  Without explicit knowledge of the state of the guarded
  84. resource or region, reckless automatic reclamation of a semaphore could
  85. leave the resource in a partial state.  Thus, if a task ceases execution
  86. unexpectedly, as with a bus error, currently owned semaphores will not be
  87. given back, effectively leaving a resource permanently unavailable.  The
  88. mutual-exclusion semaphores provided by semMLib offer protection from
  89. unexpected task deletion.
  90. INTERNAL:
  91. WINDVIEW INSTRUMENTATION
  92. Level 1:
  93. semCCreate() causes EVENT_SEMCCREATE
  94. Level 2 (for portable only):
  95. semGive() causes EVENT_OBJ_SEMGIVE
  96. semTake() causes EVENT_OBJ_SEMTAKE
  97. Level 3:
  98. N/A
  99. INCLUDE FILES: semLib.h
  100. SEE ALSO: semLib, semBLib, semMLib,
  101. .pG "Basic OS"
  102. */
  103. /* LINTLIBRARY */
  104. #include "vxWorks.h"
  105. #include "classLib.h"
  106. #include "errno.h"
  107. #include "taskLib.h"
  108. #include "intLib.h"
  109. #include "errnoLib.h"
  110. #include "eventLib.h"
  111. #include "private/eventLibP.h"
  112. #include "private/sigLibP.h"
  113. #include "private/objLibP.h"
  114. #include "private/semLibP.h"
  115. #include "private/windLibP.h"
  116. #include "private/eventP.h"
  117. /* optimized version available for 680X0, MIPS, i86, SH, */
  118. /* COLDFIRE and ARM (excluding Thumb) */
  119. #if (defined(PORTABLE) || 
  120.      ((CPU_FAMILY != MC680X0) && 
  121.       (CPU_FAMILY != MIPS) && 
  122.       (CPU_FAMILY != I80X86) && 
  123.       (CPU_FAMILY != SH) && 
  124.       (CPU_FAMILY != COLDFIRE) && 
  125.       (CPU_FAMILY != ARM)) || 
  126.      ((CPU_FAMILY == ARM) && ARM_THUMB))
  127. #define semCLib_PORTABLE
  128. #endif
  129. /* locals */
  130. LOCAL BOOL semCLibInstalled; /* protect from muliple inits */
  131. /*******************************************************************************
  132. *
  133. * semCLibInit - initialize the binary semaphore management package
  134. * SEE ALSO: semLibInit(1).
  135. * NOMANUAL
  136. */
  137. STATUS semCLibInit (void)
  138.     {
  139.     if (!semCLibInstalled)
  140. {
  141. semGiveTbl [SEM_TYPE_COUNTING] = (FUNCPTR) semCGive;
  142. semTakeTbl [SEM_TYPE_COUNTING] = (FUNCPTR) semCTake;
  143. semFlushTbl [SEM_TYPE_COUNTING] = (FUNCPTR) semQFlush;
  144. semGiveDeferTbl [SEM_TYPE_COUNTING] = (FUNCPTR) semCGiveDefer;
  145. semFlushDeferTbl [SEM_TYPE_COUNTING] = (FUNCPTR) semQFlushDefer;
  146. if (semLibInit () == OK)
  147.     semCLibInstalled = TRUE;
  148. }
  149.     return ((semCLibInstalled) ? OK : ERROR);
  150.     }
  151. /*******************************************************************************
  152. *
  153. * semCCreate - create and initialize a counting semaphore
  154. *
  155. * This routine allocates and initializes a counting semaphore.  The
  156. * semaphore is initialized to the specified initial count.
  157. *
  158. * The <options> parameter specifies the queuing style for blocked tasks.
  159. * Tasks may be queued on a priority basis or a first-in-first-out basis.
  160. * These options are SEM_Q_PRIORITY (0x1) and SEM_Q_FIFO (0x0), respectively.
  161. * That parameter also specifies if semGive() should return ERROR when
  162. * the semaphore fails to send events. This option is turned off by default;
  163. * it is activated by doing a bitwise-OR of SEM_EVENTSEND_ERR_NOTIFY (0x10) 
  164. * with the queuing style of the semaphore.
  165. *
  166. * RETURNS: The semaphore ID, or NULL if memory cannot be allocated.
  167. */
  168. SEM_ID semCCreate
  169.     (
  170.     int         options,                /* semaphore option modes */
  171.     int         initialCount            /* initial count */
  172.     )
  173.     {
  174.     SEM_ID semId;
  175.     if ((!semCLibInstalled) && (semCLibInit () != OK)) /* initialize package */
  176. return (NULL);
  177.     if ((semId = (SEM_ID) objAlloc (semClassId)) == NULL)
  178. return (NULL);
  179.     /* initialize allocated semaphore */
  180.     if (semCInit (semId, options, initialCount) != OK)
  181. {
  182. objFree (semClassId, (char *) semId);
  183. return (NULL);
  184. }
  185. #ifdef WV_INSTRUMENTATION
  186.     /* windview - level 1 event logging */
  187.     EVT_OBJ_3 (OBJ, semId, semClassId,
  188.        EVENT_SEMCCREATE, semId, options, initialCount);
  189. #endif
  190.     return (semId);
  191.     }
  192. /*******************************************************************************
  193. *
  194. * semCInit - initialize a declared counting semaphore
  195. *
  196. * The initialization of a static counting semaphore, or a counting semaphore
  197. * embedded in some larger object need not deal with allocation.
  198. * This routine may be called to initialize such a semaphore.  The semaphore
  199. * is initialized to the specified initial count.
  200. *
  201. * Counting semaphore options include the queuing style for blocked tasks.
  202. * Tasks may be queued on the basis of their priority or first-in-first-out.
  203. * These options are SEM_Q_PRIORITY and SEM_Q_FIFO respectively.
  204. *
  205. * SEE ALSO: semCCreate
  206. *
  207. * NOMANUAL
  208. */
  209. STATUS semCInit
  210.     (
  211.     SEMAPHORE   *pSemaphore,            /* pointer to semaphore to init */
  212.     int         options,                /* semaphore options */
  213.     int         initialCount            /* initial count */
  214.     )
  215.     {
  216.     if ((!semCLibInstalled) && (semCLibInit () != OK)) /* initialize package */
  217. return (ERROR);
  218.     if (semQInit (pSemaphore, options) != OK) /* initialize queue */
  219. return (ERROR);
  220.     return (semCCoreInit (pSemaphore, options, initialCount));
  221.     }
  222. /*******************************************************************************
  223. *
  224. * semCCoreInit - initialize a counting semaphore with queue already initialized
  225. *
  226. * To initialize a semaphore with some special queuing algorithm, this routine
  227. * is used.  This routine will initialize a counting semaphore without
  228. * initializing the queue.
  229. *
  230. * ERRNO: S_semLib_INVALID_OPTION
  231. *
  232. * NOMANUAL
  233. */
  234. STATUS semCCoreInit
  235.     (
  236.     SEMAPHORE   *pSemaphore,            /* pointer to semaphore to init */
  237.     int         options,                /* semaphore options */
  238.     int         initialCount            /* initial count */
  239.     )
  240.     {
  241.     if ((options & SEM_INVERSION_SAFE) || (options & SEM_DELETE_SAFE))
  242. {
  243. errno = S_semLib_INVALID_OPTION;
  244. return (ERROR);
  245. }
  246.     pSemaphore->semCount = initialCount; /* initialize count */
  247.     pSemaphore->recurse  = 0; /* no recursive takes */
  248.     pSemaphore->options  = options; /* stow away options */
  249.     pSemaphore->semType  = SEM_TYPE_COUNTING; /* type is counting */
  250.     eventInit (&pSemaphore->events); /* initialize events */
  251.     /* initialize the semaphore object core information */
  252. #ifdef WV_INSTRUMENTATION
  253.     /* windview - connect instrumented class for level 1 event logging */
  254.     if (wvObjIsEnabled) objCoreInit (&pSemaphore->objCore, semInstClassId);
  255.     else
  256. #endif
  257.     objCoreInit (&pSemaphore->objCore, semClassId);
  258.     return (OK);
  259.     }
  260. #ifdef semCLib_PORTABLE
  261. /*******************************************************************************
  262. *
  263. * semCGive - give a semaphore
  264. *
  265. * Gives the semaphore.  If a higher priority task has already taken
  266. * the semaphore (so that it is now pended waiting for it), that task
  267. * will now become ready to run, and preempt the task that does the semGive().
  268. * If the semaphore is already full (it has been given but not taken) this
  269. * call is essentially a no-op.
  270. *
  271. * NOMANUAL
  272. */
  273. STATUS semCGive
  274.     (
  275.     SEM_ID semId        /* semaphore ID to give */
  276.     )
  277.     {
  278.     int level = intLock (); /* LOCK INTERRUPTS */
  279.     if (OBJ_VERIFY (semId, semClassId) != OK)
  280. {
  281. intUnlock (level); /* UNLOCK INTERRUPTS */
  282. return (ERROR);
  283. }
  284.     if (Q_FIRST (&semId->qHead) == NULL)
  285. {
  286. int     oldErrno;
  287. STATUS  evStatus;
  288. STATUS  retStatus;
  289. semId->semCount ++; /* give semaphore */
  290. retStatus = OK;
  291. if (semId->events.taskId != (int)NULL)
  292.     {
  293.     kernelState = TRUE;
  294.     intUnlock (level);
  295.     oldErrno = errno;
  296.     evStatus = eventRsrcSend (semId->events.taskId,
  297.       semId->events.registered);
  298.     if(evStatus != OK)
  299. {
  300. if ((semId->options & SEM_EVENTSEND_ERR_NOTIFY) != 0x0)
  301.     {
  302.     retStatus = ERROR;
  303.     oldErrno = S_eventLib_EVENTSEND_FAILED;
  304.     }
  305.         semId->events.taskId = (int)NULL;
  306. }
  307.     else if ((semId->events.options & EVENTS_SEND_ONCE) != 0x0)
  308.         semId->events.taskId = (int)NULL;
  309.     windExit ();
  310.     errno = oldErrno;
  311.     return (retStatus);
  312.     }
  313. else
  314.     intUnlock (level);
  315. }
  316.     else
  317. {
  318. kernelState = TRUE; /* KERNEL ENTER */
  319. intUnlock (level); /* UNLOCK INTERRUPTS */
  320. #ifdef WV_INSTRUMENTATION
  321. /* windview - level 2 event logging */
  322. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  323. #endif
  324. windPendQGet (&semId->qHead); /* unblock a task */
  325. windExit (); /* KERNEL EXIT */
  326. }
  327.     return (OK);
  328.     }
  329. /*******************************************************************************
  330. *
  331. * semCTake - take a semaphore
  332. *
  333. * Takes the semaphore.  If the semaphore is empty, i.e., it has not been given
  334. * since the last semTake() or semInit(), this task will become pended until
  335. * the semaphore becomes available by some other task doing a semGive()
  336. * of it.  If the semaphore is already available, this call will empty
  337. * the semaphore, so that no other task can take it until this task gives
  338. * it back, and this task will continue running.
  339. *
  340. * WARNING
  341. * This routine may not be used from interrupt level.
  342. *
  343. * NOMANUAL
  344. */
  345. STATUS semCTake
  346.     (
  347.     SEM_ID semId,       /* semaphore ID to take */
  348.     int timeout         /* timeout in ticks */
  349.     )
  350.     {
  351.     int level;
  352.     int status;
  353.     if (INT_RESTRICT () != OK) /* restrict isr use */
  354. return (ERROR);
  355. again:
  356.     level = intLock (); /* LOCK INTERRUPTS */
  357.     if (OBJ_VERIFY (semId, semClassId) != OK)
  358. {
  359. intUnlock (level); /* UNLOCK INTERRUPTS */
  360. return (ERROR);
  361. }
  362.     if (semId->semCount > 0)
  363. {
  364. semId->semCount --; /* take semaphore */
  365. intUnlock (level); /* UNLOCK INTERRUPTS */
  366. return (OK); }
  367.     kernelState = TRUE; /* KERNEL ENTER */
  368.     intUnlock (level); /* UNLOCK INTERRUPTS */
  369. #ifdef WV_INSTRUMENTATION
  370.     /* windview - level 2 event logging */
  371.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, semId);
  372. #endif
  373.     if (windPendQPut (&semId->qHead, timeout) != OK)
  374. {
  375. windExit (); /* KERNEL EXIT */
  376. return (ERROR);
  377. }
  378.     if ((status = windExit ()) == RESTART) /* KERNEL EXIT */
  379. {
  380. timeout = SIG_TIMEOUT_RECALC(timeout);
  381. goto again;
  382. }
  383.     return (status);
  384.     }
  385. #endif /* semCLib_PORTABLE */
  386. /*******************************************************************************
  387. *
  388. * semCGiveDefer - give a semaphore as deferred work
  389. *
  390. * Gives the semaphore.  If a higher priority task has already taken
  391. * the semaphore (so that it is now pended waiting for it), that task
  392. * will now become ready to run, and preempt the task that does the semGive().
  393. * If the semaphore is already full (it has been given but not taken) this
  394. * call is essentially a no-op.
  395. *
  396. * NOMANUAL
  397. */
  398. void semCGiveDefer
  399.     (
  400.     SEM_ID semId        /* semaphore ID to give */
  401.     )
  402.     {
  403.      if (Q_FIRST (&semId->qHead) == NULL) /* anyone blocked? */
  404. {
  405. semId->semCount ++; /* give semaphore */
  406. /* sem is free, send events if registered */
  407. if (semId->events.taskId != (int)NULL)
  408.     {
  409.     if (eventRsrcSend (semId->events.taskId,
  410.        semId->events.registered) != OK)
  411. {
  412. semId->events.taskId = (int)NULL;
  413. return;
  414. }
  415.     if ((semId->events.options & EVENTS_SEND_ONCE) == EVENTS_SEND_ONCE)
  416. semId->events.taskId = (int)NULL;
  417.     }
  418. }
  419.      else
  420. {
  421. #ifdef WV_INSTRUMENTATION
  422.         /* windview - level 2 event logging */
  423. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, semId);
  424. #endif
  425. windPendQGet (&semId->qHead); /* unblock a task */
  426. }
  427.     }