?? selectlib.c
字號:
if (pWriteFds != NULL) for (fd = 0; fd < width; fd++) { /* look at the fd_set a long word at a time */ partMask = pWriteFds->fds_bits[((unsigned)fd) / NFDBITS]; if (partMask == 0) fd += NFDBITS - 1; else if (partMask & (1 << (((unsigned) fd) % NFDBITS))) { numFound++; } } return (numFound); }/******************************************************************************** selDoIoctls - perform the given ioctl on all the fd's in a mask** RETURNS: OK or ERROR if ioctl failed.*/LOCAL STATUS selDoIoctls ( FAST fd_set *pFdSet, FAST int fdSetWidth, FAST int ioctlFunc, FAST SEL_WAKEUP_NODE *pWakeupNode, BOOL stopOnErr ) { FAST int fd; FAST int partMask; int status = OK; for (fd = 0; fd < fdSetWidth; fd++) { /* look at the fd_set a long word at a time */ partMask = pFdSet->fds_bits[((unsigned)fd)/NFDBITS]; if (partMask == 0) fd += NFDBITS - 1; else if (partMask & (1 << (((unsigned) fd) % NFDBITS))) { pWakeupNode->fd = fd; if (ioctl (fd, ioctlFunc, (int)pWakeupNode) != OK) { status = ERROR; if (stopOnErr) break; } } } return (status); }/* The following routines are available to drivers to manage wake-up lists *//******************************************************************************** selWakeup - wake up a task pended in select()** This routine wakes up a task pended in select(). Once a driver's* FIOSELECT function installs a wake-up node in a device's wake-up list* (using selNodeAdd()) and checks to make sure the device is ready, this* routine ensures that the select() call does not pend.** RETURNS: N/A*/void selWakeup ( SEL_WAKEUP_NODE *pWakeupNode /* node to wake up */ ) { SEL_CONTEXT *pSelectContext; pSelectContext = ((WIND_TCB *)pWakeupNode->taskId)->pSelectContext; switch (pWakeupNode->type) { case SELREAD: FD_SET(pWakeupNode->fd, pSelectContext->pReadFds); break; case SELWRITE: FD_SET(pWakeupNode->fd, pSelectContext->pWriteFds); break; } semGive (&pSelectContext->wakeupSem); }/******************************************************************************** selWakeupAll - wake up all tasks in a select() wake-up list** This routine wakes up all tasks pended in select() that are waiting for* a device; it is called by a driver when the device becomes ready. The* <type> parameter specifies the task to be awakened, either reader tasks* (SELREAD) or writer tasks (SELWRITE).** RETURNS: N/A*/void selWakeupAll ( SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */ FAST SELECT_TYPE type /* readers (SELREAD) or writers (SELWRITE) */ ) { FAST SEL_WAKEUP_NODE *pWakeupNode; if (lstCount (&pWakeupList->wakeupList) == 0) return; if (intContext ()) { excJobAdd (selWakeupAll, (int)pWakeupList, (int)type, 0, 0, 0, 0); return; } semTake (&pWakeupList->listMutex, WAIT_FOREVER); for (pWakeupNode = (SEL_WAKEUP_NODE *) lstFirst (&pWakeupList->wakeupList); pWakeupNode != NULL; pWakeupNode = (SEL_WAKEUP_NODE *) lstNext ((NODE *) pWakeupNode)) { if (pWakeupNode->type == type) selWakeup (pWakeupNode); } semGive (&pWakeupList->listMutex); }/******************************************************************************** selNodeAdd - add a wake-up node to a select() wake-up list** This routine adds a wake-up node to a device's wake-up list. It is * typically called from a driver's FIOSELECT function.** RETURNS: OK, or ERROR if memory is insufficient.*/STATUS selNodeAdd ( SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */ SEL_WAKEUP_NODE *pWakeupNode /* node to add to list */ ) { SEL_WAKEUP_NODE *pCopyOfNode; BOOL dontFree; semTake (&pWakeupList->listMutex, WAIT_FOREVER); if (lstCount (&pWakeupList->wakeupList) == 0) { pCopyOfNode = &pWakeupList->firstNode; dontFree = TRUE; } else { pCopyOfNode = (SEL_WAKEUP_NODE *) malloc (sizeof (SEL_WAKEUP_NODE)); dontFree = FALSE; } if (pCopyOfNode == NULL) { semGive (&pWakeupList->listMutex); return (ERROR); } *pCopyOfNode = *pWakeupNode; pCopyOfNode->dontFree = dontFree; lstAdd (&pWakeupList->wakeupList, (NODE *) pCopyOfNode); semGive (&pWakeupList->listMutex); return (OK); }/******************************************************************************** selNodeDelete - find and delete a node from a select() wake-up list** This routine deletes a specified wake-up node from a specified wake-up* list. Typically, it is called by a driver's FIOUNSELECT function.** RETURNS: OK, or ERROR if the node is not found in the wake-up list.*/STATUS selNodeDelete ( SEL_WAKEUP_LIST *pWakeupList, /* list of tasks to wake up */ SEL_WAKEUP_NODE *pWakeupNode /* node to delete from list */ { FAST SEL_WAKEUP_NODE *pWorkNode; semTake (&pWakeupList->listMutex, WAIT_FOREVER); /* get exclusion */ for (pWorkNode = (SEL_WAKEUP_NODE *) lstFirst (&pWakeupList->wakeupList); pWorkNode != NULL; pWorkNode = (SEL_WAKEUP_NODE *) lstNext ((NODE *) pWorkNode)) { if ((pWorkNode->taskId == pWakeupNode->taskId) && (pWorkNode->type == pWakeupNode->type)) { lstDelete (&pWakeupList->wakeupList, (NODE *) pWorkNode); if (!(pWorkNode->dontFree)) free ((char *) pWorkNode); /* deallocate node */ semGive (&pWakeupList->listMutex); /* release exclusion */ return (OK); } } semGive (&pWakeupList->listMutex); /* release exclusion */ return (ERROR); }/******************************************************************************** selWakeupListInit - initialize a select() wake-up list** This routine should be called in a device's create routine to* initialize the SEL_WAKEUP_LIST structure.** RETURNS: N/A**/void selWakeupListInit ( SEL_WAKEUP_LIST *pWakeupList /* wake-up list to initialize */ ) { lstInit (&pWakeupList->wakeupList); semMInit (&pWakeupList->listMutex, mutexOptionsSelectLib); }/******************************************************************************** selWakeupListTerm - terminate a select() wake-up list** This routine should be called in a device's terminate routine to* terminate the SEL_WAKEUP_LIST structure.** RETURNS: N/A**/void selWakeupListTerm ( SEL_WAKEUP_LIST *pWakeupList /* wake-up list to terminate */ ) { semTerminate (&pWakeupList->listMutex); }/******************************************************************************** selWakeupListLen - get the number of nodes in a select() wake-up list** This routine returns the number of nodes in a specified SEL_WAKEUP_LIST.* It can be used by a driver to determine if any tasks are currently* pended in select() on this device, and whether these tasks need to be* activated with selWakeupAll().** RETURNS:* The number of nodes currently in a select() wake-up list, or ERROR.**/int selWakeupListLen ( SEL_WAKEUP_LIST *pWakeupList /* list of tasks to wake up */ ) { return (lstCount (&pWakeupList->wakeupList)); }/******************************************************************************** selWakeupType - get the type of a select() wake-up node** This routine returns the type of a specified SEL_WAKEUP_NODE.* It is typically used in a device's FIOSELECT function to determine* if the device is being selected for read or write operations.** RETURNS: SELREAD (read operation) or SELWRITE (write operation).**/SELECT_TYPE selWakeupType ( SEL_WAKEUP_NODE *pWakeupNode /* node to get type of */ ) { return (pWakeupNode->type); }/******************************************************************************** selTaskCreateHook - select task create hook** This routine creates a select context for the task. The select context * for the root task is not created by this routine. Instead, it is created * by the selectInit() routine.** The memory for the context is allocated from the system heap. The amount* of memory allocated for the context is enough to support fd_sets of size* maxFiles, instead of the compile time value of FD_SETSIZE.** This routine is installed as a create hook by selectInit.*/LOCAL STATUS selTaskCreateHook ( WIND_TCB *pNewTcb ) { SEL_CONTEXT *pSelectContext; int fdSetBytes; /* * Allocate sufficient memory from the heap to contain the select * context. This memory includes space for the various fd_sets to * handle file descriptors up to maxFiles, i.e. select() will not be * limited to FD_SETSIZE. */ fdSetBytes = sizeof (fd_mask) * howmany (maxFiles, NFDBITS); pSelectContext = (SEL_CONTEXT *) malloc (sizeof (SEL_CONTEXT) + 2 * fdSetBytes); if (pSelectContext == NULL) return (ERROR); /* assign various convenience fd_set pointers */ pSelectContext->pOrigReadFds = (fd_set *) ((int) pSelectContext + sizeof (SEL_CONTEXT)); pSelectContext->pOrigWriteFds = (fd_set *) ((int) pSelectContext->pOrigReadFds + fdSetBytes); pSelectContext->pendedOnSelect = FALSE; /* task is not pending */ /* initialize the task's wakeup binary semaphore */ if (semBInit (&pSelectContext->wakeupSem, SEM_Q_PRIORITY, SEM_EMPTY) != OK) { free ((char*) pSelectContext); return (ERROR); } /* initialization succeeded so set task's select context pointer */ pNewTcb->pSelectContext = pSelectContext; return (OK); }/******************************************************************************** selTaskDeleteHook - select task delete hook** If a task is deleted while it is pended in select, this delete hook* tells all the relevent devices to delete the wake-up node associated* with this task. This routine is installed as a delete hook by * selTaskDeleteHookAdd(). RPC adds a delete hook to close the client and* server handle sockets -- we insure that the select delete hook gets * called before the RPC delete hook (so that the socket device still exists)* by installing it AFTER RPC initialization (see usrConfig.c).*/LOCAL void selTaskDeleteHook ( WIND_TCB *pTcb ) { SEL_CONTEXT *pSelectContext = pTcb->pSelectContext; /* * A wakeup node is created on the deleting task's stack since * the work node on the stack of the task being deleting may * be inaccessible to the current task. */ SEL_WAKEUP_NODE wakeupNode; if (pSelectContext != NULL) { /* task pended in select()? */ if (pSelectContext->pendedOnSelect == TRUE) { wakeupNode.taskId = (int) pTcb; /* unregister all the read fd's */ wakeupNode.type = SELREAD; selDoIoctls (pSelectContext->pOrigReadFds, pSelectContext->width, FIOUNSELECT, &wakeupNode, FALSE); /* unregister all the write fd's */ wakeupNode.type = SELWRITE; selDoIoctls (pSelectContext->pOrigWriteFds, pSelectContext->width, FIOUNSELECT, &wakeupNode, FALSE); } semTerminate (&pSelectContext->wakeupSem); free ((char *) pSelectContext); } } /********************************************************************************* selTyAdd - tyLib FIOSELECT ioctl** This is located here to keep tyLib from dragging in selectLib.*/LOCAL void selTyAdd ( TY_DEV *pTyDev, int arg ) { selNodeAdd (&pTyDev->selWakeupList, (SEL_WAKEUP_NODE *) arg); if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELREAD) && (rngNBytes (pTyDev->rdBuf) > 0)) { selWakeup ((SEL_WAKEUP_NODE *) arg); } if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELWRITE) && rngFreeBytes (pTyDev->wrtBuf) > 0) { selWakeup ((SEL_WAKEUP_NODE *) arg); } }/********************************************************************************* selTyDelete - tyLib FIOUNSELECT ioctl** This is located here to keep tyLib from dragging in selectLib.*/LOCAL void selTyDelete ( TY_DEV *pTyDev, int arg ) { selNodeDelete (&pTyDev->selWakeupList, (SEL_WAKEUP_NODE *)arg); }/********************************************************************************* selPtyAdd - ptyLib FIOSELECT ioctl**/LOCAL void selPtyAdd ( PSEUDO_DEV *pPtyDev, int arg ) { selNodeAdd (&pPtyDev->masterSelWakeupList, (SEL_WAKEUP_NODE *) arg); if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELREAD) && rngNBytes (pPtyDev->tyDev.wrtBuf) > 0) /* reversed read criteria for master */ { selWakeup ((SEL_WAKEUP_NODE *) arg); } if ((selWakeupType ((SEL_WAKEUP_NODE *) arg) == SELWRITE) && rngFreeBytes (pPtyDev->tyDev.rdBuf) > 0 ) /* reversed write criteria for master */ { selWakeup ((SEL_WAKEUP_NODE *) arg); } }/********************************************************************************* selPtyDelete - ptyLib FIOUNSELECT ioctl** This is located here to keep ptyLib from dragging in selectLib.*/LOCAL void selPtyDelete ( PSEUDO_DEV *pPtyDev, int arg ) { selNodeDelete (&pPtyDev->masterSelWakeupList, (SEL_WAKEUP_NODE *)arg); }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -