/* 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; }
void redisLogRaw(int level, const char *msg) { const char *c = ".-*#"; DWORD dwBytesWritten; /* The complete message needs to be passed to WriteFile at once, to ensure * atomicity of log entries across processes. * So we format the complete message into a buffer first. * Any output that doesn't fit the size of this buffer will be truncated. */ char buf[REDIS_MAX_LOGMSG_LEN]; const char *completeMessage; DWORD completeMessageLength; int rawmode = (level & REDIS_LOG_RAW); level &= 0xff; /* clear flags */ if (level < verbosity) return; if (hLogFile == INVALID_HANDLE_VALUE) return; if (rawmode) { completeMessage = msg; completeMessageLength = (DWORD)strlen(msg); } else { int vlen, off = 0; time_t secs; unsigned int usecs; struct tm * now ; completeMessage = buf; secs = gettimeofdaysecs(&usecs); now = localtime(&secs); vlen = snprintf(buf + off, sizeof(buf) - off, "[%d] ", (int)_getpid()); assert(vlen >= 0); off += vlen; vlen = (int)strftime(buf + off, sizeof(buf) - off, "%d %b %H:%M:%S.", now); assert(vlen >= 0); off += vlen; vlen = snprintf(buf + off, sizeof(buf) - off, "%03d %c ", usecs / 1000, c[level]); assert(vlen >= 0); off += vlen; vlen = snprintf(buf + off, sizeof(buf) - off, "%s\n", msg); if (vlen >= 0 && (off + vlen < sizeof(buf))) { completeMessageLength = off + vlen; } else { /* The MS CRT implementation of vsnprintf/snprintf returns -1 if the formatted output doesn't fit the buffer, * in addition to when an encoding error occurs. Proceeding with a zero-terminated ellipsis at the end of the * buffer seems a better option than not logging this message at all. */ strncpy(buf + sizeof(buf)-sizeof(ellipsisWithNewLine), ellipsisWithNewLine, sizeof(ellipsisWithNewLine)); completeMessageLength = sizeof(buf)-1; } } WriteFile(hLogFile, completeMessage, completeMessageLength, &dwBytesWritten, NULL); /* FlushFileBuffers() ensures that all data and metadata is written to disk, but it's effect * on performance is severe. */ #ifdef FLUSH_LOG_WRITES FlushFileBuffers(hLogFile); #endif if (IsEventLogEnabled() == 1) { WriteEventLog(msg); } }