bool SocketLayer::AssociateSocketWithCompletionPortAndRead( SOCKET readSocket, unsigned int binaryAddress, unsigned short port, RakPeer *rakPeer ) { #ifdef __USE_IO_COMPLETION_PORTS assert( readSocket != INVALID_SOCKET ); ClientContextStruct* ccs = new ClientContextStruct; ccs->handle = ( HANDLE ) readSocket; ExtendedOverlappedStruct* eos = ExtendedOverlappedPool::Instance()->GetPointer(); memset( &( eos->overlapped ), 0, sizeof( OVERLAPPED ) ); eos->binaryAddress = binaryAddress; eos->port = port; eos->rakPeer = rakPeer; eos->length = MAXIMUM_MTU_SIZE; bool b = AsynchronousFileIO::Instance()->AssociateSocketWithCompletionPort( readSocket, ( DWORD ) ccs ); if ( !b ) { ExtendedOverlappedPool::Instance()->ReleasePointer( eos ); delete ccs; return false; } BOOL success = ReadAsynch( ( HANDLE ) readSocket, eos ); if ( success == FALSE ) return false; #endif return true; }
unsigned __stdcall ThreadPoolFunc( LPVOID arguments ) { DWORD dwIoSize; ClientContextStruct* lpClientContext; ExtendedOverlappedStruct* lpOverlapped; LPOVERLAPPED temp; BOOL bError; HANDLE *completionPort = ( HANDLE * ) arguments; AsynchronousFileIO::Instance()->threadCount++; while ( 1 ) { // Get a completed IO request. BOOL returnValue = GetQueuedCompletionStatus( completionPort, &dwIoSize, ( LPDWORD ) & lpClientContext, &temp, INFINITE ); lpOverlapped = ( ExtendedOverlappedStruct* ) temp; DWORD dwIOError = GetLastError(); if ( lpOverlapped == 0 ) break; // Cancelled thread if ( !returnValue && dwIOError != WAIT_TIMEOUT ) { if ( dwIOError != ERROR_OPERATION_ABORTED ) { // Print all but this very common error message #if defined(_WIN32) && defined(_DEBUG) LPVOID messageBuffer; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwIOError, MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), // Default language ( LPTSTR ) & messageBuffer, 0, NULL ); // something has gone wrong here... printf( "GetQueuedCompletionStatus failed:Error code - %d\n%s", dwIOError, messageBuffer ); //Free the buffer. LocalFree( messageBuffer ); #endif } HANDLE_ERROR: // Some kind of error. Erase the data for this call bError = true; // This socket is no longer used if ( lpOverlapped ) delete lpOverlapped; if ( lpClientContext ) delete lpClientContext; // If we are killing the threads, then we keep posting fake completion statuses until we get a fake one through the queue (i.e. lpOverlapped==0 as above) // This way we delete all the data from the real calls before exiting the thread if ( AsynchronousFileIO::Instance()->killThreads ) { PostQueuedCompletionStatus( completionPort, 0, 0, 0 ); } } else bError = false; if ( !bError ) { if ( returnValue && NULL != lpOverlapped && NULL != lpClientContext ) { if ( lpOverlapped->read == true ) { assert( dwIoSize > 0 ); ProcessNetworkPacket( lpOverlapped->binaryAddress, lpOverlapped->port, lpOverlapped->data, dwIoSize, lpOverlapped->rakPeer ); // Issue a new read so we always have one outstanding read per socket // Finished a read. Reuse the overlapped pointer bError = ReadAsynch( lpClientContext->handle, lpOverlapped ); if ( !bError ) goto HANDLE_ERROR; // Windows is super unreliable! } else { // AsynchronousFileIO::Instance()->Write(lpClientContext); // Finished a write ExtendedOverlappedPool::Instance()->ReleasePointer( lpOverlapped ); } } else assert( 0 ); } } AsynchronousFileIO::Instance()->threadCount--; return 0; }