Exemplo n.º 1
0
/* 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;
}
Exemplo n.º 2
0
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);
    }
}