📄 rvselect.c
字号:
/* Since Unix systems support only Read/Write events, we have to translate
the richer set of events we have */
translatedEvents = rvSelectToOS(selectEvents);
/* Fill in the pollfd element */
fdUpdate.fd = fd->fd;
fdUpdate.events = 0;
fdUpdate.revents = 0;
if (translatedEvents & RV_SELECT_READ)
fdUpdate.events |= POLLIN;
if (translatedEvents & RV_SELECT_WRITE)
fdUpdate.events |= POLLOUT;
/* Write the change to /dev/poll */
if (write(selectEngine->fdDevPoll, &fdUpdate, sizeof(fdUpdate)) == sizeof(fdUpdate))
{
fd->devpollEvents = fdUpdate.events; /* Know what we're waiting for */
RvLockGet(&selectEngine->lock);
/* We've got one more fd in /dev/poll */
selectEngine->maxFdInDevPoll++;
RvLockRelease(&selectEngine->lock);
}
else
{
RvSelectLogError((&rvSelectLogSource,
"RvSelectAdd: Can't add fd=%d with %d", fd->fd, selectEvents));
ret = RvSelectErrorCode(RV_ERROR_UNKNOWN);
}
}
}
#endif
if (ret == RV_OK)
{
/* Write down the events of this fd in its struct */
fd->callback = eventsCb;
fd->events = selectEvents;
#if (RV_OS_TYPE == RV_OS_TYPE_NUCLEUS)
RvSocketSetSelectEngine(*RvFdGetSocket(fd), (void*)selectEngine);
#endif
rvFdPreempt(selectEngine);
}
if ((ret != RV_OK) && allocatedBucketHash)
fdBucketHashRemove(selectEngine, fd);
RvSelectLogLeave((&rvSelectLogSource, "RvSelectAdd(fd=%d)=%d", fd->fd, ret));
return ret;
}
/********************************************************************************************
* RvSelectRemove
*
* purpose : Remove a file descriptor that is being checked by this engine
* input : selectEngine - Events engine of this fd
* fd - File descriptor to remove
* output : None
* return : RV_OK on success, other on failure
* notes : This function should only be called directly when the user wants the file
* descriptor to remain valid and active, but use it with a different events
* engine.
* Calling this function just before calling RvFdDestruct() on the same file
* descriptor will cause RvFdDestruct() to log an error message.
********************************************************************************************/
RVCOREAPI
RvStatus RVCALLCONV RvSelectRemove(
IN RvSelectEngine* selectEngine,
IN RvSelectFd* fd)
{
RvStatus status = RV_OK;
RvSelectLogEnter((&rvSelectLogSource, "RvSelectRemove(fd=%d)", fd->fd));
if (fd->events != (RvSelectEvents)0)
{
/* Remove the events from the bucket hash */
fd->events = (RvSelectEvents)0;
status = fdBucketHashRemove(selectEngine, fd);
}
#if (RV_SELECT_TYPE == RV_SELECT_WIN32_WSA)
if (status == RV_OK)
{
MSG msg;
/* Make sure the network sends no events on this fd */
if (WSAAsyncSelect(fd->fd, selectEngine->hNetEventsWnd, 0, 0) != 0)
status = RvSelectErrorCode(RV_ERROR_UNKNOWN);
if (GetCurrentThreadId() == selectEngine->threadId)
{
/* Post an ending message - when we reach it - we're done here */
PostMessage(selectEngine->hNetEventsWnd, FD_NET_LOOP_END, 0, 0);
/* Clear current message queue from this socket */
while (PeekMessage(&msg, selectEngine->hNetEventsWnd,
FD_NET_MESSAGE, FD_NET_LOOP_END, PM_REMOVE))
{
if (LOWORD(msg.message) == FD_NET_LOOP_END)
{
/* We reached the end of the queue - exit */
break;
}
/* Make sure that network events not related to this socket are being posted
back into the message queue */
if (msg.wParam != (WPARAM)fd->fd)
PostMessage(selectEngine->hNetEventsWnd, FD_NET_MESSAGE, msg.wParam, msg.lParam);
}
}
}
#elif (RV_SELECT_TYPE == RV_SELECT_WIN32_COMPLETION)
#elif (RV_SELECT_TYPE == RV_SELECT_SELECT)
if (status == RV_OK)
{
#if (RV_OS_TYPE != RV_OS_TYPE_WINCE) && defined(RV_RANGECHECK)
/* Windows CE doesn't really care that the socket's fd value is within
the range of FD_SETSIZE. This is because the fd_set struct is actually
defined more like poll - a list of fd's to select and not a bits buffer.
If we'll range check for WinCE we'll just get errors after several socket
constructions. */
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHANGE */
if (status == RV_OK)
{
RvLockGet(&selectEngine->lock);
/* Remove this client */
FD_CLR(fd->fd, &selectEngine->rdSet);
FD_CLR(fd->fd, &selectEngine->wrSet);
/* Update the maximum limit of select() if we have to */
if (fd->fd == selectEngine->maxFdInSelect)
{
RvSocket minFd = (fd->fd - 1);
while ((selectEngine->maxFdInSelect > 0) &&
(!FD_ISSET(minFd, &selectEngine->rdSet)) &&
(!FD_ISSET(minFd, &selectEngine->wrSet)))
{
minFd--;
selectEngine->maxFdInSelect--;
}
}
RvLockRelease(&selectEngine->lock);
}
}
#elif (RV_SELECT_TYPE == RV_SELECT_POLL)
if (status == RV_OK)
{
#ifdef RV_RANGECHECK
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHANGE */
if (status == RV_OK)
{
RvLockGet(&selectEngine->lock);
selectEngine->maxFdInPoll--; /* We have one less */
/* Remove this client from fdArray - we don't want holes in our array, so we'll
just move the last one to fill in the gap */
if (selectEngine->maxFdInPoll != fd->fdArrayIndex)
{
RvSelectFd* movedFd;
/* It's not the last - fill it in */
memcpy(selectEngine->fdArray + fd->fdArrayIndex,
selectEngine->fdArray + selectEngine->maxFdInPoll, sizeof(struct pollfd));
/* We'll also need to move the fd itself... */
movedFd = fdBucketHashFind(selectEngine, selectEngine->fdArray[fd->fdArrayIndex].fd);
if (movedFd != NULL)
{
movedFd->fdArrayIndex = fd->fdArrayIndex;
}
/* todo: handle errors */
}
RvLockRelease(&selectEngine->lock);
}
}
#elif (RV_SELECT_TYPE == RV_SELECT_DEVPOLL)
if (status == RV_OK)
{
struct pollfd fdRemove;
#ifdef RV_RANGECHECK
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHANGE */
if (status == RV_OK)
{
fdRemove.fd = fd->fd;
fdRemove.events = POLLREMOVE;
fdRemove.revents = 0;
/* Write the change to /dev/poll */
if (write(selectEngine->fdDevPoll, &fdRemove, sizeof(fdRemove)) == sizeof(fdRemove))
{
RvLockGet(&selectEngine->lock);
/* We've got one less fd in /dev/poll */
selectEngine->maxFdInDevPoll--;
RvLockRelease(&selectEngine->lock);
}
else
{
RvSelectLogError((&rvSelectLogSource,
"RvSelectRemove: Can't remove fd=%d", fd->fd));
status = RvSelectErrorCode(RV_ERROR_UNKNOWN);
}
}
}
#endif
if (status == RV_OK)
status = rvFdPreempt(selectEngine);
RvSelectLogLeave((&rvSelectLogSource, "RvSelectRemove(fd=%d)=%d", fd->fd, status));
return status;
}
/********************************************************************************************
* RvSelectUpdate
*
* purpose : Update the events of callback used for a given file descriptor
* input : selectEngine - Events engine of this fd
* fd - File descriptor to update
* selectEvents - Events to check
* eventsCb - Callback to use when these events occur
* output : None
* return : RV_OK on success, other on failure
********************************************************************************************/
RVCOREAPI
RvStatus RVCALLCONV RvSelectUpdate(
IN RvSelectEngine* selectEngine,
IN RvSelectFd* fd,
IN RvSelectEvents selectEvents,
IN RvSelectCb eventsCb)
{
RvStatus status = RV_OK;
RvBool anyChanges = RV_FALSE;
RvSelectLogEnter((&rvSelectLogSource,
"RvSelectUpdate(fd=%d,events=%s%s%s%s%s,cb=%p)", fd->fd,
fdGetEventStr((RvSelectEvents)(selectEvents & RvSelectRead)),
fdGetEventStr((RvSelectEvents)(selectEvents & RvSelectWrite)),
fdGetEventStr((RvSelectEvents)(selectEvents & RvSelectAccept)),
fdGetEventStr((RvSelectEvents)(selectEvents & RvSelectConnect)),
fdGetEventStr((RvSelectEvents)(selectEvents & RvSelectClose)),
eventsCb));
#if (RV_SELECT_TYPE == RV_SELECT_WIN32_WSA)
{
if (WSAAsyncSelect(fd->fd, selectEngine->hNetEventsWnd, FD_NET_MESSAGE, selectEvents) == 0)
anyChanges = RV_TRUE;
else
status = RvSelectErrorCode(RV_ERROR_UNKNOWN);
}
#elif (RV_SELECT_TYPE == RV_SELECT_WIN32_COMPLETION)
#elif (RV_SELECT_TYPE == RV_SELECT_SELECT)
{
RvSelectEvents translatedEvents;
#if (RV_OS_TYPE != RV_OS_TYPE_WINCE) && defined(RV_RANGECHECK)
/* Windows CE doesn't really care that the socket's fd value is within
the range of FD_SETSIZE. This is because the fd_set struct is actually
defined more like poll - a list of fd's to select and not a bits buffer.
If we'll range check for WinCE we'll just get errors after several socket
constructions. */
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHECK */
if (status == RV_OK)
{
/* Since Unix systems support only Read/Write events, we have to translate
the richer set of events we have */
translatedEvents = rvSelectToOS(selectEvents);
anyChanges = RV_TRUE; /* Always think we have changes - simplify matters */
RvLockGet(&selectEngine->lock);
if (translatedEvents & RV_SELECT_READ)
RV_FD_SET(fd->fd, &selectEngine->rdSet);
else
FD_CLR(fd->fd, &selectEngine->rdSet);
if (translatedEvents & RV_SELECT_WRITE)
RV_FD_SET(fd->fd, &selectEngine->wrSet);
else
FD_CLR(fd->fd, &selectEngine->wrSet);
RvLockRelease(&selectEngine->lock);
}
}
#elif (RV_SELECT_TYPE == RV_SELECT_POLL)
{
RvSelectEvents translatedEvents;
struct pollfd* pollFdElem;
short newEvents;
#ifdef RV_RANGECHECK
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHANGE */
if (status == RV_OK)
{
/* Find the entry to fill in */
pollFdElem = selectEngine->fdArray + fd->fdArrayIndex;
#ifdef RV_OTHERCHECK
/* Make sure we're updating the right fd */
if (pollFdElem->fd != fd->fd)
{
RvSelectLogExcep((&rvSelectLogSource,
"RvSelectUpdate: Updating fd=%d with fd=%d.", pollFdElem->fd, fd->fd));
status = RV_ERROR_BADPARAM;
}
#endif
/* Since Unix systems support only Read/Write events, we have to translate
the richer set of events we have */
translatedEvents = rvSelectToOS(selectEvents);
newEvents = 0;
if (translatedEvents & RV_SELECT_READ)
newEvents |= POLLIN;
if (translatedEvents & RV_SELECT_WRITE)
newEvents |= POLLOUT;
if (newEvents != pollFdElem->events)
{
/* Fill in the pollfd element - it's updated now */
pollFdElem->revents = 0;
pollFdElem->events = newEvents;
anyChanges = RV_TRUE;
}
}
}
#elif (RV_SELECT_TYPE == RV_SELECT_DEVPOLL)
if (status == RV_OK)
{
RvSelectEvents translatedEvents;
struct pollfd fdUpdate[2];
RvSize_t writeSize;
int updateIndex;
short newEvents;
#ifdef RV_RANGECHECK
if ((fd->fd < 0) || (fd->fd >= selectEngine->maxFd))
status = RvSelectErrorCode(RV_ERROR_OUTOFRANGE);
#endif /* RV_RANGECHANGE */
if (status == RV_OK)
{
/* Since Unix systems support only Read/Write events, we have to translate
the richer set of events we have */
translatedEvents = rvSelectToOS(selectEvents);
newEvents = 0;
if (translatedEvents & RV
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -