int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { if (fd >= eventLoop->setsize) { errno = ERANGE; return AE_ERR; } aeFileEvent *fe = &eventLoop->events[fd]; if (aeApiAddEvent(eventLoop, fd, mask) == -1) return AE_ERR; fe->mask |= mask; if (mask & AE_READABLE) fe->rfileProc = proc; if (mask & AE_WRITABLE) fe->wfileProc = proc; fe->clientData = clientData; if (fd > eventLoop->maxfd) eventLoop->maxfd = fd; return AE_OK; }
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { aeFileEvent *fe = NULL; if(fd >= eventLoop->setsize){ return (-1); } fe = &eventLoop->events[fd]; if(aeApiAddEvent(eventLoop, fd, mask)==-1){ return (-1); } fe->mask |= mask; if(mask & AE_READABLE) fe->rfileProc = proc; if(mask & AE_WRITABLE) fe->wfileProc = proc; fe->clientData = clientData; if(fd > eventLoop->maxfd) eventLoop->maxfd = fd; return 0; }
/* * 根据 mask 参数的值,监听 fd 文件的状态, * 当 fd 可用时,执行 proc 函数 */ int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { if (fd >= eventLoop->setsize) return AE_ERR; aeFileEvent *fe = &eventLoop->events[fd]; // 监听指定 fd if (aeApiAddEvent(eventLoop, fd, mask) == -1) return AE_ERR; // 设置文件事件类型 fe->mask |= mask; if (mask & AE_READABLE) fe->rfileProc = proc; if (mask & AE_WRITABLE) fe->wfileProc = proc; fe->clientData = clientData; // 如果有需要,更新事件处理器的最大 fd if (fd > eventLoop->maxfd) eventLoop->maxfd = fd; return AE_OK; }
/*** * 创建IO事件并注册IO事件 * @eventLoop[IN]: 新建事件要添加到的事件循环处理器 * @fd[IN]: IO事件对应的文件描述符 * @mask[IN]: IO事件关注的事件类型, AE_READABLE与AE_WRITEABLE的任意结合 * @proc[IN]: IO事件就绪处理函数, 这里读和写事件公用一个处理函数, 可以根据处理函数传入的mask区分 * @clientData[IN]: 用户私有数据, 事件处理函数调用时传回 * @return: 成功返回AE_OK, 失败返回AE_ERR */ int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData) { /* 如果要注册的IO事件对应的文件描述符不小于setsize, 则返回失败 */ if (fd >= eventLoop->setsize) { errno = ERANGE; return AE_ERR; } /* 根据fd定位到已注册IO事件数组中相应的event元素 */ aeFileEvent *fe = &eventLoop->events[fd]; /* 将fd注册到操作系统特定IO复用设施中 */ if (aeApiAddEvent(eventLoop, fd, mask) == -1) return AE_ERR; /* 以下部分填充fd在数组中对应的event结构体 */ /* 填充mask标记 */ fe->mask |= mask; /* 如果关注读事件, 则设置读就绪处理函数 */ if (mask & AE_READABLE) fe->rfileProc = proc; /* 如果关注些事件, 则设置写就绪处理函数 */ if (mask & AE_WRITABLE) fe->wfileProc = proc; /* 记录用户私有数据 */ fe->clientData = clientData; /* 如果新注册的IO事件的fd值大于eventLoop中的maxfd, 则以fd更新maxfd */ if (fd > eventLoop->maxfd) eventLoop->maxfd = fd; return AE_OK; }
/* return array of sockets that are ready for read or write depending on the mask for each socket */ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { aeApiState *state = (aeApiState *)eventLoop->apidata; aeSockState *sockstate; ULONG j; int numevents = 0; ULONG numComplete = 0; int rc; int mswait = (tvp == NULL) ? 100 : (tvp->tv_sec * 1000) + (tvp->tv_usec / 1000); if (pGetQueuedCompletionStatusEx != NULL) { /* first get an array of completion notifications */ rc = pGetQueuedCompletionStatusEx(state->iocp, state->entries, MAX_COMPLETE_PER_POLL, &numComplete, mswait, FALSE); } else { /* need to get one at a time. Use first array element */ rc = GetQueuedCompletionStatus(state->iocp, &state->entries[0].dwNumberOfBytesTransferred, &state->entries[0].lpCompletionKey, &state->entries[0].lpOverlapped, mswait); if (!rc && state->entries[0].lpOverlapped == NULL) { // timeout. Return. return 0; } else { // check if more completions are ready int lrc = 1; rc = 1; numComplete = 1; while (numComplete < MAX_COMPLETE_PER_POLL) { lrc = GetQueuedCompletionStatus(state->iocp, &state->entries[numComplete].dwNumberOfBytesTransferred, &state->entries[numComplete].lpCompletionKey, &state->entries[numComplete].lpOverlapped, 0); if (lrc) { numComplete++; } else { if (state->entries[numComplete].lpOverlapped == NULL) break; } } } } if (rc && numComplete > 0) { LPOVERLAPPED_ENTRY entry = state->entries; for (j = 0; j < numComplete && numevents < state->setsize; j++, entry++) { /* the competion key is the socket */ int rfd = (int)entry->lpCompletionKey; sockstate = aeGetExistingSockState(state, rfd); if (sockstate != NULL) { if ((sockstate->masks & LISTEN_SOCK) && entry->lpOverlapped != NULL) { /* need to set event for listening */ aacceptreq *areq = (aacceptreq *)entry->lpOverlapped; areq->next = sockstate->reqs; sockstate->reqs = areq; sockstate->masks &= ~ACCEPT_PENDING; if (sockstate->masks & AE_READABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_READABLE; numevents++; } } else if (sockstate->masks & CONNECT_PENDING) { /* check if connect complete */ if (entry->lpOverlapped == &sockstate->ov_read) { sockstate->masks &= ~CONNECT_PENDING; /* enable read and write events for this connection */ aeApiAddEvent(eventLoop, rfd, sockstate->masks); } } else { int matched = 0; /* check if event is read complete (may be 0 length read) */ if (entry->lpOverlapped == &sockstate->ov_read) { matched = 1; sockstate->masks &= ~READ_QUEUED; if (sockstate->masks & AE_READABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_READABLE; numevents++; } } else if (sockstate->wreqs > 0 && entry->lpOverlapped != NULL) { /* should be write complete. Get results */ asendreq *areq = (asendreq *)entry->lpOverlapped; matched = removeMatchFromList(&sockstate->wreqlist, areq); if (matched) { /* call write complete callback so buffers can be freed */ if (areq->proc != NULL) { DWORD written = 0; DWORD flags; WSAGetOverlappedResult(rfd, &areq->ov, &written, FALSE, &flags); areq->proc(areq->eventLoop, rfd, &areq->req, (int)written); } sockstate->wreqs--; zfree(areq); /* if no active write requests, set ready to write */ if (sockstate->wreqs == 0 && sockstate->masks & AE_WRITABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_WRITABLE; numevents++; } } } if (matched == 0) { /* redisLog */printf("Sec:%lld Unknown complete (closed) on %d\n", gettimeofdaysecs(NULL), rfd); sockstate = NULL; } } } else { // no match for active connection. // Try the closing list. list *socklist = &(state->closing); listNode *node; node = listFirst(socklist); while (node != NULL) { sockstate = (aeSockState *)listNodeValue(node); if (sockstate->fd == rfd) { if (sockstate->masks & CONNECT_PENDING) { /* check if connect complete */ if (entry->lpOverlapped == &sockstate->ov_read) { sockstate->masks &= ~CONNECT_PENDING; } } else if (entry->lpOverlapped == &sockstate->ov_read) { // read complete sockstate->masks &= ~READ_QUEUED; } else { // check pending writes asendreq *areq = (asendreq *)entry->lpOverlapped; if (removeMatchFromList(&sockstate->wreqlist, areq)) { sockstate->wreqs--; zfree(areq); } } if (sockstate->wreqs == 0 && (sockstate->masks & (CONNECT_PENDING | READ_QUEUED | SOCKET_ATTACHED)) == 0) { if ((sockstate->masks & CLOSE_PENDING) != 0) { close(rfd); sockstate->masks &= ~(CLOSE_PENDING); } // safe to delete sockstate aeDelSockState(state, sockstate); } break; } node = listNextNode(node); } } } } return numevents; }
static int aeApiUpdateEvent(EventLoop *eventLoop, int fd, int mask) { return aeApiAddEvent(eventLoop, fd, mask); }
/* Return array of sockets that are ready for read or write * depending on the mask for each socket */ static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { aeApiState *state = (aeApiState *) eventLoop->apidata; iocpSockState *sockstate; ULONG j; int numevents = 0; ULONG numComplete = 0; BOOL rc; int mswait = (tvp == NULL) ? 100 : (tvp->tv_sec * 1000) + (tvp->tv_usec / 1000); if (pGetQueuedCompletionStatusEx != NULL) { // First get an array of completion notifications rc = pGetQueuedCompletionStatusEx(state->iocp, state->entries, MAX_COMPLETE_PER_POLL, &numComplete, mswait, FALSE); } else { // Need to get one at a time. Use first array element rc = GetQueuedCompletionStatus(state->iocp, &state->entries[0].dwNumberOfBytesTransferred, &state->entries[0].lpCompletionKey, &state->entries[0].lpOverlapped, mswait); if (!rc && state->entries[0].lpOverlapped == NULL) { // Timeout. Return. return 0; } else { // Check if more completions are ready BOOL lrc = TRUE; rc = TRUE; numComplete = 1; while (numComplete < MAX_COMPLETE_PER_POLL) { lrc = GetQueuedCompletionStatus(state->iocp, &state->entries[numComplete].dwNumberOfBytesTransferred, &state->entries[numComplete].lpCompletionKey, &state->entries[numComplete].lpOverlapped, 0); if (lrc) { numComplete++; } else { if (state->entries[numComplete].lpOverlapped == NULL) break; } } } } if (rc && numComplete > 0) { LPOVERLAPPED_ENTRY entry = state->entries; for (j = 0; j < numComplete && numevents < state->setsize; j++, entry++) { // The competion key is the rfd identifying the socket int rfd = (int) entry->lpCompletionKey; sockstate = WSIOCP_GetExistingSocketState(rfd); if (sockstate == NULL) { continue; } if ((sockstate->masks & CLOSE_PENDING) == FALSE) { if ((sockstate->masks & LISTEN_SOCK) && entry->lpOverlapped != NULL) { // Need to set event for listening aacceptreq *areq = (aacceptreq *) entry->lpOverlapped; areq->next = sockstate->reqs; sockstate->reqs = areq; sockstate->masks &= ~ACCEPT_PENDING; if (sockstate->masks & AE_READABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_READABLE; numevents++; } } else if (sockstate->masks & CONNECT_PENDING) { // Check if connect complete if (entry->lpOverlapped == &sockstate->ov_read) { sockstate->masks &= ~CONNECT_PENDING; // Enable read and write events for this connection aeApiAddEvent(eventLoop, rfd, sockstate->masks); } } else { BOOL matched = FALSE; // Check if event is read complete (may be 0 length read) if (entry->lpOverlapped == &sockstate->ov_read) { matched = TRUE; sockstate->masks &= ~READ_QUEUED; if (sockstate->masks & AE_READABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_READABLE; numevents++; } } else if (sockstate->wreqs > 0 && entry->lpOverlapped != NULL) { // Should be write complete. Get results asendreq *areq = (asendreq *) entry->lpOverlapped; matched = removeMatchFromList(&sockstate->wreqlist, areq); if (matched == TRUE) { // Call write complete callback so buffers can be freed if (areq->proc != NULL) { DWORD written = 0; DWORD flags; FDAPI_WSAGetOverlappedResult(rfd, &areq->ov, &written, FALSE, &flags); areq->proc(areq->eventLoop, rfd, &areq->req, (int) written); } sockstate->wreqs--; FreeMemoryNoCOW(areq); // If no active write requests, set ready to write if (sockstate->wreqs == 0 && sockstate->masks & AE_WRITABLE) { eventLoop->fired[numevents].fd = rfd; eventLoop->fired[numevents].mask = AE_WRITABLE; numevents++; } } } if (matched == 0 && sockstate->unknownComplete == 0) { sockstate->unknownComplete = 1; close(rfd); } } } else { if (sockstate->masks & CONNECT_PENDING) { // Check if connect complete if (entry->lpOverlapped == &sockstate->ov_read) { sockstate->masks &= ~CONNECT_PENDING; } } else if (entry->lpOverlapped == &sockstate->ov_read) { // Read complete sockstate->masks &= ~READ_QUEUED; } else { // Check pending writes asendreq *areq = (asendreq *) entry->lpOverlapped; if (removeMatchFromList(&sockstate->wreqlist, areq)) { sockstate->wreqs--; FreeMemoryNoCOW(areq); } } if (sockstate->wreqs == 0 && (sockstate->masks & (CONNECT_PENDING | READ_QUEUED | SOCKET_ATTACHED)) == 0) { sockstate->masks &= ~(CLOSE_PENDING); if (WSIOCP_CloseSocketState(sockstate)) { FDAPI_ClearSocketInfo(rfd); } } } } } return numevents; }