Ejemplo n.º 1
0
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 );

}