semSmLib.c
上传用户:baixin
上传日期:2008-03-13
资源大小:4795k
文件大小:35k
开发平台:

MultiPlatform

  1. /* semSmLib.c - shared memory semaphore library (VxMP Option) */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01n,06may02,mas  cache flush and volatile fix (SPR 68334); bridge flush fix
  7.  (SPR 68844)
  8. 01m,24oct01,mas  doc update (SPR 71149)
  9. 01l,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  10. 01k,22feb99,wsl  doc: fixed typo in errno code
  11. 01j,22mar94,pme  added WindView level event logging.
  12. 01i,24feb93,jdi  doc tweaks.
  13. 01h,08feb93,jdi  documentation cleanup.
  14. 01g,29jan93,pme  added little endian support.
  15. 01f,23nov92,jdi  documentation cleanup.
  16. 01e,13nov92,dnw  added include of smObjLib.h
  17. 01d,02oct92,pme  added SPARC support. documentation cleanup.
  18. 01c,29sep92,pme  changed semSm[BC]Create to sem[BC]SmCreate
  19.  comments cleanup
  20. 01b,30jul92,pme  changed semSm[BC]Init to call qFifoGInit.
  21.  added signal restarting.
  22.  semSm{Create,Init} call semSmLibInit for robustness.
  23.  documentation cleanup.
  24. 01a,19jul92,pme  added semSmLibInit() to reduce coupling.
  25.                  reduced interrupt latency in semSmGive and semSmTake.
  26.                  merged shared counting and binary semaphores.
  27.                  code review clean up.
  28.                  written.
  29. */
  30. /*
  31. DESCRIPTION
  32. This library provides the interface to VxWorks shared memory binary and
  33. counting semaphores.  Once a shared memory semaphore is created, the
  34. generic semaphore-handling routines provided in semLib are used to
  35. manipulate it.  Shared memory binary semaphores are created using
  36. semBSmCreate().  Shared memory counting semaphores are created using
  37. semCSmCreate().
  38. Shared memory binary semaphores are used to:  (1) control mutually
  39. exclusive access to multiprocessor-shared data structures, or (2)
  40. synchronize multiple tasks running in a multiprocessor system.  For
  41. general information about binary semaphores, see the manual entry
  42. semBLib.
  43. Shared memory counting semaphores are used for guarding multiple instances
  44. of a resource used by multiple CPUs.  For general information about shared
  45. counting semaphores, see the manual entry for semCLib.
  46. For information about the generic semaphore-handling routines, see the
  47. manual entry for semLib.
  48. MEMORY REQUIREMENTS
  49. The semaphore structure is allocated from a dedicated shared memory partition.
  50. The shared semaphore dedicated shared memory partition is initialized by
  51. the shared memory objects master CPU.  The size of this partition is
  52. defined by the maximum number of shared semaphores, set in the configuration
  53. parameter SM_OBJ_MAX_SEM .
  54. This memory partition is common to shared binary and counting semaphores,
  55. thus SM_OBJ_MAX_SEM must be set to the sum total of binary and counting
  56. semaphores to be used in the system.
  57. RESTRICTIONS
  58. Shared memory semaphores differ from local semaphores in the following ways:
  59. is
  60. i `Interrupt Use:'
  61. Shared semaphores may not be given, taken, or flushed at interrupt level.
  62. i `Deletion:'
  63. There is no way to delete a shared semaphore and free its associated
  64. shared memory.  Attempts to delete a shared semaphore return ERROR and
  65. set `errno' to S_smObjLib_NO_OBJECT_DESTROY .
  66. i `Queuing Style:'
  67. The shared semaphore queuing style specified when the semaphore is created 
  68. must be FIFO.
  69. ie
  70. INTERRUPT LATENCY
  71. Internally, interrupts are locked while manipulating shared semaphore 
  72. data structures, thus increasing local CPU interrupt latency.
  73. CONFIGURATION
  74. Before routines in this library can be called, the shared memory object
  75. facility must be initialized by calling usrSmObjInit().  This is done
  76. automatically during VxWorks initialization when the component INCLUDE_SM_OBJ
  77. is included.
  78. AVAILABILITY
  79. This module is distributed as a component of the unbundled shared memory
  80. support option, VxMP.
  81. INTERNAL
  82. To achieve full transparency, semBSmCreate() and semCSmCreate() returns 
  83. a semaphore of type SEM_ID but the effective structure pointed to by 
  84. this ID is a SM_SEMAPHORE.
  85. When a task blocks on a shared semaphore a data structure called shared
  86. memory object task control block (smObjTcb) is added to the shared 
  87. semaphore pend queue.  This smObjTcb is allocated from a dedicated 
  88. fixed block size shared memory partition the first time the task
  89. blocks on a shared semaphore or after each restart signal or timeout
  90. occuring while taking a shared semaphore.
  91. In order to use the standard wind kernel routines we use a pseudo multi-way
  92. queue to manipulate the shared queues and nodes (actually shared TCBs). 
  93. We have defined a new class of queue called qFifoG for which the queue head
  94. contains :
  95.        - a pointer to qFifoGClass.
  96.        - a pointer to the Fifo pending queue associated with the
  97.          shared object where task is pending on.
  98.        - a pointer to the shared memory object pend queue lock.  This
  99.          pointer is initialized to NULL if we already have the lock.
  100.          This pointer is necessary because when a timeout expires,
  101.          when a signal is sent to the task, or when a task is deleted 
  102.  Q_REMOVE is called to remove the shared TCB from the semaphore 
  103.  pending list without having previously acquired semaphore 
  104.  lock access.  Thus only qFifoGRemove(), which is called by Q_REMOVE ,
  105.          need to check if this pointer is NULL before manipulating the queue.
  106. - Shared Semaphore Flush
  107. The issue here is to keep a per CPU semaphore flush indivisibility while
  108. keeping a reasonable interrupt latency.  Note that a system wide flush
  109. indivisibility is impossible to achieve.
  110. This implies that only one notification is made to any CPU where there's
  111. one or more tasks pending on the flushed semaphore.
  112. Since no modifications are made to the semaphore status, semaphore flush
  113. is the same for binary and counting semaphores and is called semSmFlush().
  114. - Optional Facility:
  115. Since this facility is optional, 'flush', 'give' and 'take' routines are
  116. called via function pointers in semFlush(), semGive(), and semTake(),
  117. respectively, to avoid this code being imported into VxWorks when the VxMP
  118. option is not available.
  119. Functions pointers are initialized by semSmLibInit() which is called
  120. in smObjInit().
  121. routine structure:
  122.  semBSmCreate       semCSmCreate
  123.  |     |            |      |
  124. (o) semSmBInit     (o) semSmCInit
  125.          |                 |
  126.                           /
  127.           ------   --------
  128.                  /
  129.              qFifoGInit
  130.                  |
  131.              smDllInit     
  132.          semGive           semFlush                 semTake
  133.             |                 |        Interrupt       | 
  134.         semSmGive         semSmFlush   /            semSmTake
  135.         /  |  |           /  | |      /              | |   
  136.        /   *  |   --------   * |     /               | *    
  137.       /       |  /             |    /                |       
  138.       | smObjEventSend  smObjEventProcess       smObjTcbInit/|
  139.       |     /                |       |            |      / |
  140.       |    *     -----  windReadyQPut |    *       (i)    /  |
  141.       |   -----------                 |                  /   |
  142.  windReadyQPut         -------------- |    windReadyQRemove  |
  143.                       |               |                      |
  144.                  qFifoGRemove          |                  qFifoGPut
  145.                       |               |                      |
  146.                   smDllRemove *    smDllConcat             smDllPut
  147.         *                      *               (o)           (i)
  148. |                      |                |             |
  149.    SM_OBJ_LOCK_TAKE    SM_OBJ_LOCK_GIVE   smMemPartAlloc smFixBlkPartAlloc
  150. INCLUDE FILES: semSmLib.h
  151. SEE ALSO: semLib, semBLib, semCLib, smObjLib, semShow, usrSmObjInit(),
  152. tb VxWorks Programmer's Guide: Shared Memory Objects, 
  153. tb VxWorks Programmer's Guide: Basic OS
  154. */
  155. /* LINTLIBRARY */
  156. #include "vxWorks.h"
  157. #include "errnoLib.h"
  158. #include "objLib.h"
  159. #include "classLib.h"
  160. #include "qFifoGLib.h"
  161. #include "semLib.h"
  162. #include "stdlib.h"
  163. #include "stdio.h"
  164. #include "string.h"
  165. #include "taskLib.h"
  166. #include "cacheLib.h"
  167. #include "intLib.h"
  168. #include "smObjLib.h"
  169. #include "netinet/in.h"
  170. #include "private/semSmLibP.h"
  171. #include "private/windLibP.h"
  172. #include "private/smObjLibP.h"
  173. #include "private/smMemLibP.h"
  174. #include "private/sigLibP.h"
  175. #include "private/eventP.h"
  176. /* locals */
  177. LOCAL BOOL  semSmLibInstalled; /* protect from muliple inits */
  178. /*****************************************************************************
  179. *
  180. * semSmLibInit - initialize the shared semaphore management package
  181. *
  182. * This routine initializes the shared memory semaphore library by installing
  183. * the addresses of its give, take, and flush routines for both binary and
  184. * counting semaphores in the kernel's semaphore function dispatch table.
  185. *
  186. * SEE ALSO: smObjLibInit().
  187. *
  188. * RETURNS: N/A
  189. *
  190. * NOMANUAL
  191. */
  192. void semSmLibInit (void)
  193.     {
  194.     if ((!semSmLibInstalled) & (semLibInit () == OK))
  195. {
  196.      /* fill the semaphore function tables */
  197.      semGiveTbl  [SEM_TYPE_SM_BINARY] = (FUNCPTR) semSmGive;
  198.      semTakeTbl  [SEM_TYPE_SM_BINARY] = (FUNCPTR) semSmTake;
  199.      semFlushTbl [SEM_TYPE_SM_BINARY] = (FUNCPTR) semSmFlush;
  200.      semGiveTbl  [SEM_TYPE_SM_COUNTING] = (FUNCPTR) semSmGive;
  201.      semTakeTbl  [SEM_TYPE_SM_COUNTING] = (FUNCPTR) semSmTake;
  202.      semFlushTbl [SEM_TYPE_SM_COUNTING] = (FUNCPTR) semSmFlush;
  203. semSmLibInstalled = TRUE;
  204. }
  205.     }
  206. /*****************************************************************************
  207. *
  208. * semBSmCreate - create and initialize a shared memory binary semaphore (VxMP Option)
  209. *
  210. * This routine allocates and initializes a shared memory binary semaphore.
  211. * The semaphore is initialized to an <initialState> of either
  212. * SEM_FULL (available) or SEM_EMPTY (not available).  The shared semaphore
  213. * structure is allocated from the shared semaphore dedicated memory
  214. * partition.
  215. *
  216. * The semaphore ID returned by this routine can be used directly by the
  217. * generic semaphore-handling routines in semLib -- semGive(), semTake(), and
  218. * semFlush() -- and the show routines, such as show() and semShow().
  219. *
  220. * The queuing style for blocked tasks is set by <options>; the only
  221. * supported queuing style for shared memory semaphores is first-in-first-out,
  222. * selected by SEM_Q_FIFO .
  223. *
  224. * Before this routine can be called, the shared memory objects facility must
  225. * be initialized (see semSmLib).
  226. *
  227. * The maximum number of shared memory semaphores (binary plus counting) that
  228. * can be created is SM_OBJ_MAX_SEM , a configurable parameter.
  229. *
  230. * AVAILABILITY
  231. * This routine is distributed as a component of the unbundled shared memory
  232. * support option, VxMP.
  233. * RETURNS: The semaphore ID, or NULL if memory cannot be allocated 
  234. * from the shared semaphore dedicated memory partition.
  235. * ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_semLib_INVALID_QUEUE_TYPE,
  236. * S_semLib_INVALID_STATE, S_smObjLib_LOCK_TIMEOUT
  237. *
  238. * SEE ALSO: semLib, semBLib, smObjLib, semShow,
  239. * tb VxWorks Programmer's Guide: Basic OS
  240. *
  241. * INTERNAL
  242. * The least significant bit of the semaphore id is set to 1 in order to
  243. * differentiate shared and local semaphores.
  244. */
  245. SEM_ID semBSmCreate
  246.     (
  247.     int options, /* semaphore options */
  248.     SEM_B_STATE initialState /* initial semaphore state */
  249.     )
  250.     {
  251.     SM_SEM_ID   smSemId;
  252.     int         temp;           /* temp storage */
  253.     /* 
  254.      * Allocate semaphore structure from shared semaphores
  255.      * dedicated shared memory partition. 
  256.      */
  257.   
  258.     smSemId = (SM_SEM_ID) smMemPartAlloc ((SM_PART_ID) smSemPartId,
  259.                                           sizeof (SM_SEMAPHORE));
  260.     if (smSemId == NULL)
  261.         {
  262. return (NULL);
  263.         }
  264.     /* clear shared semaphore structure */
  265.     bzero ((char *) smSemId, sizeof (SM_SEMAPHORE));
  266.     /* initialize allocated semaphore */
  267.     if (semSmBInit ((SM_SEMAPHORE *) (smSemId), options, initialState) != OK)
  268.      {
  269.      smMemPartFree ((SM_PART_ID) smSemPartId, (char *) smSemId);
  270.      return (NULL);
  271.      }
  272.     /* update shared memory objects statistics */
  273.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  274.     temp = pSmObjHdr->curNumSemB;               /* PCI bridge bug [SPR 68844]*/
  275.     pSmObjHdr->curNumSemB = htonl (ntohl (pSmObjHdr->curNumSemB) + 1);
  276.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  277.     temp = pSmObjHdr->curNumSemB;               /* BRIDGE FLUSH  [SPR 68334] */
  278.     return ((SEM_ID) (SM_OBJ_ADRS_TO_ID (smSemId)));
  279.     }
  280. /*****************************************************************************
  281. *
  282. * semSmBInit - initialize a declared shared binary semaphore
  283. *
  284. * The initialization of a static shared binary semaphore, or a shared binary
  285. * semaphore embedded in some larger shared object need not deal with
  286. * allocation.  This routine may be called to initialize such a semaphore.  The
  287. * semaphore is initialized to the specified initial state of either SEM_FULL
  288. * or SEM_EMPTY .
  289. *
  290. * Binary semaphore options include the queuing style for blocked tasks.
  291. * For now, the only available shared semaphore queueing style is
  292. * first-in-first-out, type SEM_Q_FIFO defined as 0 in semLib.h.
  293. *
  294. * The semaphore address parameter is the local address of a shared semaphore
  295. * structure. 
  296. *
  297. * RETURNS: OK, or ERROR if queue type or initial state is invalid.
  298. * SEE ALSO: semBSmCreate
  299. *
  300. * ERRNO: S_semLib_INVALID_QUEUE_TYPE, S_semLib_INVALID_STATE   
  301. *
  302. * NOMANUAL
  303. */
  304. STATUS semSmBInit
  305.     (
  306.     SM_SEMAPHORE * pSem,                /* pointer to semaphore to initialize */
  307.     int            options,             /* semaphore options */
  308.     SEM_B_STATE    initialState         /* initial semaphore state */
  309.     )
  310.     {
  311.     Q_FIFO_G_HEAD           pseudoPendQ; /* pseudo pendQ to init sem pend Q */
  312.     SM_SEMAPHORE volatile * pSemv = (SM_SEMAPHORE volatile *) pSem;
  313.     int                     temp;        /* temp storage */
  314.     if (!semSmLibInstalled)
  315.         {
  316. semSmLibInit (); /* initialize package */
  317.         }
  318.     if (options != SEM_Q_FIFO) /* only FIFO queuing for now */
  319. {
  320. errno = S_semLib_INVALID_QUEUE_TYPE;
  321. return (ERROR);
  322. }
  323.     pSemv->objType = htonl (SEM_TYPE_SM_BINARY); /* semaphore type is binary */
  324.     pSemv->lock    = 0; /* lock available */
  325.     /* initialize pseudo multi way queue */
  326.     pseudoPendQ.pLock   = NULL; /* we already have the lock */
  327.     pseudoPendQ.pFifoQ  = &pSem->smPendQ; /* address of actual queue */
  328.     pseudoPendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */
  329.     qFifoGInit (&pseudoPendQ);          /* initialize sem pend Q */
  330.     /* fill state flag according to initial state */
  331.     switch (initialState)
  332.         {
  333.         case SEM_EMPTY:
  334.         case SEM_FULL:
  335.             pSemv->state.flag = htonl (initialState);   
  336.             break;
  337.         default:
  338.             errno = S_semLib_INVALID_STATE;
  339.             return (ERROR);
  340.         }
  341.     /* verify field must contain the global address of semaphore */
  342.     pSemv->verify = (UINT32) htonl (LOC_TO_GLOB_ADRS (pSem));
  343.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  344.     temp = pSemv->lock;                         /* BRIDGE FLUSH  [SPR 68334] */
  345.     return (OK);
  346.     }
  347. /*****************************************************************************
  348. *
  349. * semCSmCreate - create and initialize a shared memory counting semaphore (VxMP Option)
  350. *
  351. * This routine allocates and initializes a shared memory counting
  352. * semaphore.  The initial count value of the semaphore is specified
  353. * by <initialCount>.
  354. *
  355. * The semaphore ID returned by this routine can be used directly by the
  356. * generic semaphore-handling routines in semLib -- semGive(), semTake() and
  357. * semFlush() -- and the show routines, such as show() and semShow().
  358. *
  359. * The queuing style for blocked tasks is set by <options>; the only
  360. * supported queuing style for shared memory semaphores is first-in-first-out,
  361. * selected by SEM_Q_FIFO .
  362. *
  363. * Before this routine can be called, the shared memory objects facility must
  364. * be initialized (see semSmLib).
  365. *
  366. * The maximum number of shared memory semaphores (binary plus counting) that
  367. * can be created is SM_OBJ_MAX_SEM , a configurable paramter.
  368. *
  369. * AVAILABILITY
  370. * This routine is distributed as a component of the unbundled shared memory
  371. * support option, VxMP.
  372. * RETURNS: The semaphore ID, or NULL if memory cannot be allocated
  373. * from the shared semaphore dedicated memory partition.
  374. *
  375. * ERRNO: S_memLib_NOT_ENOUGH_MEMORY, S_semLib_INVALID_QUEUE_TYPE,
  376. * S_smObjLib_LOCK_TIMEOUT
  377. *
  378. * SEE ALSO: semLib, semCLib, smObjLib, semShow,
  379. * tb VxWorks Programmer's Guide: Basic OS
  380. *
  381. * INTERNAL
  382. * The least significant bit of the semaphore ID is set to 1 in order to
  383. * differentiate shared and local semaphores.
  384. */
  385. SEM_ID semCSmCreate
  386.     (
  387.     int options, /* semaphore options */
  388.     int initialCount /* initial semaphore count */
  389.     )
  390.     {
  391.     SM_SEM_ID smSemId;
  392.     int       temp;     /* temp storage */
  393.     /* allocate semaphore structure from shared semaphore dedicated pool */
  394.     smSemId = (SM_SEM_ID) smMemPartAlloc ((SM_PART_ID) smSemPartId,
  395.                                           sizeof (SM_SEMAPHORE));
  396.     if (smSemId == NULL)
  397.         {
  398. return (NULL);
  399.         }
  400.     bzero ((char *) smSemId, sizeof(SM_SEMAPHORE));
  401.     /* initialize allocated semaphore */
  402.     if (semSmCInit ((SM_SEMAPHORE *) (smSemId), options, initialCount) != OK)
  403.         {
  404.         smMemPartFree ((SM_PART_ID) smSemPartId, (char *) smSemId);
  405.         return (NULL);
  406.         }
  407.     /* update shared memory objects statistics */
  408.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  409.     temp = pSmObjHdr->curNumSemC;               /* PCI bridge bug [SPR 68844]*/
  410.     pSmObjHdr->curNumSemC = htonl (ntohl (pSmObjHdr->curNumSemC) + 1);
  411.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  412.     temp = pSmObjHdr->curNumSemC;               /* BRIDGE FLUSH  [SPR 68334] */
  413.     return ((SEM_ID) (SM_OBJ_ADRS_TO_ID (smSemId)));
  414.     }
  415. /*****************************************************************************
  416. *
  417. * semSmCInit - initialize a declared shared counting semaphore
  418. *
  419. * The initialization of a static counting semaphore, or a shared 
  420. * counting semaphore embedded in some larger object need not deal 
  421. * with allocation.
  422. * This routine may be called to initialize such a semaphore.  The semaphore
  423. * <pSem> is initialized to the specified <initialCount>.
  424. *
  425. * Counting semaphore <options> include the queuing style for blocked tasks.
  426. * The only available pending queue type is first-in-first-out, type
  427. * SEM_Q_FIFO defined as 0 in semLib.h.
  428. *
  429. * The semaphore address parameter <pSem> is the local address of a
  430. * shared semaphore data structure.
  431. *
  432. * RETURNS: OK or ERROR if queue type invalid.
  433. *
  434. * ERRNO: S_semLib_INVALID_QUEUE_TYPE
  435. *
  436. * SEE ALSO: semCSmCreate()
  437. *
  438. * NOMANUAL
  439. */
  440. STATUS semSmCInit
  441.     (
  442.     SM_SEMAPHORE * pSem,                /* pointer to semaphore to initialize */
  443.     int            options,             /* semaphore options */
  444.     int            initialCount         /* initial semaphore count */
  445.     )
  446.     {
  447.     Q_FIFO_G_HEAD           pseudoPendQ; /* pseudo pendQ to init sem pend Q */
  448.     SM_SEMAPHORE volatile * pSemv = (SM_SEMAPHORE volatile *) pSem;
  449.     int                     temp;        /* temp storage */
  450.     if (!semSmLibInstalled)
  451.         {
  452.         semSmLibInit ();                /* initialize package */
  453.         }
  454.     if (options != SEM_Q_FIFO)          /* only FIFO queuing for now */
  455.         {
  456.         errno = S_semLib_INVALID_QUEUE_TYPE;
  457.         return (ERROR);
  458.         }
  459.     pSemv->objType = htonl(SEM_TYPE_SM_COUNTING);/* fill semaphore type */
  460.     pSemv->lock    = 0; /* lock available */
  461.     /* initialize pseudo multi way queue */
  462.     pseudoPendQ.pLock   = NULL; /* we already have the lock */
  463.     pseudoPendQ.pFifoQ  = &pSem->smPendQ; /* address of actual queue */
  464.     pseudoPendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */
  465.     qFifoGInit (&pseudoPendQ);          /* initialize sem pend Q */
  466.     pSemv->state.count = htonl (initialCount);  /* set initial count */
  467.     /* verify field must contain the global address of semaphore */
  468.     pSemv->verify = (UINT32) htonl (LOC_TO_GLOB_ADRS (pSem));
  469.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  470.     temp = pSemv->lock;                         /* BRIDGE FLUSH  [SPR 68334] */
  471.     return (OK);
  472.     }
  473. /*****************************************************************************
  474. *
  475. * semSmGive - give shared memory binary or counting semaphore
  476. *
  477. * Gives the semaphore.  If a higher priority task has already taken
  478. * the semaphore (so that it is now pended waiting for it), that task
  479. * will now become ready to run.  If that task is local to this CPU and is of
  480. * higher priority than the task that does the semGive, it will preempt this
  481. * task.  If the first pended task is located on a remote processor, the
  482. * availability of the semaphore is made known to the remote processor via
  483. * an internal notification mecanism.
  484. * For a shared binary semaphore, if the semaphore is already full (it has
  485. * been given but not taken), this call is essentially a no-op.
  486. *
  487. * For a shared counting semaphore, if the semaphore count is already
  488. * greater than 0 (semaphore was given but not taken), this call is
  489. * essentially a no-op.
  490. *
  491. * The <smSemId> passed to this routine must be the local semaphore address.
  492. *
  493. * This routine is usually called by semGive() which first converts the
  494. * semaphore ID to the shared semaphore local address.
  495. *
  496. * WARNING
  497. * This routine may not be used from interrupt level.
  498. *
  499. * RETURNS: OK or ERROR.
  500. *
  501. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_ID_ERROR,
  502. *        S_smObjLib_LOCK_TIMEOUT
  503. *
  504. * NOMANUAL
  505. */
  506. STATUS semSmGive
  507.     (
  508.     SM_SEM_ID smSemId           /* global semaphore ID to give */
  509.     )
  510.     {
  511.     Q_FIFO_G_HEAD pendQ;        /* temporary pendQ to unpend task */
  512.     int           level; /* processor specific inLock return value */
  513.     SM_DL_LIST    eventList; /* list of events used to notify give */
  514.     SM_OBJ_TCB volatile *  firstSmTcb;   /* first pending shared memory tcb */
  515.     SM_SEM_ID volatile     smSemIdv = (SM_SEM_ID volatile) smSemId;
  516.     int                    temp;         /* temp storage */
  517.     
  518.     if (INT_RESTRICT () != OK) /* not ISR callable */
  519.         {
  520. return (ERROR);
  521.         }
  522.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  523.     temp = smSemIdv->verify;                    /* PCI bridge bug [SPR 68844]*/
  524.     if (SM_OBJ_VERIFY (smSemIdv) != OK) /* check semaphore id */
  525. {
  526. return (ERROR);
  527. }
  528.     /* ENTER LOCKED SECTION */
  529.     if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK) 
  530. {
  531. smObjTimeoutLogMsg ("semGive", (char *) &smSemId->lock);
  532. return (ERROR);                         /* can't take lock */
  533. }
  534.     /* get first pending shared TCB */
  535.     firstSmTcb = (SM_OBJ_TCB volatile *) SM_DL_FIRST (&smSemId->smPendQ);
  536.     /* pendQ is empty */
  537.     if (firstSmTcb == (SM_OBJ_TCB volatile *) LOC_NULL)
  538. {
  539.         /* binary semaphore: sem available */
  540. if (ntohl (smSemIdv->objType) == SEM_TYPE_SM_BINARY) 
  541.     {
  542.     smSemIdv->state.flag = htonl (SEM_FULL);
  543.     }
  544.         /* counting semaphore: increment sem count */
  545.         else
  546.     {
  547.     smSemIdv->state.count = htonl (ntohl (smSemIdv->state.count) + 1);
  548.     }
  549.         /* EXIT LOCKED SECTION */
  550. SM_OBJ_LOCK_GIVE (&smSemId->lock, level);
  551. return (OK);
  552. }
  553.     /* pendQ is not empty, initialize pseudo multi way queue */
  554.     pendQ.pLock   = NULL; /* we already have the lock */
  555.     pendQ.pFifoQ  = &smSemId->smPendQ;   /* address of actual queue */
  556.     pendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */
  557.     /* 
  558.      * Do now the necessary manipulations in shared memory
  559.      * in order to be able to release lock access ASAP
  560.      * thus reducing interrupt latency.
  561.      */
  562.     /* ENTER KERNEL */
  563.     kernelState = TRUE;
  564.     /* remove from pending list */
  565.     Q_REMOVE (&pendQ, (SM_DL_NODE *) firstSmTcb);
  566.     /* EXIT LOCKED SECTION */
  567.     SM_OBJ_LOCK_GIVE (&smSemId->lock, level);
  568.     /* pending task is local */
  569.     if (ntohl (firstSmTcb->ownerCpu) == smObjProcNum)
  570. {
  571. /* 
  572.  * The shared TCB has been removed from the shared semaphore
  573.  * pendQ by qFifoGRemove(), during that call removedByGive is
  574.  * set to TRUE to avoid non-null notification time race.
  575.  * Then, if the task that has taken the semaphore is remote,
  576.  * an event notification is done and removedByGive is reset
  577.  * by smObjEventProcess() on the remote processor.
  578.  * If the pended task is local removedByGive must be reset
  579.  * here to avoid the shared TCB being screwed up.
  580.  */ 
  581. firstSmTcb->removedByGive = htonl (FALSE);
  582. /* windview - level 2 event logging */
  583. EVT_TASK_1 (EVENT_OBJ_SEMGIVE, smSemId);
  584.         CACHE_PIPE_FLUSH ();                    /* CACHE FLUSH   [SPR 68334] */
  585.         temp = (int) firstSmTcb->localTcb;      /* PCI bridge bug [SPR 68844]*/
  586. windReadyQPut ((WIND_TCB *) ntohl ((int) firstSmTcb->localTcb));
  587. }
  588.     /* pending task is remote */
  589.     else
  590. {
  591.   /* 
  592.  * Add the shared TCB that was pended on the semaphore
  593.  * pend queue to the list of events to send to the
  594.  * CPU where the pended task is located.
  595.  */
  596. eventList.head = (SM_DL_NODE *) htonl (LOC_TO_GLOB_ADRS (firstSmTcb));
  597. eventList.tail = eventList.head;
  598. /* 
  599.  * Unlink the shared TCB from other shared TCBs of the semaphore
  600.  * pend queue.
  601.  */
  602. firstSmTcb->qNode.next = NULL;
  603.   /* notify remote CPU */
  604.         CACHE_PIPE_FLUSH ();                    /* CACHE FLUSH   [SPR 68334] */
  605.         temp = firstSmTcb->ownerCpu;            /* PCI bridge bug [SPR 68844]*/
  606. if (smObjEventSend (&eventList, ntohl (firstSmTcb->ownerCpu)) != OK) 
  607.     {
  608.          windExit (); /* EXIT KERNEL */
  609.     return (ERROR);
  610.     }
  611. }
  612.     windExit (); /* EXIT KERNEL */
  613.     return (OK);
  614.     }
  615. /*****************************************************************************
  616. *
  617. * semSmTake - take shared memory binary or counting semaphore
  618. *
  619. * Takes a shared semaphore.  If the semaphore is empty, i.e., it has not been
  620. * given since the last semTake() or semInit(), this task will become pended
  621. * until the semaphore becomes available by some other local or remote task
  622. * doing a semGive() of it or if the optional <timeout> value is not NO_WAIT,
  623. * in which case the task will pend for no more than <timeout> system clock
  624. * ticks.  If <timeout> is WAIT_FOREVER , the task may never return if a remote
  625. * task has the semaphore and crashes.
  626. *
  627. * For binary semaphores, if the semaphore is already available, this
  628. * call will empty the semaphore, so that no other task can take it
  629. * until this task gives it back, and this task will continue running.
  630. *
  631. * For counting semaphores, if the semaphore count is already greater
  632. * than 0, this call will decrement the semaphore count, and this task
  633. * will continue running.
  634. *
  635. * The <smSemId> passed to this routine must be the local semaphore address.
  636. * This routine is usually called by semTake() which first converts the
  637. * semaphore ID to the shared semaphore local address.
  638. *
  639. * WARNING
  640. * This routine may not be used from interrupt level.
  641. *
  642. * RETURNS: OK or ERROR.
  643. *
  644. * ERRNO: S_objLib_OBJ_UNAVAILABLE, S_intLib_NOT_ISR_CALLABLE,
  645. *        S_objLib_OBJ_ID_ERROR, S_objLib_OBJ_TIMEOUT, S_smObjLib_LOCK_TIMEOUT,
  646. *        S_smMemLib_NOT_ENOUGH_MEMORY
  647. *
  648. * NOMANUAL
  649. *
  650. * INTERNAL
  651. * When semSmTake is called for the first time or after a timeout or a
  652. * RESTART signal occuring while this task was blocked on a shared
  653. * semaphore, a shared TCB is created in shared memory.
  654. * This is done by allocating a shared TCB structure
  655. * from a shared partition dedicated to shared TCBs.  A pointer to this
  656. * shared TCB is then initialized in the local Task Control Block.
  657. */
  658. STATUS semSmTake 
  659.     (
  660.     SM_SEM_ID smSemId,     /* global semaphore ID to take */
  661.     int       timeout      /* timeout in ticks */
  662.     )
  663.     {
  664.     Q_FIFO_G_HEAD      pendQ; /* global FIFO to pend on */
  665.     int                level;   /* processor specific inLock return value */
  666.     int                status;  /* returned status */
  667.     WIND_TCB *         pTcb; /* current task tcb pointer */
  668.     SM_SEM_ID volatile smSemIdv = (SM_SEM_ID volatile) smSemId;
  669.     int                temp;    /* temp storage */
  670.     if (INT_RESTRICT () != OK) /* not ISR callable */
  671.         {
  672. return (ERROR);
  673.         }
  674. again:
  675.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  676.     temp = smSemIdv->verify;                    /* PCI bridge bug [SPR 68844]*/
  677.     if (SM_OBJ_VERIFY (smSemIdv) != OK) /* check semaphore */
  678. {
  679. return (ERROR);
  680. }
  681.     /* 
  682.      * If it's the first call to semSmBTake, or if a timeout or a
  683.      * RESTART signal has occured while this task was blocked on a shared
  684.      * semaphore, the pSmObjTcb field of the TCB is NULL, we allocate
  685.      * and initialize a shared TCB.
  686.      */
  687.     
  688.     pTcb = (WIND_TCB *) taskIdCurrent;
  689.     if (pTcb->pSmObjTcb == NULL)
  690. {
  691. if (smObjTcbInit () != OK)
  692.     {
  693.     return  (ERROR);
  694.     }
  695. }
  696.     /* ENTER LOCKED SECTION */
  697.     if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK)
  698. {
  699. smObjTimeoutLogMsg ("semTake", (char *) &smSemId->lock);
  700. return (ERROR);                         /* can't take lock */
  701. }
  702.     
  703.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  704.     temp = smSemIdv->objType;                   /* PCI bridge bug [SPR 68844]*/
  705.     if (ntohl (smSemIdv->objType) == SEM_TYPE_SM_BINARY) /* binary semaphore */
  706. {
  707.      if (ntohl (smSemIdv->state.flag) == SEM_FULL)
  708.     {
  709.     smSemIdv->state.flag = htonl (SEM_EMPTY); /* set sem unavailable */
  710.     SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */
  711.     return (OK);
  712.     }
  713. }
  714.     else  /* counting samaphore */
  715. {
  716.      if (ntohl (smSemId->state.count) > 0)
  717.             {
  718.     /* decrement semaphore count */
  719.             smSemId->state.count = htonl (ntohl (smSemId->state.count) - 1);
  720.             SM_OBJ_LOCK_GIVE(&smSemId->lock, level);  /* EXIT LOCKED SECTION */
  721.             return (OK);
  722.             }
  723.     } 
  724.     kernelState = TRUE;   /* ENTER KERNEL */
  725.     if (timeout == NO_WAIT)                           /* NO_WAIT = no block */
  726.         {
  727.         SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */
  728.         errno = S_objLib_OBJ_UNAVAILABLE;             /* resource gone */
  729.         windExit ();                                  /* KERNEL EXIT */
  730.         return (ERROR);
  731.         }
  732.     /* 
  733.      * We get here if the semaphore is not available and we must wait.
  734.      * The calling task must be added to the shared semaphore
  735.      * queue using standard wind kernel functions.  For that we
  736.      * initialize a pseudo multi-way queue header that points to
  737.      * the shared semaphore pend queue and which will be used
  738.      * by the multi-way queue manipulation macros.
  739.      */
  740.     /* 
  741.      * We optimize interrupt latency by doing only the Q_PUT on the
  742.      * shared semaphore pend Q while interrupts are locked.
  743.      * The remaining part of blocking the task is done in
  744.      * windReadyQRemove() with interrupts unlocked.
  745.      */
  746.     pendQ.pLock   = NULL; /* we already have the lock */
  747.     pendQ.pFifoQ  = &smSemId->smPendQ;   /* address of actual queue */
  748.     pendQ.pQClass = qFifoGClassId; /* global fifo multi way Q */
  749.     Q_PUT (&pendQ, taskIdCurrent, taskIdCurrent->priority);
  750.     SM_OBJ_LOCK_GIVE (&smSemId->lock, level);  /* EXIT LOCKED SECTION */
  751.     pendQ.pLock  = &smSemId->lock; /* now we don't have lock */
  752.     /* windview - level 2 event logging */
  753.     EVT_TASK_1 (EVENT_OBJ_SEMTAKE, smSemId);
  754.     windReadyQRemove ((Q_HEAD *) &pendQ, timeout); /* block task */
  755.     if ((status = windExit ()) == RESTART)      /* KERNEL EXIT */
  756.         {
  757.         timeout = SIG_TIMEOUT_RECALC (timeout);
  758.         goto again;
  759.         }
  760.     return (status);
  761.     }
  762. /*****************************************************************************
  763. *
  764. * semSmFlush - flush shared binary or counting semaphore
  765. *
  766. * Flush the shared semaphore.  If one or more tasks have already taken
  767. * the semaphore (so that it is now pended waiting for it), those tasks
  768. * will now become ready to run.  If a local higher priority task was
  769. * pending on the semaphore it will preempt the task that does the semFlush().
  770. * If the semaphore pend queue is empty, this call is essentially a no-op.
  771. * The smSemId passed to this routine must be the local semaphore address.
  772. *
  773. * This routine is usually called by semFlush() which first converts the
  774. * semaphore ID to the shared semaphore local address.
  775. *
  776. * WARNING
  777. * This routine may not be used from interrupt level.
  778. *
  779. * RETURNS: OK or ERROR.
  780. *
  781. * ERRNO: S_intLib_NOT_ISR_CALLABLE, S_objLib_OBJ_ID_ERROR,
  782. *        S_smObjLib_LOCK_TIMEOUT
  783. *
  784. * NOMANUAL
  785. */
  786. STATUS semSmFlush
  787.     (
  788.     SM_SEM_ID smSemId             /* global semaphore ID to flush */
  789.     )
  790.     {
  791.     SM_OBJ_TCB volatile * firstSmTcb;   /* first pending shared memory TCB */
  792.     SM_OBJ_TCB volatile * pSmObjTcb;    /* useful shared TCB pointer */ 
  793.     SM_OBJ_TCB volatile * pSmObjTcbTmp; /* useful shared TCB pointer */   
  794.     int                   level;        /* CPU specific inLock return value */
  795.     int                   cpuNum;       /* loop counter for remote flush */
  796.     SM_DL_LIST            flushQ [SM_OBJ_MAX_CPU];  /* per CPU flush Q */
  797.     SM_SEM_ID volatile    smSemIdv = (SM_SEM_ID volatile) smSemId;
  798.     int                   temp;         /* temp storage */
  799.     
  800.     if (INT_RESTRICT () != OK) /* not ISR callable */
  801.         {
  802. return (ERROR);
  803.         }
  804.     CACHE_PIPE_FLUSH ();                        /* CACHE FLUSH   [SPR 68334] */
  805.     temp = smSemIdv->verify;                    /* PCI bridge bug [SPR 68844]*/
  806.     if (SM_OBJ_VERIFY (smSemIdv) != OK) /* check semaphore */
  807. {
  808. return (ERROR);
  809. }
  810.     /* ENTER LOCKED SECTION */
  811.     if (SM_OBJ_LOCK_TAKE (&smSemId->lock, &level) != OK)
  812. {
  813. smObjTimeoutLogMsg ("semFlush", (char *) &smSemId->lock);
  814. return (ERROR);                         /* can't take lock */
  815. }
  816.     /* 
  817.      * In order to reduce interrupt latency we get the first
  818.      * shared TCB from the shared semaphore pend queue, then
  819.      * we empty the pend queue by clearing the pend queue head.
  820.      * All the previously pended shared TCBs are still linked
  821.      * to the first pending TCB and we can give back lock access
  822.      * to the shared semaphore.
  823.      */
  824.     firstSmTcb = (SM_OBJ_TCB volatile *) SM_DL_FIRST (&smSemId->smPendQ);
  825.     if (firstSmTcb == (SM_OBJ_TCB volatile *) LOC_NULL)  /* pendQ is empty */
  826. {
  827. SM_OBJ_LOCK_GIVE (&smSemId->lock, level);/* EXIT LOCKED SECTION */
  828. return (OK);
  829. }
  830.     smSemIdv->smPendQ.head = NULL;     /* empty semaphore pend queue */
  831.     smSemIdv->smPendQ.tail = NULL;
  832.     SM_OBJ_LOCK_GIVE (&smSemId->lock, level); /* EXIT LOCKED SECTION */
  833.     /* create a list of pending task per cpu */
  834.     bzero ((char *) flushQ, sizeof (flushQ));  /* clear flush Q table */
  835.     pSmObjTcb = firstSmTcb;
  836.     do
  837. {
  838. /* get next shared TCB behind current shared TCB */
  839.         pSmObjTcbTmp = (SM_OBJ_TCB volatile *) SM_DL_NEXT (pSmObjTcb);
  840. /* add the shared TCB to its CPU flush Queue */
  841. smDllAdd (&flushQ [ntohl (pSmObjTcb->ownerCpu)], 
  842.   (SM_DL_NODE *) pSmObjTcb);
  843.         /* make current shared TCB be next shared TCB */
  844. pSmObjTcb = pSmObjTcbTmp;
  845. } while (pSmObjTcbTmp != LOC_NULL);
  846.     /* notify remote flush */
  847.     for (cpuNum = 0; cpuNum < SM_OBJ_MAX_CPU; cpuNum ++)
  848. {
  849. if ((SM_DL_FIRST (&flushQ [cpuNum]) != (int) LOC_NULL) && 
  850.     (cpuNum != smObjProcNum))
  851.     {
  852.     /* 
  853.      * There is one or more task running on cpuNum to unblock and
  854.      * cpuNum is not the local CPU so notify cpuNum.
  855.      */
  856.     if (smObjEventSend (&flushQ [cpuNum], cpuNum) != OK)
  857.         {
  858.                 return (ERROR);
  859.         }
  860.     }
  861. }
  862.     /* perform local flush if needed */
  863.     if (SM_DL_FIRST (&flushQ [smObjProcNum]) != (int) LOC_NULL)
  864. {
  865. kernelState = TRUE; /* ENTER KERNEL */
  866. /*
  867.  * Since all tasks have been removed from the shared
  868.  * semaphore pend queue, unblocking them now consists
  869.  * of putting all the tasks for which the shared TCBs
  870.  * are in the flush Queue in the ready Queue.
  871.  * This is exacly what smObjEventProcess() does on the remote
  872.  * side so we just call it.
  873.  */
  874. smObjEventProcess (&flushQ [smObjProcNum]);
  875. windExit (); /* EXIT KERNEL */
  876. }
  877.     return (OK);
  878.     }