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

VxWorks

开发平台:

C/C++

  1. /* selectLib.c - UNIX BSD 4.3 select library */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02b,20may02,gls  Added semTake to select to prevent race condition (SPR #77032)
  8. 02a,30nov01,sbs  Added documentation about FD_SETSIZE (SPR 9377)
  9. 01z,12oct01,brk  added SELECT functionality to ptyLib (SPR 65498) 
  10. 01y,20sep01,aeg  removed dependence on FD_SETSIZE from select() (SPR #31319).
  11. 01x,10jul97,dgp  doc: fix SPR 6476, correct no. bits examined by select()
  12. 01w,09jul97,dgp  doc: add max number of file descripters (SPR 7695)
  13. 01v,13feb95,jdi  doc tweaks.
  14. 01u,03feb93,jdi  doc changes based on review by rdc.
  15. 01t,21jan93,jdi  documentation cleanup for 5.1.
  16. 01s,23aug92,jcf  added tyLib select stuff here to make tyLib standalone.
  17. 01r,18jul92,smb  Changed errno.h to errnoLib.h.
  18. 01q,04jul92,jcf  scalable/ANSI/cleanup effort.
  19. 01p,26may92,rrr  the tree shuffle
  20. 01o,10jan92,rdc  Fixed bug in selNodeAdd - release semaphore after malloc error.
  21. 01n,09jan92,rdc  integrated fix from 5.0.2 that fixed timeout bug in select
  22.  causing incorrect return fdsets.
  23. 01m,13dec91,gae  ANSI cleanup.
  24. 01l,04oct91,rrr  passed through the ansification filter
  25.                   -changed functions to ansi style
  26.   -changed includes to have absolute path from h/
  27.   -changed VOID to void
  28.   -changed copyright notice
  29. 01k,01aug91,yao  fixed to pass 6 args to excJobAdd() call.
  30. 01j,29apr91,hdn  changed how quitTime is calculated to optimize code
  31. 01i,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  32.  doc review by rdc.
  33. 01h,24mar91,jaa  documentation cleanup.
  34. 01g,25oct90,dnw  deleted include of utime.h.
  35. 01f,01aug90,jcf  changed tcb selWakeupNode to pSelWakeupNode.
  36. 01e,13jul90,rdc  added mechanism to clean up after tasks that get deleted
  37.  while pended in select.
  38. 01d,26jun90,jcf  changed binary semaphore interface
  39. 01c,17may90,rdc  changed to use binary sem's and timeouts instead of WDOGS.
  40. 01b,14apr90,jcf  removed tcb extension dependencies.
  41. 01a,02jan90,rdc  written.
  42. */
  43. /*
  44. DESCRIPTION
  45. This library provides a BSD 4.3 compatible f2selectfP facility to wait
  46. for activity on a set of file descriptors.  selectLib provides a mechanism
  47. that gives a driver the ability to detect pended tasks that are awaiting
  48. activity on the driver's device.  This allows a driver's interrupt service
  49. routine to wake up such tasks directly, eliminating the need for polling.
  50. Applications can use select() with pipes and serial devices, in addition
  51. to sockets.  Also, select() examines f2writef1 file descriptors in addition
  52. to f2readf1 file descriptors; however, exception file descriptors remain
  53. unsupported.
  54. Typically, application developers need concern themselves only with the
  55. select() call.  However, driver developers should become familiar with the
  56. other routines that may be used with select(), if they wish to support the
  57. select() mechanism.
  58. The select facility is included in a system when VxWorks is configured
  59. with the INCLUDE_SELECT component.
  60. INCLUDE FILES: selectLib.h
  61. SEE ALSO:
  62. .pG "I/O System"
  63. */
  64. #include "vxWorks.h"
  65. #include "ioLib.h"
  66. #include "memLib.h"
  67. #include "errnoLib.h"
  68. #include "vwModNum.h"
  69. #include "net/systm.h"
  70. #include "semLib.h"
  71. #include "logLib.h"
  72. #include "string.h"
  73. #include "sysLib.h"
  74. #include "intLib.h"
  75. #include "stdlib.h"
  76. #include "taskHookLib.h"
  77. #include "selectLib.h"
  78. #include "tyLib.h"
  79. #include "ptyDrv.h"
  80. #include "private/funcBindP.h"
  81. #include "private/selectLibP.h"
  82. #include "private/iosLibP.h" /* maxFiles */
  83. /* global variables */
  84. int mutexOptionsSelectLib = SEM_Q_FIFO | SEM_DELETE_SAFE;
  85. /* forward declarations */
  86. void selWakeupAll ();
  87. /* forward static functions */
  88. LOCAL void selTyAdd (TY_DEV *pTyDev, int arg);
  89. LOCAL void selTyDelete (TY_DEV *pTyDev, int arg);
  90. LOCAL void selPtyAdd            (PSEUDO_DEV *pPtyDev, int arg);
  91. LOCAL void selPtyDelete         (PSEUDO_DEV *pPtyDev, int arg);
  92. LOCAL void selTaskDeleteHook  (WIND_TCB *pTcb);
  93. LOCAL STATUS selTaskCreateHook (WIND_TCB *pNewTcb);
  94. LOCAL STATUS selDoIoctls (fd_set *pFdSet, int fdSetWidth, int ioctlFunc,
  95.  SEL_WAKEUP_NODE *pWakeupNode, BOOL stopOnErr);
  96. /*******************************************************************************
  97. *
  98. * selectInit - initialize the select facility
  99. *
  100. * This routine initializes the UNIX BSD 4.3 select facility.  It should be
  101. * called only once, and typically is called from the root task, usrRoot(),
  102. * in usrConfig.c.  It installs a task create hook such that a select context
  103. * is initialized for each task.
  104. *
  105. * RETURNS: N/A
  106. *
  107. * INTERNAL
  108. * The <numFiles> parameter is supplied so that the root task can have a
  109. * properly defined select context area. This is needed for any init routines
  110. * executed as part of the root task which call select, e.g. nfsMountAll().
  111. */
  112. void selectInit 
  113.     (
  114.     int numFiles /* maximum number of open files */
  115.     )
  116.     {
  117.     _func_selTyAdd = (FUNCPTR) selTyAdd;
  118.     _func_selTyDelete = (FUNCPTR) selTyDelete;
  119.     _func_selPtyAdd = (FUNCPTR) selPtyAdd;
  120.     _func_selPtyDelete = (FUNCPTR) selPtyDelete; 
  121.     _func_selWakeupAll = (FUNCPTR) selWakeupAll;
  122.     _func_selWakeupListInit = (FUNCPTR) selWakeupListInit;
  123.     _func_selWakeupListTerm = (FUNCPTR) selWakeupListTerm;
  124.     if (taskCreateHookAdd ((FUNCPTR) selTaskCreateHook) != OK)
  125. {
  126. if (_func_logMsg != NULL)
  127.     {
  128.     _func_logMsg ("selectInit: couldn't install task create hook!n",
  129.    0, 0, 0, 0, 0, 0);
  130.     }
  131. return;
  132. }
  133.     /*
  134.      * Make sure maxFiles has the correct value in it. This will be overridden
  135.      * later, but this will allow the root task to use select too.
  136.      */
  137.     if (maxFiles == 0)
  138. maxFiles = numFiles;
  139.     /*
  140.      * Create the select context for the calling task too.  This should be
  141.      * the root task, but we don't check.  Instead we just make sure that
  142.      * the task doesn't already have a select context.
  143.      */
  144.     if (taskIdCurrent->pSelectContext == NULL)
  145. {
  146. if (selTaskCreateHook (taskIdCurrent) == ERROR)
  147.     {
  148.     if (_func_logMsg != NULL)
  149. {
  150. _func_logMsg ("selectInit: couldn't install create hook for the caller! 0x%xn",
  151.        errno, 0, 0, 0, 0, 0);
  152. }
  153.     return;
  154.     }
  155. }
  156.     }
  157. /*******************************************************************************
  158. *
  159. * selTaskDeleteHookAdd - initialize the select facility (part 2)
  160. *
  161. * This routine installs a select task delete hook so that tasks pended in
  162. * select() can be cleaned up properly.  This routine should only be called
  163. * once, and typically is called from the root task, usrRoot(), in usrConfig.c.
  164. * It should be called after RPC initialization so that the select task delete
  165. * hook is invoked before the RPC task delete hook whenever a task dies.
  166. *
  167. * RETURNS: N/A
  168. *
  169. * NOMANUAL
  170. */
  171. void selTaskDeleteHookAdd
  172.     (
  173.     void
  174.     )
  175.     {
  176.     if (taskDeleteHookAdd ((FUNCPTR) selTaskDeleteHook) != OK)
  177. {
  178. if (_func_logMsg != NULL)
  179.     {
  180.     _func_logMsg ("selTaskDeleteHookAdd: couldn't install task delete hook!n",
  181.      0, 0, 0, 0, 0, 0);
  182.     }
  183. }
  184.     }
  185. /*******************************************************************************
  186. *
  187. * select - pend on a set of file descriptors
  188. *
  189. * This routine permits a task to pend until one of a set of file descriptors
  190. * becomes ready.  Three parameters -- <pReadFds>, <pWriteFds>, and
  191. * <pExceptFds> -- point to file descriptor sets in which each bit
  192. * corresponds to a particular file descriptor.   Bits set in the read file
  193. * descriptor set (<pReadFds>) will cause select() to pend until data is
  194. * available on any of the corresponding file descriptors, while bits set in
  195. * the write file descriptor set (<pWriteFds>) will cause select() to pend
  196. * until any of the corresponding file descriptors become writable.  (The
  197. * <pExceptFds> parameter is currently unused, but is provided for UNIX call
  198. * compatibility.)
  199. *
  200. * The following macros are available for setting the appropriate bits
  201. * in the file descriptor set structure:
  202. * .CS
  203. *     FD_SET(fd, &fdset)
  204. *     FD_CLR(fd, &fdset)
  205. *     FD_ZERO(&fdset)
  206. * .CE
  207. *
  208. * If either <pReadFds> or <pWriteFds> is NULL, they are ignored.  The
  209. * <width> parameter defines how many bits will be examined in the file
  210. * descriptor sets, and should be set to either the maximum file descriptor
  211. * value in use plus one, or simply to FD_SETSIZE.  When select() returns, 
  212. * it zeros out the file descriptor sets, and sets only the bits that 
  213. * correspond to file descriptors that are ready.  The FD_ISSET macro may 
  214. * be used to determine which bits are set.
  215. *
  216. * If <pTimeOut> is NULL, select() will block indefinitely.  If <pTimeOut> is
  217. * not NULL, but points to a `timeval' structure with an effective time of
  218. * zero, the file descriptors in the file descriptor sets will be polled and
  219. * the results returned immediately.  If the effective time value is greater
  220. * than zero, select() will return after the specified time has elapsed, even
  221. * if none of the file descriptors are ready.
  222. *
  223. * Applications can use select() with pipes and serial devices, in addition
  224. * to sockets.  Also, select() now examines write file descriptors in
  225. * addition to read file descriptors; however, exception file descriptors
  226. * remain unsupported.
  227. *
  228. * The value for the maximum number of file descriptors configured in the
  229. * system (NUM_FILES) should be less than or equal to the value of 
  230. * FD_SETSIZE (2048).
  231. *
  232. * Driver developers should consult the 
  233. * .I "VxWorks Programmer's Guide: I/O System"
  234. * for details on writing drivers that will use select().
  235. *
  236. * INTERNAL
  237. * The select library can handle arbitrarily large fd_sets, i.e. up to
  238. * the maximum number of file descriptors configured in the system
  239. * (NUM_FILES).  To maintain this capability, the use of the macro
  240. * FD_SETSIZE must be restricted.  For example, instead of using FD_ZERO,
  241. * use bzero().
  242. * RETURNS:
  243. * The number of file descriptors with activity, 0 if timed out, or
  244. * ERROR if an error occurred when the driver's select() routine
  245. * was invoked via ioctl().
  246. *
  247. * ERRNOS
  248. * Possible errnos generated by this routine include:
  249. * .iP 'S_selectLib_NO_SELECT_SUPPORT_IN_DRIVER'
  250. * A driver associated with one or more fds does not support select().
  251. * .iP 'S_selectLib_NO_SELECT_CONTEXT'
  252. * The task's select context was not initialized at task creation time.
  253. * .iP 'S_selectLib_WIDTH_OUT_OF_RANGE'
  254. * The width parameter is greater than the maximum possible fd.
  255. * .LP
  256. *
  257. * SEE ALSO:
  258. * .pG "I/O System"
  259. */
  260. int select
  261.     (
  262.     int             width,      /* number of bits to examine from 0 */
  263.     FAST fd_set    *pReadFds,   /* read fds */
  264.     FAST fd_set    *pWriteFds,  /* write fds */
  265.     fd_set         *pExceptFds, /* exception fds (unsupported) */
  266.     struct timeval *pTimeOut    /* max time to wait, NULL = forever */
  267.     )
  268.     {
  269.     FAST int fd;
  270.     FAST int partMask;
  271.     SEL_WAKEUP_NODE wakeupNode;
  272.     int widthInBytes;
  273.     int status;
  274.     int numFound = 0;
  275.     int quitTime = 0;
  276.     int clockRate;
  277.     SEL_CONTEXT *pSelectContext = taskIdCurrent->pSelectContext;
  278.     /* ensure that the task's select context was successfully initialized */
  279.     if (pSelectContext == NULL)
  280. {
  281. errno = S_selectLib_NO_SELECT_CONTEXT;
  282. return (ERROR);
  283. }
  284.     /* gracefully handle situation where width is larger than maxFiles */
  285.     if ((width < 0) || ((width > maxFiles) && (width > FD_SETSIZE)))
  286. {
  287. errno = S_selectLib_WIDTH_OUT_OF_RANGE;
  288. return (ERROR);
  289. }
  290.     /* truncate width to maxFiles for cases when FD_SETSIZE is specifed */
  291.     if (width > maxFiles)
  292. width = maxFiles;
  293.     widthInBytes = howmany(width, NFDBITS) * sizeof (fd_mask);
  294.     /*
  295.      * Make a copy of the original read/write fd_set for potential use
  296.      * by the task delete hook. Note that FD_ZERO is not used since it
  297.      * uses FD_SETSIZE.
  298.      */
  299.     if (pReadFds != NULL)
  300. bcopy ((char*) pReadFds, (char *) pSelectContext->pOrigReadFds,
  301. widthInBytes);
  302.     else
  303. bzero ((char *) pSelectContext->pOrigReadFds, widthInBytes);
  304.     if (pWriteFds != NULL)
  305. bcopy ((char*) pWriteFds, (char *) pSelectContext->pOrigWriteFds,
  306. widthInBytes);
  307.     else
  308. bzero ((char *) pSelectContext->pOrigWriteFds, widthInBytes);
  309.     if (pTimeOut != NULL)
  310. {
  311. clockRate = sysClkRateGet ();
  312. /* convert to ticks */
  313. quitTime = (pTimeOut->tv_sec * clockRate) +
  314.             ((((pTimeOut->tv_usec * clockRate) / 100)/100)/100);
  315. }
  316.     /* initialize select context and wakeup node fields */
  317.     pSelectContext->pReadFds = pReadFds;
  318.     pSelectContext->pWriteFds = pWriteFds;
  319.     /*
  320.      * The reason we would want to take the semaphore here is that it
  321.      * serves to prevent a race condition.  Without this semTake it is
  322.      * possible for the call to select to be interrupted after acquiring
  323.      * the semaphore but BEFORE the driver's FIOUNSELECT routine is called.
  324.      * If another 'event' occurs on the driver's device during this time
  325.      * it will be handled by the current call to select(), but not detected.
  326.      * That is to say, the wakeup semaphore will remain available.  The next
  327.      * call to select will take this semaphore but find that there is no
  328.      * 'event' to handle and return this, which is interpreted as a
  329.      * timeout.
  330.      *
  331.      * By taking the semaphore prior to calling the FIOSELECT routine of the
  332.      * driver we will then properly wait for a valid 'event' in this case.  
  333.      * If the semaphore is already empty we will pass through as NO_WAIT 
  334.      * is specified.  
  335.      */
  336.     semTake(&pSelectContext->wakeupSem, NO_WAIT);
  337.     wakeupNode.taskId = taskIdSelf ();
  338.     /* clear out the read and write fd_sets in task's context */
  339.     if (pReadFds != NULL)
  340. bzero ((char *)pReadFds, widthInBytes);
  341.     if (pWriteFds != NULL)
  342. bzero ((char *)pWriteFds, widthInBytes);
  343.     /* Clear out caller's copy of exception fds for completeness */
  344.     if (pExceptFds != NULL)
  345. bzero ((char *)pExceptFds, widthInBytes);
  346.     status = OK;
  347.     /* do the read fd's */
  348.     if (pReadFds != NULL)
  349. {
  350. wakeupNode.type = SELREAD;
  351. if (selDoIoctls (pSelectContext->pOrigReadFds, width,
  352.  FIOSELECT, &wakeupNode, TRUE) != OK)
  353.     {
  354.     status = ERROR;
  355.     }
  356. }
  357.     /* do the write fd's */
  358.     if (status != ERROR)
  359. if (pWriteFds != NULL)
  360.     {
  361.     wakeupNode.type = SELWRITE;
  362.     if (selDoIoctls (pSelectContext->pOrigWriteFds, width,
  363.      FIOSELECT, &wakeupNode, TRUE) != OK)
  364. {
  365. status = ERROR;
  366. }
  367.     }
  368.     if (status != OK)
  369. {
  370. status = errnoGet ();
  371. wakeupNode.type = SELREAD;
  372. selDoIoctls (pSelectContext->pOrigReadFds, width, FIOUNSELECT, 
  373.      &wakeupNode, FALSE);
  374. wakeupNode.type = SELWRITE;
  375. selDoIoctls (pSelectContext->pOrigWriteFds, width, FIOUNSELECT,
  376.      &wakeupNode, FALSE);
  377. /* if no select support in driver, inform the naive user */
  378. if (status == S_ioLib_UNKNOWN_REQUEST)
  379.     errnoSet (S_selectLib_NO_SELECT_SUPPORT_IN_DRIVER);
  380. return (ERROR);
  381. }
  382.     /* if the user specified a zero quittime, we don't pend.
  383.      * a NULL pointer indicates wait for ever
  384.      */
  385.     if ((pTimeOut != NULL) && (quitTime == 0))
  386. quitTime = NO_WAIT;
  387.     else
  388. if (pTimeOut == NULL)
  389.     quitTime = WAIT_FOREVER;
  390.     /*
  391.      * Indicate that the current task is pended in select().  In the
  392.      * event the current task is deleted, the task delete hook will
  393.      * be able to remove the various wakeup nodes from driver lists.
  394.      */
  395.     pSelectContext->width     = width;
  396.     pSelectContext->pendedOnSelect = TRUE;
  397.     semTake (&pSelectContext->wakeupSem, quitTime);
  398.     /* clean up after ourselves */
  399.     /* first the read fd's ... */
  400.     status = OK;
  401.     if (pReadFds != NULL)
  402. {
  403. wakeupNode.type = SELREAD;
  404. if (selDoIoctls (pSelectContext->pOrigReadFds, width,
  405.  FIOUNSELECT, &wakeupNode, FALSE) != OK)
  406.     {
  407.     status = ERROR;
  408.     }
  409. }
  410.     /* ... now the write fd's. */
  411.     if (pWriteFds != NULL)
  412. {
  413. wakeupNode.type = SELWRITE;
  414. if (selDoIoctls (pSelectContext->pOrigWriteFds, width,
  415.  FIOUNSELECT, &wakeupNode, FALSE) != OK)
  416.     {
  417.     status = ERROR;
  418.     }
  419. }
  420.     /* indicate that current task is no longer pended in select() */
  421.     pSelectContext->pendedOnSelect = FALSE;
  422.     if (status == ERROR)
  423. return (ERROR);
  424.     /* find out how many bits are set in the read and write fd sets */
  425.     if (pReadFds != NULL)
  426. for (fd = 0; fd < width; fd++)
  427.     {
  428.     /* look at the fd_set a long word at a time */
  429.     partMask = pReadFds->fds_bits[((unsigned)fd) / NFDBITS];
  430.     if (partMask == 0)
  431. {
  432. fd += NFDBITS - 1;
  433. }
  434.     else if (partMask & (1 << (((unsigned) fd) % NFDBITS)))
  435. {
  436. numFound++;
  437. }
  438.     }
  439.     if (pWriteFds != NULL)
  440. for (fd = 0; fd < width; fd++)
  441.     {
  442.     /* look at the fd_set a long word at a time */
  443.     partMask = pWriteFds->fds_bits[((unsigned)fd) / NFDBITS];
  444.     if (partMask == 0)
  445. fd += NFDBITS - 1;
  446.     else if (partMask & (1 << (((unsigned) fd) % NFDBITS)))
  447. {
  448. numFound++;
  449. }
  450.     }
  451.     return (numFound);
  452.     }
  453. /******************************************************************************
  454. *
  455. * selDoIoctls - perform the given ioctl on all the fd's in a mask
  456. *
  457. * RETURNS: OK or ERROR if ioctl failed.
  458. */
  459. LOCAL STATUS selDoIoctls
  460.     (
  461.     FAST fd_set *pFdSet,
  462.     FAST int fdSetWidth,
  463.     FAST int ioctlFunc,
  464.     FAST SEL_WAKEUP_NODE *pWakeupNode,
  465.     BOOL stopOnErr
  466.     )
  467.     {
  468.     FAST int fd;
  469.     FAST int partMask;
  470.     int status = OK;
  471.     for (fd = 0; fd < fdSetWidth; fd++)
  472. {
  473. /* look at the fd_set a long word at a time */
  474. partMask = pFdSet->fds_bits[((unsigned)fd)/NFDBITS];
  475. if (partMask == 0)
  476.     fd += NFDBITS - 1;
  477. else if (partMask & (1 << (((unsigned) fd) % NFDBITS)))
  478.     {
  479.     pWakeupNode->fd = fd;
  480.     if (ioctl (fd, ioctlFunc, (int)pWakeupNode) != OK)
  481. {
  482. status = ERROR;
  483. if (stopOnErr)
  484.     break;
  485. }
  486.     }
  487. }
  488.     return (status);
  489.     }
  490. /* The following routines are available to drivers to manage wake-up lists */
  491. /******************************************************************************
  492. *
  493. * selWakeup - wake up a task pended in select()
  494. *
  495. * This routine wakes up a task pended in select().  Once a driver's
  496. * FIOSELECT function installs a wake-up node in a device's wake-up list
  497. * (using selNodeAdd()) and checks to make sure the device is ready, this
  498. * routine ensures that the select() call does not pend.
  499. *
  500. * RETURNS: N/A
  501. */
  502. void selWakeup
  503.     (
  504.     SEL_WAKEUP_NODE *pWakeupNode        /* node to wake up */
  505.     )
  506.     {
  507.     SEL_CONTEXT *pSelectContext;
  508.     pSelectContext = ((WIND_TCB *)pWakeupNode->taskId)->pSelectContext;
  509.     switch (pWakeupNode->type)
  510. {
  511. case SELREAD:
  512.     FD_SET(pWakeupNode->fd, pSelectContext->pReadFds);
  513.     break;
  514. case SELWRITE:
  515.     FD_SET(pWakeupNode->fd, pSelectContext->pWriteFds);
  516.     break;
  517. }
  518.     semGive (&pSelectContext->wakeupSem);
  519.     }
  520. /******************************************************************************
  521. *
  522. * selWakeupAll - wake up all tasks in a select() wake-up list
  523. *
  524. * This routine wakes up all tasks pended in select() that are waiting for
  525. * a device; it is called by a driver when the device becomes ready.  The
  526. * <type> parameter specifies the task to be awakened, either reader tasks
  527. * (SELREAD) or writer tasks (SELWRITE).
  528. *
  529. * RETURNS: N/A
  530. */
  531. void selWakeupAll
  532.     (
  533.     SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */
  534.     FAST SELECT_TYPE type         /* readers (SELREAD) or writers (SELWRITE) */
  535.     )
  536.     {
  537.     FAST SEL_WAKEUP_NODE *pWakeupNode;
  538.     if (lstCount (&pWakeupList->wakeupList) == 0)
  539. return;
  540.     if (intContext ())
  541. {
  542. excJobAdd (selWakeupAll, (int)pWakeupList, (int)type, 0, 0, 0, 0);
  543. return;
  544. }
  545.     semTake (&pWakeupList->listMutex, WAIT_FOREVER);
  546.     for (pWakeupNode = (SEL_WAKEUP_NODE *) lstFirst (&pWakeupList->wakeupList);
  547.          pWakeupNode != NULL;
  548.          pWakeupNode = (SEL_WAKEUP_NODE *) lstNext ((NODE *) pWakeupNode))
  549.          {
  550.          if (pWakeupNode->type == type)
  551.             selWakeup (pWakeupNode);
  552.          }
  553.     semGive (&pWakeupList->listMutex);
  554.     }
  555. /******************************************************************************
  556. *
  557. * selNodeAdd - add a wake-up node to a select() wake-up list
  558. *
  559. * This routine adds a wake-up node to a device's wake-up list.  It is 
  560. * typically called from a driver's FIOSELECT function.
  561. *
  562. * RETURNS: OK, or ERROR if memory is insufficient.
  563. */
  564. STATUS selNodeAdd
  565.     (
  566.     SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */
  567.     SEL_WAKEUP_NODE *pWakeupNode /* node to add to list */
  568.     )
  569.     {
  570.     SEL_WAKEUP_NODE *pCopyOfNode;
  571.     BOOL dontFree;
  572.     semTake (&pWakeupList->listMutex, WAIT_FOREVER);
  573.     if (lstCount (&pWakeupList->wakeupList) == 0)
  574. {
  575. pCopyOfNode = &pWakeupList->firstNode;
  576. dontFree = TRUE;
  577. }
  578.     else
  579. {
  580. pCopyOfNode = (SEL_WAKEUP_NODE *) malloc (sizeof (SEL_WAKEUP_NODE));
  581. dontFree = FALSE;
  582. }
  583.     if (pCopyOfNode == NULL)
  584. {
  585. semGive (&pWakeupList->listMutex);
  586. return (ERROR);
  587. }
  588.     *pCopyOfNode = *pWakeupNode;
  589.     pCopyOfNode->dontFree = dontFree;
  590.     lstAdd (&pWakeupList->wakeupList, (NODE *) pCopyOfNode);
  591.     semGive (&pWakeupList->listMutex);
  592.     return (OK);
  593.     }
  594. /******************************************************************************
  595. *
  596. * selNodeDelete - find and delete a node from a select() wake-up list
  597. *
  598. * This routine deletes a specified wake-up node from a specified wake-up
  599. * list.  Typically, it is called by a driver's FIOUNSELECT function.
  600. *
  601. * RETURNS: OK, or ERROR if the node is not found in the wake-up list.
  602. */
  603. STATUS selNodeDelete
  604.     (
  605.     SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */
  606.     SEL_WAKEUP_NODE *pWakeupNode /* node to delete from list */
  607.     )
  608.     {
  609.     FAST SEL_WAKEUP_NODE *pWorkNode;
  610.     semTake (&pWakeupList->listMutex, WAIT_FOREVER); /* get exclusion */
  611.     for (pWorkNode = (SEL_WAKEUP_NODE *) lstFirst (&pWakeupList->wakeupList);
  612.          pWorkNode != NULL;
  613.          pWorkNode = (SEL_WAKEUP_NODE *) lstNext ((NODE *) pWorkNode))
  614. {
  615. if ((pWorkNode->taskId == pWakeupNode->taskId) &&
  616.     (pWorkNode->type == pWakeupNode->type))
  617.     {
  618.     lstDelete (&pWakeupList->wakeupList, (NODE *) pWorkNode);
  619.     if (!(pWorkNode->dontFree))
  620. free ((char *) pWorkNode); /* deallocate node */
  621.     semGive (&pWakeupList->listMutex); /* release exclusion */
  622.     return (OK);
  623.     }
  624.          }
  625.     semGive (&pWakeupList->listMutex); /* release exclusion */
  626.     return (ERROR);
  627.     }
  628. /******************************************************************************
  629. *
  630. * selWakeupListInit - initialize a select() wake-up list
  631. *
  632. * This routine should be called in a device's create routine to
  633. * initialize the SEL_WAKEUP_LIST structure.
  634. *
  635. * RETURNS: N/A
  636. *
  637. */
  638. void selWakeupListInit
  639.     (
  640.     SEL_WAKEUP_LIST *pWakeupList /* wake-up list to initialize */
  641.     )
  642.     {
  643.     lstInit (&pWakeupList->wakeupList);
  644.     semMInit (&pWakeupList->listMutex, mutexOptionsSelectLib);
  645.     }
  646. /******************************************************************************
  647. *
  648. * selWakeupListTerm - terminate a select() wake-up list
  649. *
  650. * This routine should be called in a device's terminate routine to
  651. * terminate the SEL_WAKEUP_LIST structure.
  652. *
  653. * RETURNS: N/A
  654. *
  655. */
  656. void selWakeupListTerm
  657.     (
  658.     SEL_WAKEUP_LIST *pWakeupList /* wake-up list to terminate */
  659.     )
  660.     {
  661.     semTerminate (&pWakeupList->listMutex);
  662.     }
  663. /******************************************************************************
  664. *
  665. * selWakeupListLen - get the number of nodes in a select() wake-up list
  666. *
  667. * This routine returns the number of nodes in a specified SEL_WAKEUP_LIST.
  668. * It can be used by a driver to determine if any tasks are currently
  669. * pended in select() on this device, and whether these tasks need to be
  670. * activated with selWakeupAll().
  671. *
  672. * RETURNS:
  673. * The number of nodes currently in a select() wake-up list, or ERROR.
  674. *
  675. */
  676. int selWakeupListLen
  677.     (
  678.     SEL_WAKEUP_LIST *pWakeupList /* list of tasks to wake up */
  679.     )
  680.     {
  681.     return (lstCount (&pWakeupList->wakeupList));
  682.     }
  683. /******************************************************************************
  684. *
  685. * selWakeupType - get the type of a select() wake-up node
  686. *
  687. * This routine returns the type of a specified SEL_WAKEUP_NODE.
  688. * It is typically used in a device's FIOSELECT function to determine
  689. * if the device is being selected for read or write operations.
  690. *
  691. * RETURNS: SELREAD (read operation) or SELWRITE (write operation).
  692. *
  693. */
  694. SELECT_TYPE selWakeupType
  695.     (
  696.     SEL_WAKEUP_NODE *pWakeupNode /* node to get type of */
  697.     )
  698.     {
  699.     return (pWakeupNode->type);
  700.     }
  701. /******************************************************************************
  702. *
  703. * selTaskCreateHook - select task create hook
  704. *
  705. * This routine creates a select context for the task.  The select context 
  706. * for the root task is not created by this routine.  Instead, it is created 
  707. * by the selectInit() routine.
  708. *
  709. * The memory for the context is allocated from the system heap.  The amount
  710. * of memory allocated for the context is enough to support fd_sets of size
  711. * maxFiles, instead of the compile time value of FD_SETSIZE.
  712. *
  713. * This routine is installed as a create hook by selectInit.
  714. */
  715. LOCAL STATUS selTaskCreateHook
  716.     (
  717.     WIND_TCB *pNewTcb
  718.     )
  719.     {
  720.     SEL_CONTEXT *pSelectContext;
  721.     int  fdSetBytes;
  722.     /*
  723.      * Allocate sufficient memory from the heap to contain the select
  724.      * context.  This memory includes space for the various fd_sets to
  725.      * handle file descriptors up to maxFiles, i.e. select() will not be
  726.      * limited to FD_SETSIZE.
  727.      */
  728.      fdSetBytes = sizeof (fd_mask) * howmany (maxFiles, NFDBITS);
  729.      pSelectContext = (SEL_CONTEXT *) malloc (sizeof (SEL_CONTEXT) + 
  730.            2 * fdSetBytes);
  731.      if (pSelectContext == NULL)
  732. return (ERROR);
  733.      /* assign various convenience fd_set pointers */
  734.      pSelectContext->pOrigReadFds   = (fd_set *) ((int) pSelectContext +
  735.  sizeof (SEL_CONTEXT));
  736.      pSelectContext->pOrigWriteFds  = (fd_set *)
  737.       ((int) pSelectContext->pOrigReadFds +
  738.      fdSetBytes);
  739.      pSelectContext->pendedOnSelect = FALSE;   /* task is not pending */
  740.      /* initialize the task's wakeup binary semaphore */
  741.      if (semBInit (&pSelectContext->wakeupSem, SEM_Q_PRIORITY, 
  742.    SEM_EMPTY) != OK)
  743.  {
  744.  free ((char*) pSelectContext);
  745.  return (ERROR);
  746.  }
  747.     /* initialization succeeded so set task's select context pointer */
  748.     pNewTcb->pSelectContext = pSelectContext;
  749.     return (OK);
  750.     }
  751. /******************************************************************************
  752. *
  753. * selTaskDeleteHook - select task delete hook
  754. *
  755. * If a task is deleted while it is pended in select, this delete hook
  756. * tells all the relevent devices to delete the wake-up node associated
  757. * with this task.  This routine is installed as a delete hook by 
  758. * selTaskDeleteHookAdd().  RPC adds a delete hook to close the client and
  759. * server handle sockets -- we insure that the select delete hook gets 
  760. * called before the RPC delete hook (so that the socket device still exists)
  761. * by installing it AFTER RPC initialization (see usrConfig.c).
  762. */
  763. LOCAL void selTaskDeleteHook
  764.     (
  765.     WIND_TCB *pTcb
  766.     )
  767.     {
  768.     SEL_CONTEXT *pSelectContext = pTcb->pSelectContext;
  769.     /* 
  770.      * A wakeup node is created on the deleting task's stack since
  771.      * the work node on the stack of the task being deleting may
  772.      * be inaccessible to the current task.
  773.      */
  774.     SEL_WAKEUP_NODE wakeupNode;
  775.     if (pSelectContext != NULL)
  776. {
  777. /* task pended in select()? */
  778. if (pSelectContext->pendedOnSelect == TRUE)
  779.     {
  780.     wakeupNode.taskId = (int) pTcb;
  781.     /* unregister all the read fd's */
  782.     wakeupNode.type   = SELREAD;
  783.     selDoIoctls (pSelectContext->pOrigReadFds, pSelectContext->width,
  784.  FIOUNSELECT, &wakeupNode, FALSE);
  785.     /* unregister all the write fd's */
  786.     wakeupNode.type = SELWRITE;
  787.     selDoIoctls (pSelectContext->pOrigWriteFds, pSelectContext->width,
  788.  FIOUNSELECT, &wakeupNode, FALSE);
  789.     }
  790. semTerminate (&pSelectContext->wakeupSem);
  791. free ((char *) pSelectContext);
  792. }
  793.     }
  794. /*******************************************************************************
  795. *
  796. * selTyAdd - tyLib FIOSELECT ioctl
  797. *
  798. * This is located here to keep tyLib from dragging in selectLib.
  799. */
  800. LOCAL void selTyAdd 
  801.     (
  802.     TY_DEV *pTyDev,
  803.     int arg 
  804.     )
  805.     {
  806.     selNodeAdd (&pTyDev->selWakeupList, (SEL_WAKEUP_NODE *) arg);
  807.     if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELREAD) &&
  808.  (rngNBytes (pTyDev->rdBuf) > 0))
  809. {
  810. selWakeup ((SEL_WAKEUP_NODE *) arg);
  811. }
  812.     if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELWRITE) &&
  813.  rngFreeBytes (pTyDev->wrtBuf) > 0)
  814. {
  815. selWakeup ((SEL_WAKEUP_NODE *) arg);
  816. }
  817.     }
  818. /*******************************************************************************
  819. *
  820. * selTyDelete - tyLib FIOUNSELECT ioctl
  821. *
  822. * This is located here to keep tyLib from dragging in selectLib.
  823. */
  824. LOCAL void selTyDelete
  825.     (
  826.     TY_DEV *pTyDev,
  827.     int arg 
  828.     )
  829.     {
  830.     selNodeDelete (&pTyDev->selWakeupList, (SEL_WAKEUP_NODE *)arg);
  831.     }
  832. /*******************************************************************************
  833. *
  834. * selPtyAdd - ptyLib FIOSELECT ioctl
  835. *
  836. * This is located here to keep ptyLib from dragging in selectLib.
  837. */
  838. LOCAL void selPtyAdd 
  839.     (
  840.     PSEUDO_DEV *pPtyDev,
  841.     int arg 
  842.     )
  843.     {
  844.     selNodeAdd (&pPtyDev->masterSelWakeupList, (SEL_WAKEUP_NODE *) arg);
  845.     if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELREAD) &&
  846.   rngNBytes (pPtyDev->tyDev.wrtBuf) > 0)
  847. /* reversed read criteria for master */
  848. {
  849. selWakeup ((SEL_WAKEUP_NODE *) arg);
  850. }
  851.     if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELWRITE) &&
  852.  rngFreeBytes (pPtyDev->tyDev.rdBuf) > 0 )
  853. /* reversed write criteria for master */
  854. {
  855. selWakeup ((SEL_WAKEUP_NODE *) arg);
  856. }
  857.     }
  858. /*******************************************************************************
  859. *
  860. * selPtyDelete - ptyLib FIOUNSELECT ioctl
  861. *
  862. * This is located here to keep ptyLib from dragging in selectLib.
  863. */
  864. LOCAL void selPtyDelete
  865.     (
  866.     PSEUDO_DEV *pPtyDev,
  867.     int arg 
  868.     )
  869.     {
  870.     selNodeDelete (&pPtyDev->masterSelWakeupList, (SEL_WAKEUP_NODE *)arg);
  871.     }