?? selectlib.c
字號(hào):
/* selectLib.c - UNIX BSD 4.3 select library *//* Copyright 1984-2001 Wind River Systems, Inc. */#include "copyright_wrs.h"/*modification history--------------------02b,20may02,gls Added semTake to select to prevent race condition (SPR #77032)02a,30nov01,sbs Added documentation about FD_SETSIZE (SPR 9377)01z,12oct01,brk added SELECT functionality to ptyLib (SPR 65498) 01y,20sep01,aeg removed dependence on FD_SETSIZE from select() (SPR #31319).01x,10jul97,dgp doc: fix SPR 6476, correct no. bits examined by select()01w,09jul97,dgp doc: add max number of file descripters (SPR 7695)01v,13feb95,jdi doc tweaks.01u,03feb93,jdi doc changes based on review by rdc.01t,21jan93,jdi documentation cleanup for 5.1.01s,23aug92,jcf added tyLib select stuff here to make tyLib standalone.01r,18jul92,smb Changed errno.h to errnoLib.h.01q,04jul92,jcf scalable/ANSI/cleanup effort.01p,26may92,rrr the tree shuffle01o,10jan92,rdc Fixed bug in selNodeAdd - release semaphore after malloc error.01n,09jan92,rdc integrated fix from 5.0.2 that fixed timeout bug in select causing incorrect return fdsets.01m,13dec91,gae ANSI cleanup.01l,04oct91,rrr passed through the ansification filter -changed functions to ansi style -changed includes to have absolute path from h/ -changed VOID to void -changed copyright notice01k,01aug91,yao fixed to pass 6 args to excJobAdd() call.01j,29apr91,hdn changed how quitTime is calculated to optimize code01i,05apr91,jdi documentation -- removed header parens and x-ref numbers; doc review by rdc.01h,24mar91,jaa documentation cleanup.01g,25oct90,dnw deleted include of utime.h.01f,01aug90,jcf changed tcb selWakeupNode to pSelWakeupNode.01e,13jul90,rdc added mechanism to clean up after tasks that get deleted while pended in select.01d,26jun90,jcf changed binary semaphore interface01c,17may90,rdc changed to use binary sem's and timeouts instead of WDOGS.01b,14apr90,jcf removed tcb extension dependencies.01a,02jan90,rdc written.*//*DESCRIPTIONThis library provides a BSD 4.3 compatible \f2select\fP facility to waitfor activity on a set of file descriptors. selectLib provides a mechanismthat gives a driver the ability to detect pended tasks that are awaitingactivity on the driver's device. This allows a driver's interrupt serviceroutine to wake up such tasks directly, eliminating the need for polling.Applications can use select() with pipes and serial devices, in additionto sockets. Also, select() examines \f2write\f1 file descriptors in additionto \f2read\f1 file descriptors; however, exception file descriptors remainunsupported.Typically, application developers need concern themselves only with theselect() call. However, driver developers should become familiar with theother routines that may be used with select(), if they wish to support theselect() mechanism.The select facility is included in a system when VxWorks is configuredwith the INCLUDE_SELECT component.INCLUDE FILES: selectLib.hSEE ALSO:.pG "I/O System"*/#include "vxWorks.h"#include "ioLib.h"#include "memLib.h"#include "errnoLib.h"#include "vwModNum.h"#include "net/systm.h"#include "semLib.h"#include "logLib.h"#include "string.h"#include "sysLib.h"#include "intLib.h"#include "stdlib.h"#include "taskHookLib.h"#include "selectLib.h"#include "tyLib.h"#include "ptyDrv.h"#include "private/funcBindP.h"#include "private/selectLibP.h"#include "private/iosLibP.h" /* maxFiles *//* global variables */int mutexOptionsSelectLib = SEM_Q_FIFO | SEM_DELETE_SAFE;/* forward declarations */void selWakeupAll ();/* forward static functions */LOCAL void selTyAdd (TY_DEV *pTyDev, int arg);LOCAL void selTyDelete (TY_DEV *pTyDev, int arg);LOCAL void selPtyAdd (PSEUDO_DEV *pPtyDev, int arg);LOCAL void selPtyDelete (PSEUDO_DEV *pPtyDev, int arg);LOCAL void selTaskDeleteHook (WIND_TCB *pTcb);LOCAL STATUS selTaskCreateHook (WIND_TCB *pNewTcb);LOCAL STATUS selDoIoctls (fd_set *pFdSet, int fdSetWidth, int ioctlFunc, SEL_WAKEUP_NODE *pWakeupNode, BOOL stopOnErr);/********************************************************************************* selectInit - initialize the select facility** This routine initializes the UNIX BSD 4.3 select facility. It should be* called only once, and typically is called from the root task, usrRoot(),* in usrConfig.c. It installs a task create hook such that a select context* is initialized for each task.** RETURNS: N/A** INTERNAL* The <numFiles> parameter is supplied so that the root task can have a* properly defined select context area. This is needed for any init routines* executed as part of the root task which call select, e.g. nfsMountAll().*/void selectInit ( int numFiles /* maximum number of open files */ ) { _func_selTyAdd = (FUNCPTR) selTyAdd; _func_selTyDelete = (FUNCPTR) selTyDelete; _func_selPtyAdd = (FUNCPTR) selPtyAdd; _func_selPtyDelete = (FUNCPTR) selPtyDelete; _func_selWakeupAll = (FUNCPTR) selWakeupAll; _func_selWakeupListInit = (FUNCPTR) selWakeupListInit; _func_selWakeupListTerm = (FUNCPTR) selWakeupListTerm; if (taskCreateHookAdd ((FUNCPTR) selTaskCreateHook) != OK) { if (_func_logMsg != NULL) { _func_logMsg ("selectInit: couldn't install task create hook!\n", 0, 0, 0, 0, 0, 0); } return; } /* * Make sure maxFiles has the correct value in it. This will be overridden * later, but this will allow the root task to use select too. */ if (maxFiles == 0) maxFiles = numFiles; /* * Create the select context for the calling task too. This should be * the root task, but we don't check. Instead we just make sure that * the task doesn't already have a select context. */ if (taskIdCurrent->pSelectContext == NULL) { if (selTaskCreateHook (taskIdCurrent) == ERROR) { if (_func_logMsg != NULL) { _func_logMsg ("selectInit: couldn't install create hook for the caller! 0x%x\n", errno, 0, 0, 0, 0, 0); } return; } } }/********************************************************************************* selTaskDeleteHookAdd - initialize the select facility (part 2)** This routine installs a select task delete hook so that tasks pended in* select() can be cleaned up properly. This routine should only be called* once, and typically is called from the root task, usrRoot(), in usrConfig.c.* It should be called after RPC initialization so that the select task delete* hook is invoked before the RPC task delete hook whenever a task dies.** RETURNS: N/A** NOMANUAL*/void selTaskDeleteHookAdd ( void ) { if (taskDeleteHookAdd ((FUNCPTR) selTaskDeleteHook) != OK) { if (_func_logMsg != NULL) { _func_logMsg ("selTaskDeleteHookAdd: couldn't install task delete hook!\n", 0, 0, 0, 0, 0, 0); } } }/********************************************************************************* select - pend on a set of file descriptors** This routine permits a task to pend until one of a set of file descriptors* becomes ready. Three parameters -- <pReadFds>, <pWriteFds>, and* <pExceptFds> -- point to file descriptor sets in which each bit* corresponds to a particular file descriptor. Bits set in the read file* descriptor set (<pReadFds>) will cause select() to pend until data is* available on any of the corresponding file descriptors, while bits set in* the write file descriptor set (<pWriteFds>) will cause select() to pend* until any of the corresponding file descriptors become writable. (The* <pExceptFds> parameter is currently unused, but is provided for UNIX call* compatibility.)** The following macros are available for setting the appropriate bits* in the file descriptor set structure:* .CS* FD_SET(fd, &fdset)* FD_CLR(fd, &fdset)* FD_ZERO(&fdset)* .CE** If either <pReadFds> or <pWriteFds> is NULL, they are ignored. The* <width> parameter defines how many bits will be examined in the file* descriptor sets, and should be set to either the maximum file descriptor* value in use plus one, or simply to FD_SETSIZE. When select() returns, * it zeros out the file descriptor sets, and sets only the bits that * correspond to file descriptors that are ready. The FD_ISSET macro may * be used to determine which bits are set.** If <pTimeOut> is NULL, select() will block indefinitely. If <pTimeOut> is* not NULL, but points to a `timeval' structure with an effective time of* zero, the file descriptors in the file descriptor sets will be polled and* the results returned immediately. If the effective time value is greater* than zero, select() will return after the specified time has elapsed, even* if none of the file descriptors are ready.** Applications can use select() with pipes and serial devices, in addition* to sockets. Also, select() now examines write file descriptors in* addition to read file descriptors; however, exception file descriptors* remain unsupported.** The value for the maximum number of file descriptors configured in the* system (NUM_FILES) should be less than or equal to the value of * FD_SETSIZE (2048).** Driver developers should consult the * .I "VxWorks Programmer's Guide: I/O System"* for details on writing drivers that will use select().** INTERNAL* The select library can handle arbitrarily large fd_sets, i.e. up to* the maximum number of file descriptors configured in the system* (NUM_FILES). To maintain this capability, the use of the macro* FD_SETSIZE must be restricted. For example, instead of using FD_ZERO,* use bzero().* * RETURNS:* The number of file descriptors with activity, 0 if timed out, or* ERROR if an error occurred when the driver's select() routine* was invoked via ioctl().** ERRNOS* Possible errnos generated by this routine include:* .iP 'S_selectLib_NO_SELECT_SUPPORT_IN_DRIVER'* A driver associated with one or more fds does not support select().* .iP 'S_selectLib_NO_SELECT_CONTEXT'* The task's select context was not initialized at task creation time.* .iP 'S_selectLib_WIDTH_OUT_OF_RANGE'* The width parameter is greater than the maximum possible fd.* .LP** SEE ALSO:* .pG "I/O System"*/int select ( int width, /* number of bits to examine from 0 */ FAST fd_set *pReadFds, /* read fds */ FAST fd_set *pWriteFds, /* write fds */ fd_set *pExceptFds, /* exception fds (unsupported) */ struct timeval *pTimeOut /* max time to wait, NULL = forever */ ) { FAST int fd; FAST int partMask; SEL_WAKEUP_NODE wakeupNode; int widthInBytes; int status; int numFound = 0; int quitTime = 0; int clockRate; SEL_CONTEXT *pSelectContext = taskIdCurrent->pSelectContext; /* ensure that the task's select context was successfully initialized */ if (pSelectContext == NULL) { errno = S_selectLib_NO_SELECT_CONTEXT; return (ERROR); } /* gracefully handle situation where width is larger than maxFiles */ if ((width < 0) || ((width > maxFiles) && (width > FD_SETSIZE))) { errno = S_selectLib_WIDTH_OUT_OF_RANGE; return (ERROR); } /* truncate width to maxFiles for cases when FD_SETSIZE is specifed */ if (width > maxFiles) width = maxFiles; widthInBytes = howmany(width, NFDBITS) * sizeof (fd_mask); /* * Make a copy of the original read/write fd_set for potential use * by the task delete hook. Note that FD_ZERO is not used since it * uses FD_SETSIZE. */ if (pReadFds != NULL) bcopy ((char*) pReadFds, (char *) pSelectContext->pOrigReadFds, widthInBytes); else bzero ((char *) pSelectContext->pOrigReadFds, widthInBytes); if (pWriteFds != NULL) bcopy ((char*) pWriteFds, (char *) pSelectContext->pOrigWriteFds, widthInBytes); else bzero ((char *) pSelectContext->pOrigWriteFds, widthInBytes); if (pTimeOut != NULL) { clockRate = sysClkRateGet (); /* convert to ticks */ quitTime = (pTimeOut->tv_sec * clockRate) + ((((pTimeOut->tv_usec * clockRate) / 100)/100)/100); } /* initialize select context and wakeup node fields */ pSelectContext->pReadFds = pReadFds; pSelectContext->pWriteFds = pWriteFds; /* * The reason we would want to take the semaphore here is that it * serves to prevent a race condition. Without this semTake it is * possible for the call to select to be interrupted after acquiring * the semaphore but BEFORE the driver's FIOUNSELECT routine is called. * If another 'event' occurs on the driver's device during this time * it will be handled by the current call to select(), but not detected. * That is to say, the wakeup semaphore will remain available. The next * call to select will take this semaphore but find that there is no * 'event' to handle and return this, which is interpreted as a * timeout. * * By taking the semaphore prior to calling the FIOSELECT routine of the * driver we will then properly wait for a valid 'event' in this case. * If the semaphore is already empty we will pass through as NO_WAIT * is specified. */ semTake(&pSelectContext->wakeupSem, NO_WAIT); wakeupNode.taskId = taskIdSelf (); /* clear out the read and write fd_sets in task's context */ if (pReadFds != NULL) bzero ((char *)pReadFds, widthInBytes); if (pWriteFds != NULL) bzero ((char *)pWriteFds, widthInBytes); /* Clear out caller's copy of exception fds for completeness */ if (pExceptFds != NULL) bzero ((char *)pExceptFds, widthInBytes); status = OK; /* do the read fd's */ if (pReadFds != NULL) { wakeupNode.type = SELREAD; if (selDoIoctls (pSelectContext->pOrigReadFds, width, FIOSELECT, &wakeupNode, TRUE) != OK) { status = ERROR; } } /* do the write fd's */ if (status != ERROR) if (pWriteFds != NULL) { wakeupNode.type = SELWRITE; if (selDoIoctls (pSelectContext->pOrigWriteFds, width, FIOSELECT, &wakeupNode, TRUE) != OK) { status = ERROR; } } if (status != OK) { status = errnoGet (); wakeupNode.type = SELREAD; selDoIoctls (pSelectContext->pOrigReadFds, width, FIOUNSELECT, &wakeupNode, FALSE); wakeupNode.type = SELWRITE; selDoIoctls (pSelectContext->pOrigWriteFds, width, FIOUNSELECT, &wakeupNode, FALSE); /* if no select support in driver, inform the naive user */ if (status == S_ioLib_UNKNOWN_REQUEST) errnoSet (S_selectLib_NO_SELECT_SUPPORT_IN_DRIVER); return (ERROR); } /* if the user specified a zero quittime, we don't pend. * a NULL pointer indicates wait for ever */ if ((pTimeOut != NULL) && (quitTime == 0)) quitTime = NO_WAIT; else if (pTimeOut == NULL) quitTime = WAIT_FOREVER; /* * Indicate that the current task is pended in select(). In the * event the current task is deleted, the task delete hook will * be able to remove the various wakeup nodes from driver lists. */ pSelectContext->width = width; pSelectContext->pendedOnSelect = TRUE; semTake (&pSelectContext->wakeupSem, quitTime); /* clean up after ourselves */ /* first the read fd's ... */ status = OK; if (pReadFds != NULL) { wakeupNode.type = SELREAD; if (selDoIoctls (pSelectContext->pOrigReadFds, width, FIOUNSELECT, &wakeupNode, FALSE) != OK) { status = ERROR; } } /* ... now the write fd's. */ if (pWriteFds != NULL) { wakeupNode.type = SELWRITE; if (selDoIoctls (pSelectContext->pOrigWriteFds, width, FIOUNSELECT, &wakeupNode, FALSE) != OK) { status = ERROR; } } /* indicate that current task is no longer pended in select() */ pSelectContext->pendedOnSelect = FALSE; if (status == ERROR) return (ERROR); /* find out how many bits are set in the read and write fd sets */ if (pReadFds != NULL) for (fd = 0; fd < width; fd++) { /* look at the fd_set a long word at a time */ partMask = pReadFds->fds_bits[((unsigned)fd) / NFDBITS]; if (partMask == 0) { fd += NFDBITS - 1; } else if (partMask & (1 << (((unsigned) fd) % NFDBITS))) { numFound++; } }
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -