/********************************************************************created:2003/02/14file base:IOBufferfile ext:hauthor:liupengpurpose:Header file for CIOBuffer class*********************************************************************/#ifndef __INCLUDE_IOBUFFER_H__#define __INCLUDE_IOBUFFER_H__#if defined (_MSC_VER) && (_MSC_VER >= 1020)#pragma once#endif#ifndef _WINDOWS_#define WIN32_LEAN_AND_MEAN#include <windows.h>#undef WIN32_LEAN_AND_MEAN#endif/* * Identifier was truncated to '255' characters * in the debug information */#pragma warning(disable : 4786) #include <winsock2.h>#include "CriticalSection.h" #include "tstring.h"#include "NodeList.h"#include "OpaqueUserData.h"#include "Macro.h"#include <map>/* * Nonstandard extension used : zero-sized array in struct/union */#pragma warning(disable: 4200)/* * namespace OnlineGameLib::Win32 */namespace OnlineGameLib {namespace Win32 {/* * CIOBuffer */class CIOBuffer : public OVERLAPPED, public CNodeList::Node, public COpaqueUserData{public:class Allocator;friend class Allocator;class InOrderBufferList;WSABUF *GetWSABUF() const { return const_cast< WSABUF * >( &m_wsabuf ); };size_t GetUsed() const { return m_used; };size_t GetSize() const { return m_size; };const BYTE *GetBuffer() const { return m_buffer_ptr; };void SetupZeroByteRead();void SetupRead();void SetupWrite();void AddData( const char * const pData, size_t dataLength );void AddData( const BYTE * const pData, size_t dataLength );void AddData( BYTE data );void Use( size_t dataUsed ) { m_used += dataUsed; };CIOBuffer *SplitBuffer( size_t bytesToRemove );void RemoveBuffer( size_t bytesToRemove );CIOBuffer *AllocateNewBuffer() const;void ConsumeAndRemove( size_t bytesToRemove );void Empty();void AddRef() { ::InterlockedIncrement( &m_ref ); };void Release();size_t GetOperation() const { return m_operation; };void SetOperation( size_t operation ) { m_operation = operation; };size_t GetSequenceNumber() const { return m_sequenceNumber; };void SetSequenceNumber( size_t sequenceNumber ) { m_sequenceNumber = sequenceNumber; };private:size_t m_operation;size_t m_sequenceNumber;WSABUF m_wsabuf;Allocator &m_allocator;long m_ref;const size_t m_size;size_t m_used;/* * Start of the actual buffer, must remain the last * data member in the class. */BYTE *m_buffer_ptr;// four bytes aligned//BYTE m_buffer_base_addr[0];private:static void *operator new( size_t objSize, size_t bufferSize );static void operator delete( void *pObj, size_t bufferSize );CIOBuffer( Allocator &m_allocator, size_t size );~CIOBuffer();/* * No copies do not implement */CIOBuffer( const CIOBuffer &rhs );CIOBuffer &operator=( const CIOBuffer &rhs );};/* * CIOBuffer::Allocator */class CIOBuffer::Allocator{public: friend class CIOBuffer; explicit Allocator( size_t bufferSize, size_t maxFreeBuffers ); virtual ~Allocator(); CIOBuffer *Allocate(); size_t GetBufferSize() const { return m_bufferSize; };protected: void Flush();private: void Release( CIOBuffer *pBuffer ); virtual void OnBufferCreated() {} virtual void OnBufferAllocated() {} virtual void OnBufferReleased() {} void DestroyBuffer( CIOBuffer *pBuffer ); const size_t m_bufferSize; typedef TNodeList< CIOBuffer > BufferList; BufferList m_freeList; BufferList m_activeList; const size_t m_maxFreeBuffers; CCriticalSection m_criticalSection; /* * No copies do not implement */ Allocator( const Allocator &rhs ); Allocator &operator=( const Allocator &rhs );};/* * CIOBuffer::InOrderBufferList */class CIOBuffer::InOrderBufferList{public: explicit InOrderBufferList( CCriticalSection &lock ); void AddBuffer( CIOBuffer *pBuffer ); void ProcessBuffer(); CIOBuffer *ProcessAndGetNext(); CIOBuffer *GetNext(); CIOBuffer *GetNext( CIOBuffer *pBuffer ); void Reset(); bool Empty() const { return m_list.empty(); };private: size_t m_next; typedef std::map< size_t, CIOBuffer * > BufferSequence; BufferSequence m_list; CCriticalSection &m_criticalSection;};inline void CIOBuffer::ConsumeAndRemove( size_t bytesToRemove ){m_used -= bytesToRemove;memmove( m_buffer_ptr, m_buffer_ptr + bytesToRemove, m_used );}inline void CIOBuffer::SetupZeroByteRead(){m_wsabuf.buf = reinterpret_cast< char * >( m_buffer_ptr );m_wsabuf.len = 0; }inline void CIOBuffer::SetupRead(){if ( m_used == 0 ){m_wsabuf.buf = reinterpret_cast< char * >( m_buffer_ptr );m_wsabuf.len = m_size; }else{m_wsabuf.buf = reinterpret_cast< char * >( m_buffer_ptr ) + m_used;m_wsabuf.len = m_size - m_used; }}inline void CIOBuffer::SetupWrite(){m_wsabuf.buf = reinterpret_cast< char * >( m_buffer_ptr );m_wsabuf.len = m_used;m_used = 0;}} // End of namespace OnlineGameLib} // End of namespace Win32#endif //__INCLUDE_IOBUFFER_H__
#include "stdafx.h"#include "KWin32.h"#include "IOBuffer.h"#include "Exception.h"#include "Utils.h"/* * namespace OnlineGameLib::Win32 */namespace OnlineGameLib {namespace Win32 {CIOBuffer::CIOBuffer( Allocator &allocator, size_t size ): m_operation( 0 ) , m_sequenceNumber( 0 ) , m_allocator( allocator ) , m_ref( 1 ) , m_size( size ) , m_used( 0 ){//( ( BYTE * )( ( DWORD )( pMemory + 3 ) & ( ~3 ) ) )m_buffer_ptr = ::new BYTE[ size ];memset( this, 0, sizeof( OVERLAPPED ) );Empty();}CIOBuffer::~CIOBuffer(){ if (m_buffer_ptr) { ::delete []m_buffer_ptr; m_buffer_ptr = NULL; }}void CIOBuffer::Empty(){m_wsabuf.buf = reinterpret_cast< char * >( m_buffer_ptr );m_wsabuf.len = m_size;m_used = 0;}void *CIOBuffer::operator new( size_t objectSize, size_t /* bufferSize */ ){/* * ASSERT( sizeof( DWORD ) == 4 ); * * For four bytes aligned base on win32 system */void *pMem = ::new char[ objectSize ]; // + bufferSize + 4 ];return pMem;}void CIOBuffer::operator delete( void *pObject, size_t /* bufferSize*/ ){ if (pObject) { ::delete [](char *)pObject; pObject = NULL; }}CIOBuffer *CIOBuffer::SplitBuffer( size_t bytesToRemove ){CIOBuffer *pNewBuffer = m_allocator.Allocate();pNewBuffer->AddData( m_buffer_ptr, bytesToRemove );m_used -= bytesToRemove;memmove( m_buffer_ptr, m_buffer_ptr + bytesToRemove, m_used );return pNewBuffer;}VOID CIOBuffer::RemoveBuffer( size_t bytesToRemove ){if ( m_used < bytesToRemove )return;m_used -= bytesToRemove;memmove( m_buffer_ptr, m_buffer_ptr + bytesToRemove, m_used );}CIOBuffer *CIOBuffer::AllocateNewBuffer() const{return m_allocator.Allocate();}void CIOBuffer::AddData( const char * const pData, size_t dataLength ){if (dataLength > m_size - m_used){DEBUG_ONLY( Message( "CIOBuffer::AddData - Not enough space in buffer!" ) );throw CException( _T("CIOBuffer::AddData"), _T("Not enough space in buffer") );}memcpy( m_buffer_ptr + m_used, pData, dataLength );m_used += dataLength;}void CIOBuffer::AddData( const BYTE * const pData, size_t dataLength ){AddData( reinterpret_cast< const char * >( pData ), dataLength );}void CIOBuffer::AddData( BYTE data ){AddData( &data, 1 );}void CIOBuffer::Release(){if (m_ref == 0){/* * Error! double release */throw CException( _T("CIOBuffer::Release()"), _T("m_ref is already zero") );}if ( 0 == ::InterlockedDecrement( &m_ref ) ){m_sequenceNumber = 0;m_operation = 0;m_used = 0;m_allocator.Release( this );}}/* * CIOBuffer::Allocator */CIOBuffer::Allocator::Allocator( size_t bufferSize, size_t maxFreeBuffers ) : m_bufferSize( bufferSize ), m_maxFreeBuffers( maxFreeBuffers ){}CIOBuffer::Allocator::~Allocator(){try{Flush();}catch(...){TRACE( "CIOBuffer::Allocator::~Allocator exception!" );}}CIOBuffer *CIOBuffer::Allocator::Allocate(){CCriticalSection::Owner lock( m_criticalSection );CIOBuffer *pBuffer = 0;if ( !m_freeList.Empty() ){pBuffer = m_freeList.PopNode();pBuffer->AddRef();}else{pBuffer = new( m_bufferSize )CIOBuffer( *this, m_bufferSize );if ( !pBuffer ){throw CException( _T("CIOBuffer::Allocator::Allocate()"), _T("Out of memory") );}OnBufferCreated();}m_activeList.PushNode( pBuffer );OnBufferAllocated();return pBuffer;}void CIOBuffer::Allocator::Release( CIOBuffer *pBuffer ){if ( !pBuffer ){throw CException( _T("CIOBuffer::Allocator::Release()"), _T("pBuffer is null") );}CCriticalSection::Owner lock( m_criticalSection );OnBufferReleased();/* * unlink from the in use list */pBuffer->RemoveFromList();if ( m_maxFreeBuffers == 0 || m_freeList.Count() < m_maxFreeBuffers ){pBuffer->Empty(); /* * add to the free list */m_freeList.PushNode( pBuffer );}else{DestroyBuffer( pBuffer );}}void CIOBuffer::Allocator::DestroyBuffer( CIOBuffer *pBuffer ){SAFE_DELETE( pBuffer );}void CIOBuffer::Allocator::Flush(){CCriticalSection::Owner lock( m_criticalSection );while ( !m_activeList.Empty() ){OnBufferReleased();DestroyBuffer( m_activeList.PopNode() );}while ( !m_freeList.Empty() ){DestroyBuffer( m_freeList.PopNode() );}}/* * CIOBuffer::InOrderBufferList */CIOBuffer::InOrderBufferList::InOrderBufferList(CCriticalSection &criticalSection): m_next(0),m_criticalSection( criticalSection ){}void CIOBuffer::InOrderBufferList::AddBuffer( CIOBuffer *pBuffer ){CCriticalSection::Owner lock( m_criticalSection );std::pair< BufferSequence::iterator, bool > result = m_list.insert( BufferSequence::value_type( pBuffer->GetSequenceNumber(), pBuffer ) );if ( !result.second ){DEBUG_ONLY( Output( _T("UNEXPECTED! element already in map!") ) );}}CIOBuffer *CIOBuffer::InOrderBufferList::ProcessAndGetNext(){CCriticalSection::Owner lock( m_criticalSection );m_next ++;CIOBuffer *pNext = 0;BufferSequence::iterator it;it = m_list.begin();if ( it != m_list.end() ){if ( it->first == m_next ){pNext = it->second;m_list.erase( it );}else{DEBUG_ONLY( Output( ToString( this ) +_T(" Got buffer : ") + ToString( it->first ) +_T("Want buffer : ") +ToString( m_next ) ) );}}return pNext;}CIOBuffer *CIOBuffer::InOrderBufferList::GetNext(){CCriticalSection::Owner lock( m_criticalSection );CIOBuffer *pNext = 0;BufferSequence::iterator it;it = m_list.begin();if ( it != m_list.end() ){if ( it->first == m_next ){pNext = it->second;m_list.erase(it);}else{DEBUG_ONLY( Output( ToString( this ) + _T(" Got buffer : ") + ToString( it->first ) + _T("Want buffer : ") + ToString( m_next ) ) );}}return pNext;}CIOBuffer *CIOBuffer::InOrderBufferList::GetNext( CIOBuffer *pBuffer ){CCriticalSection::Owner lock( m_criticalSection );if ( m_next == pBuffer->GetSequenceNumber() ){return pBuffer;}std::pair< BufferSequence::iterator, bool > result = m_list.insert( BufferSequence::value_type( pBuffer->GetSequenceNumber(), pBuffer ) );if ( !result.second ){DEBUG_ONLY( Output( _T("UNEXPECTED! element already in map!") ) );}CIOBuffer *pNext = 0;BufferSequence::iterator it;it = m_list.begin();if (it != m_list.end()) {if (it->first == m_next){pNext = it->second;m_list.erase(it);}else{DEBUG_ONLY( Output( ToString( this ) +_T(" Got buffer : ") + ToString( it->first ) + _T("Want buffer : ") + ToString( m_next ) ) );}}return pNext;}void CIOBuffer::InOrderBufferList::ProcessBuffer(){CCriticalSection::Owner lock( m_criticalSection );DEBUG_ONLY( Output( ToString( this ) +_T(" Processed : ") + ToString( m_next ) ) );m_next ++;}void CIOBuffer::InOrderBufferList::Reset(){m_next = 0;if ( !m_list.empty() ){DEBUG_ONLY( Output( _T("List not empty when reset !") ) );}}} // End of namespace Win32} // End of namespace OnlineGameLib
/********************************************************************created:2003/02/14file base:IOCompletionPortfile ext:hauthor:liupengpurpose:Header file for CIOCompletionPort routines*********************************************************************/#ifndef __INCLUDE_IOCOMPLETIONPORT_H__#define __INCLUDE_IOCOMPLETIONPORT_H__#ifndef _WINDOWS_#define WIN32_LEAN_AND_MEAN#include <windows.h>#undef WIN32_LEAN_AND_MEAN#endif#include "Macro.h"/* * namespace OnlineGameLib::Win32 */namespace OnlineGameLib {namespace Win32 {/* * CIOCompletionPort */class CIOCompletionPort{public: explicit CIOCompletionPort( size_t maxConcurrency );~CIOCompletionPort();void AssociateDevice( HANDLE hDevice, ULONG_PTR completionKey );void PostStatus( ULONG_PTR completionKey, DWORD dwNumBytes = 0, OVERLAPPED *pOverlapped = 0 );DWORD GetStatus( ULONG_PTR *pCompletionKey, PDWORD pdwNumBytes,OVERLAPPED **ppOverlapped );DWORD GetStatus( ULONG_PTR *pCompletionKey, PDWORD pdwNumBytes,OVERLAPPED **ppOverlapped, DWORD dwMilliseconds );private: HANDLE m_iocp;/* * No copies do not implement */CIOCompletionPort( const CIOCompletionPort &rhs );CIOCompletionPort &operator=( const CIOCompletionPort &rhs );};} // End of namespace OnlineGameLib} // End of namespace Win32#endif //__INCLUDE_IOCOMPLETIONPORT_H__
#include "stdafx.h"#include "IOCompletionPort.h"#include "Win32Exception.h"#include "Macro.h"/* * namespace OnlineGameLib::Win32 */namespace OnlineGameLib {namespace Win32 {CIOCompletionPort::CIOCompletionPort( size_t maxConcurrency ): m_iocp( ::CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, maxConcurrency ) ){if ( m_iocp == 0 ){throw CWin32Exception( _T("CIOCompletionPort::CIOCompletionPort() - CreateIoCompletionPort"), ::GetLastError() );}}CIOCompletionPort::~CIOCompletionPort() {SAFE_CLOSEHANDLE( m_iocp );}void CIOCompletionPort::AssociateDevice( HANDLE hDevice, ULONG_PTR completionKey ){if ( m_iocp != ::CreateIoCompletionPort( hDevice,m_iocp, completionKey, 0 ) ){throw CWin32Exception( _T("CIOCompletionPort::AssociateDevice() - CreateIoCompletionPort"), ::GetLastError() );}}void CIOCompletionPort::PostStatus( ULONG_PTR completionKey, DWORD dwNumBytes /* = 0 */, OVERLAPPED *pOverlapped /* = 0 */) {if ( 0 == ::PostQueuedCompletionStatus( m_iocp, dwNumBytes, completionKey, pOverlapped ) ){throw CWin32Exception( _T("CIOCompletionPort::PostStatus() - PostQueuedCompletionStatus"), ::GetLastError() );}}DWORD CIOCompletionPort::GetStatus( ULONG_PTR *pCompletionKey, PDWORD pdwNumBytes,OVERLAPPED **ppOverlapped ){if ( 0 == ::GetQueuedCompletionStatus( m_iocp, pdwNumBytes, pCompletionKey, ppOverlapped, INFINITE ) ){return ::GetLastError();}return S_OK;}DWORD CIOCompletionPort::GetStatus( ULONG_PTR *pCompletionKey, PDWORD pdwNumBytes,OVERLAPPED **ppOverlapped, DWORD dwMilliseconds){if ( 0 == ::GetQueuedCompletionStatus( m_iocp, pdwNumBytes, pCompletionKey, ppOverlapped, dwMilliseconds ) ){DWORD lastError = ::GetLastError();if ( lastError != WAIT_TIMEOUT ){return lastError;}return S_FALSE;}return S_OK;}} // End of namespace OnlineGameLib} // End of namespace Win32