IO完成端口

 https://github.com/rajkosto/deps-detours/tree/master/samples/syelog

学习IO完成端口,最好的例子是Detours中的模块syelog,它为了高效地接收多个来源的log,创建了IO完成端口以及线程池,线程池中的线程数目为当前processor数目的8倍。

BOOL CreateWorkers(HANDLE hCompletionPort)
{
    DWORD dwThread;
    HANDLE hThread;
    DWORD i;
    SYSTEM_INFO SystemInfo;

    GetSystemInfo(&SystemInfo);

    for (i = 0; i < 2 * SystemInfo.dwNumberOfProcessors; i++) {
        hThread = CreateThread(NULL, 0, WorkerThread, hCompletionPort, 0, &dwThread);
        if (!hThread) {
            MyErrExit("CreateThread WorkerThread");
            // Unreachable: return FALSE;
        }
        CloseHandle(hThread);
    }
    return TRUE;
}

  

然后创建pipe文件,并且将pipe文件与IO完成端口绑定到一起,当其他线程(进程)向该pipe文件写数据时,会通过异步方式写,

VOID SyelogExV(BOOL fTerminate, BYTE nSeverity, PCSTR pszMsgf, va_list args)
{
    SYELOG_MESSAGE Message;
    DWORD cbWritten = 0;

    Real_GetSystemTimeAsFileTime(&Message.ftOccurance);
    Message.fTerminate = fTerminate;
    Message.nFacility = s_nFacility;
    Message.nSeverity = nSeverity;
    Message.nProcessId = s_nProcessId;
    PCHAR pszBuf = Message.szMessage;
    PCHAR pszEnd = Message.szMessage + ARRAYSIZE(Message.szMessage) - 1;
    if (s_szIdent[0]) {
        pszBuf = do_str(pszBuf, pszEnd, s_szIdent);
    }
    *pszEnd = '\0';
    VSafePrintf(pszMsgf, args,
                pszBuf, (int)(Message.szMessage + sizeof(Message.szMessage) - 1 - pszBuf));

    pszEnd = Message.szMessage;
    for (; *pszEnd; pszEnd++) {
        // no internal contents.
    }

    // Insure that the message always ends with a '\n'
    //
    if (pszEnd > Message.szMessage) {
        if (pszEnd[-1] != '\n') {
            *pszEnd++ = '\n';
            *pszEnd++ = '\0';
        }
        else {
            *pszEnd++ = '\0';
        }
    }
    else {
        *pszEnd++ = '\n';
        *pszEnd++ = '\0';
    }
    Message.nBytes = (USHORT)(pszEnd - ((PCSTR)&Message));

    Real_EnterCriticalSection(&s_csPipe);

    if (syelogIsOpen(&Message.ftOccurance)) {
        if (!Real_WriteFile(s_hPipe, &Message, Message.nBytes, &cbWritten, NULL)) {
            s_nPipeError = GetLastError();
            if (s_nPipeError == ERROR_BAD_IMPERSONATION_LEVEL) {
                // Don't close the file just for a temporary impersonation level.
            }
            else {
                if (s_hPipe != INVALID_HANDLE_VALUE) {
                    Real_CloseHandle(s_hPipe);
                    s_hPipe = INVALID_HANDLE_VALUE;
                }
                if (syelogIsOpen(&Message.ftOccurance)) {
                    Real_WriteFile(s_hPipe, &Message, Message.nBytes, &cbWritten, NULL);
                }
            }
        }
    }

    Real_LeaveCriticalSection(&s_csPipe);
}

  

如果写操作完成,会使正在等待的线程池中的一个线程结束对GetQueuedCompletionStatus的等待

DWORD WINAPI WorkerThread(LPVOID pvVoid)
{
    PCLIENT pClient;
    BOOL b;
    LPOVERLAPPED lpo;
    DWORD nBytes;
    HANDLE hCompletionPort = (HANDLE)pvVoid;

    for (BOOL fKeepLooping = TRUE; fKeepLooping;) {
        pClient = NULL;
        lpo = NULL;
        nBytes = 0;
        b = GetQueuedCompletionStatus(hCompletionPort,
                                      &nBytes, (PULONG_PTR)&pClient, &lpo, INFINITE);

        if (!b || lpo == NULL) {
            fKeepLooping = FALSE;
            MyErrExit("GetQueuedCompletionState");
            break;
        }
        else if (!b) {
            if (pClient) {
                if (GetLastError() == ERROR_BROKEN_PIPE) {
                    LogMessageV(SYELOG_SEVERITY_INFORMATION, "Client closed pipe.");
                }
                else {
                    LogMessageV(SYELOG_SEVERITY_ERROR,
                                "GetQueuedCompletionStatus failed %d [%p]",
                                GetLastError(), pClient);
                }
                CloseConnection(pClient);
            }
            continue;
        }

        if (pClient->fAwaitingAccept) {
            InterlockedIncrement(&s_nActiveClients);
            pClient->fAwaitingAccept = FALSE;
            b = ReadFile(pClient->hPipe,
                         &pClient->Message,
                         sizeof(pClient->Message),
                         &nBytes,
                         pClient);
            if (!b) {
                if (GetLastError() != ERROR_IO_PENDING) {
                    LogMessageV(SYELOG_SEVERITY_ERROR,
                                "ReadFile failed %d.", GetLastError());
                    continue;
                }
            }

            CreatePipeConnection(hCompletionPort);
        }
        else {
            if (nBytes < offsetof(SYELOG_MESSAGE, szMessage)) {
                CloseConnection(pClient);
            }

            if (pClient->Message.fTerminate) {
                LogMessageV(SYELOG_SEVERITY_NOTICE,
                            "Client requested terminate on next connection close.");
                s_fExitAfterOne = TRUE;
            }

            LogMessage(&pClient->Message, nBytes);

            b = ReadFile(pClient->hPipe,
                         &pClient->Message,
                         sizeof(pClient->Message),
                         &nBytes,
                         pClient);
            if (!b && GetLastError() == ERROR_BROKEN_PIPE) {
                CloseConnection(pClient);
            }
        }
    }
    return 0;
}

并且将写的结果通过Overlapped结构体传递给该线程,从而向log文件中添加内容。

 

posted @ 2014-09-17 17:18  Daniel King  阅读(323)  评论(0编辑  收藏  举报