unsigned int WINAPI IocpManager::IoWorkerThread(LPVOID lpParam) { LThreadType = THREAD_IO_WORKER; LIoThreadId = reinterpret_cast<int>(lpParam); LTimer = new Timer; LLockOrderChecker = new LockOrderChecker(LIoThreadId); HANDLE hComletionPort = GIocpManager->GetComletionPort(); while (true) { /// 타이머 작업은 항상 돌리고 LTimer->DoTimerJob(); /// IOCP 작업 돌리기 DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ULONG_PTR completionKey = 0; int ret = GetQueuedCompletionStatus(hComletionPort, &dwTransferred, (PULONG_PTR)&completionKey, (LPOVERLAPPED*)&context, GQCS_TIMEOUT); ClientSession* theClient = context ? context->mSessionObject : nullptr ; if (ret == 0 || dwTransferred == 0) { int gle = GetLastError(); /// check time out first if (gle == WAIT_TIMEOUT) continue; if (context->mIoType == IO_RECV || context->mIoType == IO_SEND ) { CRASH_ASSERT(nullptr != theClient); /// In most cases in here: ERROR_NETNAME_DELETED(64) theClient->DisconnectRequest(DR_COMPLETION_ERROR); DeleteIoContext(context); continue; } } CRASH_ASSERT(nullptr != theClient); bool completionOk = false; switch (context->mIoType) { case IO_DISCONNECT: theClient->DisconnectCompletion(static_cast<OverlappedDisconnectContext*>(context)->mDisconnectReason); completionOk = true; break; case IO_ACCEPT: theClient->AcceptCompletion(); completionOk = true; break; case IO_RECV_ZERO: completionOk = PreReceiveCompletion(theClient, static_cast<OverlappedPreRecvContext*>(context), dwTransferred); break; case IO_SEND: completionOk = SendCompletion(theClient, static_cast<OverlappedSendContext*>(context), dwTransferred); break; case IO_RECV: completionOk = ReceiveCompletion(theClient, static_cast<OverlappedRecvContext*>(context), dwTransferred); break; default: printf_s("Unknown I/O Type: %d\n", context->mIoType); CRASH_ASSERT(false); break; } if ( !completionOk ) { /// connection closing theClient->DisconnectRequest(DR_IO_REQUEST_ERROR); } DeleteIoContext(context); } return 0; }
void IOThread::DoIocpJob() { DWORD dwTransferred = 0; OverlappedIOContext* context = nullptr; ULONG_PTR completionKey = 0; int ret = GetQueuedCompletionStatus( mCompletionPort, &dwTransferred, (PULONG_PTR)&completionKey, (LPOVERLAPPED*)&context, GQCS_TIMEOUT ); if ( completionKey == THREAD_QUIT_KEY ) { mIsContinue = false; return; } ClientSession* session = context ? context->mSessionObject : nullptr; if ( ret == 0 || dwTransferred == 0 ) { int gle = GetLastError(); /// check time out first if ( gle == WAIT_TIMEOUT && context == nullptr ) { return; } if ( context->mIoType == IO_RECV || context->mIoType == IO_SEND ) { CRASH_ASSERT( nullptr != session ); /// In most cases in here: ERROR_NETNAME_DELETED(64) session->DisconnectRequest( DR_COMPLETION_ERROR ); DeleteIoContext( context ); return; } } CRASH_ASSERT( nullptr != session ); bool completionOk = false; switch ( context->mIoType ) { case IO_CONNECT: session->ConnectCompletion(); completionOk = true; break; case IO_DISCONNECT: session->DisconnectCompletion( static_cast<OverlappedDisconnectContext*>( context )->mDisconnectReason ); completionOk = true; break; case IO_RECV_ZERO: completionOk = session->PostRecv(); break; case IO_SEND: session->SendCompletion( dwTransferred ); if ( context->mWsaBuf.len != dwTransferred ) printf_s( "Partial SendCompletion requested [%d], sent [%d]\n", context->mWsaBuf.len, dwTransferred ); else completionOk = true; break; case IO_RECV: session->RecvCompletion( dwTransferred ); // 일단 테스트용 에코! // session->EchoBack(); completionOk = session->PreRecv(); break; default: printf_s( "Unknown I/O Type: %d\n", context->mIoType ); CRASH_ASSERT( false ); break; } if ( !completionOk ) { /// connection closing session->DisconnectRequest( DR_IO_REQUEST_ERROR ); } DeleteIoContext( context ); }