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

VxWorks

开发平台:

C/C++

  1. /* pipeDrv.c - pipe I/O driver */
  2. /* Copyright 1995-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02t,17oct01,dcb  Added include for memPartLib.h to pick up the KHEAP_ macros.
  8. 02s,05oct01,dcb  Fix SPR 9434.  Add pipeDevDelete() call.  Code merged back
  9.                  from the AE tree (created for AE under SPR 26204).
  10. 02r,14mar99,jdi  doc: removed refs to config.h and/or configAll.h (SPR 25663).
  11. 02q,12jun96,dbt  fixed SPR 5834 in pipeOpen. 
  12.  Update Copyright.
  13. 02p,22jan93,jdi  documentation cleanup for 5.1.
  14. 02o,21oct92,jdi  removed mangen SECTION designation.
  15. 02n,21sep92,jmm  fixed problem with select checking for writeable fd's (spr1095)
  16. 02m,23aug92,jcf  fixed race with select and pipeWrite.
  17. 02l,18jul92,smb  Changed errno.h to errnoLib.h.
  18. 02k,04jul92,jcf  scalable/ANSI/cleanup effort.
  19. 02j,26may92,rrr  the tree shuffle
  20. 02i,16dec91,gae  added includes for ANSI.
  21. 02h,25nov91,rrr  cleanup of some ansi warnings.
  22. 02g,04oct91,rrr  passed through the ansification filter
  23.                   -changed functions to ansi style
  24.   -changed VOID to void
  25.   -changed copyright notice
  26. 02f,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  27.  doc review by dnw.
  28. 02e,27feb91,jaa  documentation cleanup.
  29. 02d,05oct90,dnw  changed to new message queue interface.
  30.  finished documentation.
  31. 02c,04oct90,shl  made pipe{Open,Read,Write,Ioctl} be LOCAL.
  32. 02b,17jul90,dnw  lint
  33. 02a,10jun90,dnw  rewritten to use msgQ
  34. 01h,15mar90,rdc  added select support.
  35. 01g,08aug89,dab  fixed bug in pipeDevCreate() that set the wrong value for
  36.                    the size of a pipe.
  37. 01f,21nov88,jcf  lint.
  38. 01e,01oct88,gae  restored FIONMSGS and FIOFLUSH lost in new version 01a.
  39. 01d,26aug88,gae  documentation.
  40. 01c,30may88,dnw  changed to v4 names.
  41. 01b,04may88,jcf  changed semaphores for new semLib.
  42. ... old versions deleted - see RCS
  43. */
  44. /*
  45. DESCRIPTION
  46. The pipe driver provides a mechanism that lets tasks communicate with each 
  47. other through the standard I/O interface.  Pipes can be read and written with
  48. normal read() and write() calls.  The pipe driver is initialized with
  49. pipeDrv().  Pipe devices are created with pipeDevCreate().
  50. The pipe driver uses the VxWorks message queue facility to do the actual
  51. buffering and delivering of messages.  The pipe driver simply provides
  52. access to the message queue facility through the I/O system.  The main
  53. differences between using pipes and using message queues directly are:
  54. .iP "" 4
  55. pipes are named (with I/O device names).
  56. .iP
  57. pipes use the standard I/O functions -- open(), close(), read(),
  58. write() -- while message queues use the functions msgQSend() and msgQReceive().
  59. .iP
  60. pipes respond to standard ioctl() functions.
  61. .iP
  62. pipes can be used in a select() call.
  63. .iP
  64. message queues have more flexible options for timeouts and message
  65. priorities.
  66. .iP
  67. pipes are less efficient than message queues because of the additional
  68. overhead of the I/O system.
  69. .LP
  70. INSTALLING THE DRIVER
  71. Before using the driver, it must be initialized and installed by calling
  72. pipeDrv().  This routine must be called before any pipes are created.
  73. It is called automatically by the root task, usrRoot(), in usrConfig.c when
  74. the configuration macro INCLUDE_PIPES is defined.
  75. CREATING PIPES
  76. Before a pipe can be used, it must be created with pipeDevCreate().
  77. For example, to create a device pipe "/pipe/demo" with up to 10 messages
  78. of size 100 bytes, the proper call is:
  79. .CS
  80.     pipeDevCreate ("/pipe/demo", 10, 100);
  81. .CE
  82. USING PIPES
  83. Once a pipe has been created it can be opened, closed, read, and written
  84. just like any other I/O device.  Often the data that is read and written
  85. to a pipe is a structure of some type.  Thus, the following example writes
  86. to a pipe and reads back the same data:
  87. .ne 5
  88. .CS
  89.     {
  90.     int fd;
  91.     struct msg outMsg;
  92.     struct msg inMsg;
  93.     int len;
  94.     fd = open ("/pipe/demo", O_RDWR);
  95.     write (fd, &outMsg, sizeof (struct msg));
  96.     len = read (fd, &inMsg, sizeof (struct msg));
  97.     close (fd);
  98.     }
  99. .CE
  100. The data written to a pipe is kept as a single message and will be
  101. read all at once in a single read.  If read() is called with a buffer
  102. that is smaller than the message being read, the remainder of the message
  103. will be discarded.  Thus, pipe I/O is "message oriented" rather than
  104. "stream oriented."  In this respect, VxWorks pipes differ significantly 
  105. from UNIX pipes which are stream oriented and do not preserve message 
  106. boundaries.
  107. WRITING TO PIPES FROM INTERRUPT SERVICE ROUTINES
  108. Interrupt service routines (ISR) can write to pipes, providing one of several
  109. ways in which ISRs can communicate with tasks.  For example, an interrupt
  110. service routine may handle the time-critical interrupt response and then
  111. send a message on a pipe to a task that will continue with the less
  112. critical aspects.  However, the use of pipes to communicate from an ISR to
  113. a task is now discouraged in favor of the direct message queue facility,
  114. which offers lower overhead (see the manual entry for msgQLib for more
  115. information).
  116. SELECT CALLS
  117. An important feature of pipes is their ability to be used in a select()
  118. call.  The select() routine allows a task to wait for input from any of a
  119. selected set of I/O devices.  A task can use select() to wait for input
  120. from any combination of pipes, sockets, or serial devices.  See the manual
  121. entry for select().
  122. IOCTL FUNCTIONS
  123. Pipe devices respond to the following ioctl() functions.
  124. These functions are defined in the header file ioLib.h.
  125. .iP "FIOGETNAME" 18 3
  126. Gets the file name of fd and copies it to the buffer referenced by <nameBuf>:
  127. .CS
  128.     status = ioctl (fd, FIOGETNAME, &nameBuf);
  129. .CE
  130. .iP "FIONREAD"
  131. Copies to <nBytesUnread> the number of bytes remaining in the first message
  132. in the pipe:
  133. .CS
  134.     status = ioctl (fd, FIONREAD, &nBytesUnread);
  135. .CE
  136. .iP "FIONMSGS"
  137. Copies to <nMessages> the number of discrete messages remaining in the pipe:
  138. .CS
  139.     status = ioctl (fd, FIONMSGS, &nMessages);
  140. .CE
  141. .iP "FIOFLUSH"
  142. Discards all messages in the pipe and releases the memory block that contained
  143. them:
  144. .CS
  145.     status = ioctl (fd, FIOFLUSH, 0);
  146. .CE
  147. INCLUDE FILES: ioLib.h, pipeDrv.h
  148. SEE ALSO: select(), msgQLib,
  149. .pG "I/O System"
  150. */
  151. #include "vxWorks.h"
  152. #include "ioLib.h"
  153. #include "iosLib.h"
  154. #include "stdlib.h"
  155. #include "lstLib.h"
  156. #include "selectLib.h"
  157. #include "semLib.h"
  158. #include "intLib.h"
  159. #include "taskLib.h"
  160. #include "errnoLib.h"
  161. #include "string.h"
  162. #include "memPartLib.h"
  163. #include "private/msgQLibP.h"
  164. typedef struct /* PIPE_DEV */
  165.     {
  166.     DEV_HDR devHdr; /* pipe device header */
  167.     MSG_Q msgQ; /* underlying message queue */
  168.     SEL_WAKEUP_LIST selWakeupList; /* list of tasks pended in select */
  169.     UINT numOpens; /* number of pipe terminals open */
  170.     } PIPE_DEV;
  171. /* globals */
  172. int pipeMsgQOptions = MSG_Q_FIFO; /* options with which msg queues are
  173.  * created */
  174. /* locals */
  175. LOCAL int pipeDrvNum = ERROR; /* driver number of pipe driver */
  176. /* forward static functions */
  177. static int pipeOpen (PIPE_DEV *pPipeDev, char *name, int flags, int mode);
  178. static int pipeClose (PIPE_DEV *pPipeDev);
  179. static int pipeRead (PIPE_DEV *pPipeDev, char *buffer, unsigned int maxbytes);
  180. static int pipeWrite (PIPE_DEV *pPipeDev, char *buffer, int nbytes);
  181. static STATUS pipeIoctl (PIPE_DEV *pPipeDev, int request, int *argptr);
  182. /*******************************************************************************
  183. *
  184. * pipeDrv - initialize the pipe driver
  185. *
  186. * This routine initializes and installs the driver.  It must be called
  187. * before any pipes are created.  It is called automatically by the root
  188. * task, usrRoot(), in usrConfig.c when the configuration macro INCLUDE_PIPES
  189. * is defined.
  190. *
  191. * RETURNS: OK, or ERROR if the driver installation fails.
  192. */
  193. STATUS pipeDrv (void)
  194.     {
  195.     /* check if driver already installed */
  196.     if (pipeDrvNum == ERROR)
  197. {
  198. pipeDrvNum = iosDrvInstall ((FUNCPTR) NULL, (FUNCPTR) NULL, pipeOpen,
  199.     pipeClose, pipeRead, pipeWrite, pipeIoctl);
  200. }
  201.     return (pipeDrvNum == ERROR ? ERROR : OK);
  202.     }
  203. /*******************************************************************************
  204. *
  205. * pipeDevCreate - create a pipe device
  206. *
  207. * This routine creates a pipe device.  It cannot be called from an interrupt
  208. * service routine.
  209. * It allocates memory for the necessary structures and initializes the device.
  210. * The pipe device will have a maximum of <nMessages> messages of up to
  211. * <nBytes> each in the pipe at once.  When the pipe is full, a task attempting
  212. * to write to the pipe will be suspended until a message has been read.
  213. * Messages are lost if written to a full pipe at interrupt level.
  214. *
  215. * RETURNS: OK, or ERROR if the call fails.
  216. *
  217. * ERRNO
  218. * S_ioLib_NO_DRIVER - driver not initialized
  219. * S_intLib_NOT_ISR_CALLABLE - cannot be called from an ISR
  220. */
  221. STATUS pipeDevCreate
  222.     (
  223.     char *name,         /* name of pipe to be created      */
  224.     int nMessages,      /* max. number of messages in pipe */
  225.     int nBytes          /* size of each message            */
  226.     )
  227.     {
  228.     FAST PIPE_DEV *pPipeDev;
  229.     /* can't be called from ISR */
  230.     if (INT_RESTRICT () != OK)
  231.         {
  232.         return (ERROR);
  233.         }
  234.     if (pipeDrvNum == ERROR)
  235.         {
  236.         errnoSet (S_ioLib_NO_DRIVER);
  237.         return (ERROR);
  238.         }
  239.     pPipeDev = (PIPE_DEV *) KHEAP_ALLOC ((unsigned) sizeof (PIPE_DEV) +
  240.  (nMessages * MSG_NODE_SIZE (nBytes)));
  241.     if (pPipeDev == NULL)
  242. return (ERROR);
  243.     /* initialize open link counter, message queue, and select list */
  244.     pPipeDev->numOpens = 0;
  245.     if (msgQInit (&pPipeDev->msgQ, nMessages, nBytes, pipeMsgQOptions,
  246.   (void *) (((char *) pPipeDev) + sizeof (PIPE_DEV))) != OK)
  247. {
  248. KHEAP_FREE ((char *) pPipeDev);
  249. return (ERROR);
  250. }
  251.     selWakeupListInit (&pPipeDev->selWakeupList);
  252.     /* I/O device to system */
  253.     if (iosDevAdd (&pPipeDev->devHdr, name, pipeDrvNum) != OK)
  254. {
  255. msgQTerminate (&pPipeDev->msgQ);
  256. KHEAP_FREE ((char *)pPipeDev);
  257. return (ERROR);
  258. }
  259.     return (OK);
  260.     }
  261. /*******************************************************************************
  262. *
  263. * pipeDevDelete - delete a pipe device
  264. *
  265. * This routine deletes a pipe device of a given name.  The name must match
  266. * that passed to pipeDevCreate() else ERROR will be returned.  This routine
  267. * frees memory for the necessary structures and deletes the device.  It cannot
  268. * be called from an interrupt service routine.
  269. *
  270. * A pipe device cannot be deleted until its number of open requests has been
  271. * reduced to zero by an equal number of close requests and there are no tasks
  272. * pending in its select list.  If the optional force flag is asserted, the
  273. * above restrictions are ignored, resulting in forced deletion of any select
  274. * list and freeing of pipe resources.
  275. *
  276. * CAVEAT: Forced pipe deletion can have catastrophic results if used
  277. * indescriminately.  Use only as a last resort.
  278. *
  279. * RETURNS: OK, or ERROR if the call fails.
  280. *
  281. * ERRNO
  282. * S_ioLib_NO_DRIVER         - driver not initialized
  283. * S_intLib_NOT_ISR_CALLABLE - cannot be called from an ISR
  284. * EMFILE                    - pipe still has other openings
  285. * EBUSY                     - pipe is selected by at least one pending task
  286. */
  287. STATUS pipeDevDelete
  288.     (
  289.     char * name, /* name of pipe to be deleted */
  290.     BOOL   force /* if TRUE, force pipe deletion */
  291.     )
  292.     {
  293.     FAST PIPE_DEV *   pPipeDev;
  294.     char *            pTail = NULL;
  295.     SEL_WAKEUP_NODE * pNode = NULL;
  296.     /* can't be called from ISR */
  297.     if (INT_RESTRICT () != OK)
  298.         {
  299.         return (ERROR);
  300.         }
  301.     /* driver must be initialized */
  302.     if (pipeDrvNum == ERROR)
  303.         {
  304.         errno = S_ioLib_NO_DRIVER;
  305.         return (ERROR);
  306.         }
  307.     /* get pointer to pipe device descriptor */
  308.     if ((pPipeDev = (PIPE_DEV *) iosDevFind (name, &pTail)) == NULL)
  309.         {
  310. return (ERROR);
  311.         }
  312.     /* if not forced, check for other opens and non-empty select list */
  313.     if (!force)
  314.         {
  315.         if (pPipeDev->numOpens != 0)
  316.             {
  317.             errno = EMFILE;
  318.             return (ERROR);
  319.             }
  320.         if (selWakeupListLen (&pPipeDev->selWakeupList) != 0)
  321.             {
  322.             errno = EBUSY;
  323.             return (ERROR);
  324.             }
  325.         }
  326.     /* I/O device no longer in system */
  327.     iosDevDelete (&pPipeDev->devHdr);
  328.     /* force clearing of any select list */
  329.     if(force && (selWakeupListLen (&pPipeDev->selWakeupList) != 0))
  330.         {
  331.         pNode = (SEL_WAKEUP_NODE *)lstFirst ((LIST *)&pPipeDev->selWakeupList);
  332.         do
  333.             {
  334.             selNodeDelete (&pPipeDev->selWakeupList, pNode);
  335.             } while ((pNode = (SEL_WAKEUP_NODE *) lstNext ((NODE *)pNode))
  336.                            != NULL);
  337.         lstFree ((LIST *)&pPipeDev->selWakeupList);
  338.         selWakeupListTerm (&pPipeDev->selWakeupList);
  339.         }
  340.     /* terminate message queue */
  341.     msgQTerminate (&pPipeDev->msgQ);
  342.     /* free pipe memory */
  343.     KHEAP_FREE ((char *)pPipeDev);
  344.     return (OK);
  345.     }
  346. /* routines supplied to I/O system */
  347. /*******************************************************************************
  348. *
  349. * pipeOpen - open a pipe file
  350. *
  351. * This routine is called to open a pipe.  It returns a pointer to the
  352. * device.  This routine is normally reached only via the I/O system.
  353. *
  354. * RETURNS  pPipeDev or ERROR if pipe has not been created by pipeDevCreate().
  355. */
  356. LOCAL int pipeOpen
  357.     (
  358.     PIPE_DEV * pPipeDev, /* pipe descriptor */
  359.     char *     name,
  360.     int        flags,
  361.     int        mode
  362.     )
  363.     {
  364.     if ((name != NULL) && (strlen (name) > 0))
  365. {
  366. /* Only the first part of the name match with the driver's name */ 
  367. errnoSet (S_ioLib_NO_DEVICE_NAME_IN_PATH);
  368. return (ERROR);
  369. }
  370.     else
  371. {
  372. /* track number of openings to pipe */
  373. ++pPipeDev->numOpens;
  374.      return ((int) pPipeDev);
  375. }
  376.     }
  377. /*******************************************************************************
  378. *
  379. * pipeClose - close a pipe file
  380. *
  381. * This routine is called to close a pipe.  This routine is normally reached
  382. * only via the I/O system.
  383. *
  384. * RETURNS  OK or ERROR if NULL pipe device pointer.
  385. */
  386. LOCAL int pipeClose
  387.     (
  388.     PIPE_DEV * pPipeDev /* pipe descriptor */
  389.     )
  390.     {
  391.     if (pPipeDev != NULL)
  392. {
  393. /* decrement the open counter, but not past zero */ 
  394. if (pPipeDev->numOpens > 0)
  395.   --pPipeDev->numOpens;
  396. return (OK);
  397. }
  398.     else
  399. {
  400.      return (ERROR);
  401. }
  402.     }
  403. /*******************************************************************************
  404. *
  405. * pipeRead - read bytes from a pipe
  406. *
  407. * This routine reads up to maxbytes bytes of the next message in the pipe.
  408. * If the message is too long, the additional bytes are just discarded.
  409. *
  410. * RETURNS:
  411. *  number of bytes actually read;
  412. *  will be between 1 and maxbytes, or ERROR
  413. */
  414. LOCAL int pipeRead
  415.     (
  416.     FAST PIPE_DEV * pPipeDev, /* pointer to pipe descriptor */
  417.     char *          buffer, /* buffer to receive bytes */
  418.     unsigned int    maxbytes /* max number of bytes to copy into buffer */
  419.     )
  420.     {
  421.     int nbytes;
  422.     /* wait for something to be in pipe */
  423.     nbytes = msgQReceive (&pPipeDev->msgQ, buffer, maxbytes, WAIT_FOREVER);
  424.     if (nbytes == ERROR)
  425. return (ERROR);
  426.     /* wake up any select-blocked writers */
  427.     selWakeupAll (&pPipeDev->selWakeupList, SELWRITE);
  428.     return (nbytes);
  429.     }
  430. /*******************************************************************************
  431. *
  432. * pipeWrite - write bytes to a pipe
  433. *
  434. * This routine writes a message of `nbytes' to the pipe.
  435. *
  436. * RETURNS: number of bytes written or ERROR
  437. */
  438. LOCAL int pipeWrite
  439.     (
  440.     FAST PIPE_DEV * pPipeDev, /* pointer to pipe descriptor */
  441.     char *          buffer, /* buffer from which to copy bytes */
  442.     int             nbytes /* number of bytes to copy from buffer */
  443.     )
  444.     {
  445.     if (!INT_CONTEXT ())
  446. TASK_LOCK (); /* LOCK PREEMPTION */
  447.     /* 
  448.      * We lock preemption so after we send the message we can guarantee that
  449.      * we get to the selWakeupAll() call before unblocking any readers.  This
  450.      * is to avoid a race in which a higher priority reader of the pipe is
  451.      * unblocked by the msgQSend() below and subsequently enters and blocks
  452.      * in a call to select(), only to be inadvertently awakened when we return
  453.      * here and call selWakeupAll().  To minimize preemption latency we
  454.      * release the preemption lock after we obtain the selWakeupList mutual
  455.      * exclusion semaphore.  This semaphore is a mutual exclusion semaphore
  456.      * which allows recursive takes.  Avoiding a preemption lock by utilizing
  457.      * the selWakeupList semaphore as the only means of mutual exclusion is
  458.      * not viable because deadlock can occur by virtue of the fact that
  459.      * msgQSend() can block if the the message queue is full at which time a
  460.      * call to select() could block waiting for the listMutex instead of
  461.      * returning that a read is OK.  A problem this approach does not account
  462.      * for is the possibility that the selWakeupList semaphore is unavailable
  463.      * when the semTake() is attempted below.  If this were the case, the
  464.      * task could be preempted and therefore be vulnerable to the same
  465.      * scenario outlined above.  
  466.      */
  467.     if (msgQSend (&pPipeDev->msgQ, buffer, (UINT) nbytes,
  468.   INT_CONTEXT() ? NO_WAIT : WAIT_FOREVER, MSG_PRI_NORMAL) != OK)
  469. {
  470. if (!INT_CONTEXT ())
  471.     TASK_UNLOCK (); /* UNLOCK PREEMPTION */
  472. return (ERROR);
  473. }
  474.     if (!INT_CONTEXT ())
  475. {
  476. semTake (&pPipeDev->selWakeupList.listMutex, WAIT_FOREVER);
  477. TASK_UNLOCK (); /* UNLOCK PREEMPTION */
  478. }
  479.     /* wake up any select-blocked readers */
  480.     selWakeupAll (&pPipeDev->selWakeupList, SELREAD);
  481.     if (!INT_CONTEXT ())
  482. semGive (&pPipeDev->selWakeupList.listMutex);
  483.     return (nbytes);
  484.     }
  485. /*******************************************************************************
  486. *
  487. * pipeIoctl - do device specific control function
  488. *
  489. * The ioctl requests recognized are FIONREAD, FIONMSGS, and FIOFLUSH.
  490. *
  491. * RETURNS:
  492. *  OK and `argptr' gets number of bytes in pipe, or
  493. *  ERROR if request is not FIONREAD, FIONMSGS, or FIOFLUSH.
  494. */
  495. LOCAL STATUS pipeIoctl
  496.     (
  497.     FAST PIPE_DEV *pPipeDev, /* pointer to pipe descriptor */
  498.     int           request, /* ioctl code */
  499.     int           *argptr /* where to send answer */
  500.     )
  501.     {
  502.     STATUS status = OK;
  503.     MSG_Q_INFO msgQInfo;
  504.     SEL_WAKEUP_NODE * wakeNode = (SEL_WAKEUP_NODE *) argptr;
  505.     switch (request)
  506. {
  507. case FIONREAD:
  508.     /* number of bytes in 1st message in the queue */
  509.     bzero ((char *) &msgQInfo, sizeof (msgQInfo));
  510.     msgQInfo.msgListMax = 1;
  511.     msgQInfo.msgLenList = argptr;
  512.     *argptr = 0;
  513.     msgQInfoGet (&pPipeDev->msgQ, &msgQInfo);
  514.     break;
  515. case FIONMSGS:
  516.     /* number of messages in pipe */
  517.     *argptr = msgQNumMsgs (&pPipeDev->msgQ);
  518.     break;
  519. case FIOFLUSH:
  520.     /* discard all outstanding messages */
  521.     taskLock ();
  522.     while (msgQReceive (&pPipeDev->msgQ, (char *) NULL, 0, NO_WAIT) !=
  523. ERROR)
  524. ;
  525.     taskUnlock ();
  526.     break;
  527. case FIOSELECT:
  528.     selNodeAdd (&pPipeDev->selWakeupList, (SEL_WAKEUP_NODE *) argptr);
  529.     switch (wakeNode->type)
  530. {
  531. case SELREAD:
  532.     if (msgQNumMsgs (&pPipeDev->msgQ) > 0)
  533.         selWakeup ((SEL_WAKEUP_NODE *) argptr);
  534.     break;
  535.     
  536. case SELWRITE:
  537.     if (pPipeDev->msgQ.maxMsgs >
  538. msgQNumMsgs (&pPipeDev->msgQ))
  539.         selWakeup ((SEL_WAKEUP_NODE *) argptr);
  540.                     break;
  541. }
  542.             break;
  543.         case FIOUNSELECT:
  544.     selNodeDelete (&pPipeDev->selWakeupList, (SEL_WAKEUP_NODE *)argptr);
  545.             break;
  546. default:
  547.     status = ERROR;
  548.     errnoSet (S_ioLib_UNKNOWN_REQUEST);
  549.     break;
  550. }
  551.     return (status);
  552.     }