// Include files #include "StdAfx.h" #include "iocontextpool.h" #include "criticalSectionLock.h" #include // Local definitions #define SetLeft(P,L) { (P)->left = L; if (L) (L)->parent = P; } #define SetRight(P,R) { (P)->right = R; if (R) (R)->parent = P; } // Global data bool g_ioContextBuffer = false; // cIoContextPool Constructor cIoContextPool::cIoContextPool(u_long bufferLength) : mBufferLength(bufferLength) { // Critical Section¸¦ ÃʱâÈ­ ÇÑ´Ù. InitializeCriticalSection( &mCs ); // Pool Usage Pointer mPagedPoolUsage = NULL; mNonPagedPoolUsage = NULL; // ¸Þ¸ð¸® Ä«¿îÅÍ. mQuotaPagedPoolUsage = 0; mQuotaNonPagedPoolUsage = 0; mWorkingSetSize = 0; } // ~cIoContextPool Destructor. cIoContextPool::~cIoContextPool(void) { // cIoContextPool¸¦ ÇØÁ¦. Shutdown( ); // Critical Section¸¦ ÇØÁ¦. DeleteCriticalSection( &mCs ); } // DefaultWorkingSize Method bool cIoContextPool::DefaultWorkingSize(DWORD workingSize) { cCSLock lock( &mCs ); // Critical Section PerIoContext* temp = NULL; try { while ( workingSize > 0 ) { temp = GetPool( ); if ( temp == NULL ) throw false; // Socket Context¸¦ Áغñ. workingSize--; } throw true; } catch ( bool boolean ) { while ( mPagedPoolUsage != NULL ) { ReleasePool( mPagedPoolUsage ); } return boolean; } } // GetProcessMemoryInfo Method. void cIoContextPool::GetProcessMemoryInfo(SIZE_T& quotaPagedPoolUsage, SIZE_T& quotaNonPagedPoolUsage, SIZE_T& workingSetSize) { cCSLock lock( &mCs ); quotaPagedPoolUsage = mQuotaPagedPoolUsage; quotaNonPagedPoolUsage = mQuotaNonPagedPoolUsage; workingSetSize = mWorkingSetSize; } // Shutdown Method void cIoContextPool::Shutdown( ) { cCSLock lock( &mCs ); PerIoContext* prev; PerIoContext* next; PerIoContext* temp; // Pool Usage Shutdown - PagedPoolUsage while ( mPagedPoolUsage != NULL ) { prev = mPagedPoolUsage->prev; next = mPagedPoolUsage->next; temp = mPagedPoolUsage; mPagedPoolUsage = mPagedPoolUsage->next; FreeIoContext( &temp ); mQuotaPagedPoolUsage--; } // Pool Usage Shutdown - NonPagedPoolUsage while ( mNonPagedPoolUsage != NULL ) { prev = mNonPagedPoolUsage->prev; next = mNonPagedPoolUsage->next; temp = mNonPagedPoolUsage; mNonPagedPoolUsage = mNonPagedPoolUsage->next; FreeIoContext( &temp ); mQuotaNonPagedPoolUsage--; } } // AllocIoContext Method - I/O Context¸¦ »ý¼ºÇÑ´Ù. PerIoContext* cIoContextPool::AllocIoContext( ) { PerIoContext* perIoContext = (PerIoContext*)GlobalAlloc( GPTR, sizeof(PerIoContext) ); if ( perIoContext != NULL ) { ZeroMemory( &perIoContext->wsaOverlapped, sizeof(WSAOVERLAPPED) ); // overlapped I/O ¸ðµ¨ »ç¿ëÀ» À§ÇÑ ±¸Á¶Ã¼ perIoContext->socket = INVALID_SOCKET; // Ŭ¶óÀÌ¾ðÆ® ¼ÒÄÏ, PerSocketContext¿Í ÂüÁ¶ ZeroMemory( &perIoContext->addr, sizeof(SOCKADDR_IN) ); // Ŭ¶óÀÌ¾ðÆ® ÁÖ¼Ò ±¸Á¶Ã¼ perIoContext->buffer = (char*)GlobalAlloc( GPTR, mBufferLength ); // ¸Þ¸ð¸®¸¦ ÇÒ´çÇÑ´Ù. - GPTR »ç¿ë½Ã 0À¸·Î ÃʱâÈ­µÈ´Ù. perIoContext->offset = 0; // ¹öÆÛÀÇ ¿ÀÇÁ¼Â perIoContext->length = mBufferLength; // ¹öÆÛÀÇ ±æÀÌ perIoContext->requestType = IOCP_REQUEST_READ; // Request Type perIoContext->requestResult = IOCP_REQUEST_SUCCESS; // Request Result perIoContext->iParam = 0; // i Param perIoContext->lParam = 0; // l Param perIoContext->prev = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ÀÌÀü perIoContext->next = NULL; // ¼±Çü¸®½ºÆ®ÀÇ Æ÷ÀÎÅÍ - ´ÙÀ½ // I/O Context::Buffer »ý¼º - ¼º°ø½Ã, mWorkingSetSize Áõ°¡. ½ÇÆÐ½Ã, I/O Context »èÁ¦. (perIoContext->buffer != NULL) ? mWorkingSetSize++ : FreeIoContext( &perIoContext ); } if ( perIoContext == NULL ) { throw "Error - PerIoContext* cIoContextPool::AllocIoContext( ) is null."; } return perIoContext; } // FreeIoContext Method - I/O Context¸¦ »èÁ¦ÇÑ´Ù. void cIoContextPool::FreeIoContext(PerIoContext** perIoContext) { if ( (*perIoContext) != NULL ) { if ( (*perIoContext)->buffer != NULL ) { GlobalFree( (*perIoContext)->buffer ); (*perIoContext)->buffer = NULL; } GlobalFree( (*perIoContext) ); (*perIoContext) = NULL; // mWorkingSetSize¸¦ °¨¼Ò. mWorkingSetSize--; } } // AttachPool Method void cIoContextPool::AttachPool(PerIoContext** pool, PerIoContext* perIoContext) { if ( (*pool) != NULL ) { (*pool)->prev = perIoContext; perIoContext->prev = NULL; perIoContext->next = (*pool); } (*pool) = perIoContext; } // DetachPool Method void cIoContextPool::DetachPool(PerIoContext** pool, PerIoContext* perIoContext) { PerIoContext* prev = perIoContext->prev; PerIoContext* next = perIoContext->next; if ( prev == NULL && next == NULL ) { (*pool) = NULL; } else if ( prev == NULL && next != NULL ) { next->prev = NULL; (*pool) = next; } else if ( prev != NULL && next == NULL ) { prev->next = NULL; } else if ( prev != NULL && next != NULL ) { prev->next = next; next->prev = prev; } perIoContext->prev = NULL; perIoContext->next = NULL; } // GetPool Method PerIoContext* cIoContextPool::GetPool( ) { PerIoContext* perIoContext = mNonPagedPoolUsage; if ( perIoContext != NULL ) { // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®¸¦ Â÷°¨. DetachPool( &mNonPagedPoolUsage, perIoContext ); mQuotaNonPagedPoolUsage--; } else { // ÆäÀÌÁö°¡ ¾øÀ» °æ¿ì »õ·Î »ý¼ºÇÑ´Ù. perIoContext = AllocIoContext( ); } if ( perIoContext != NULL ) { // ÆäÀÌÁö µÈ Ç® »ç¿ë·®À» Áõ°¨. AttachPool( &mPagedPoolUsage, perIoContext ); mQuotaPagedPoolUsage++; } return perIoContext; } // ReleasePool Method void cIoContextPool::ReleasePool(PerIoContext* perIoContext, bool deleteIoContext) { // ÆäÀÌÁö µÈ Ç® »ç¿ë·®À» Â÷°¨. DetachPool( &mPagedPoolUsage, perIoContext ); mQuotaPagedPoolUsage--; if ( deleteIoContext != true ) { // ÆäÀÌÁö ¾ÈµÈ Ç® »ç¿ë·®À» Áõ°¨. AttachPool( &mNonPagedPoolUsage, perIoContext ); mQuotaNonPagedPoolUsage++; } else { // ÆäÀÌÁö »èÁ¦. FreeIoContext( &perIoContext ); } } // GetIoContext Method - ¼±Çü¸®½ºÆ®ÀÇ HEAD¸¦ ³Ñ°ÜÁØ´Ù. // ReleaseIoContext¿Í ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë PerIoContext* cIoContextPool::GetIoContext( ) { cCSLock lock( &mCs ); PerIoContext* perIoContext = GetPool( ); return perIoContext; } PerIoContext* cIoContextPool::GetIoContext(SOCKET socket, u_long request) { cCSLock lock( &mCs ); PerIoContext* perIoContext = GetPool( ); if ( perIoContext != NULL ) { perIoContext->socket = socket; perIoContext->requestType = request; } return perIoContext; } PerIoContext* cIoContextPool::GetIoContext(SOCKET socket, u_long request, SOCKADDR_IN addr) { cCSLock lock( &mCs ); PerIoContext* perIoContext = GetPool( ); if ( perIoContext != NULL ) { perIoContext->socket = socket; perIoContext->addr = addr; perIoContext->requestType = request; } return perIoContext; } // ReleaseIoContext Method - ¼±Çü¸®½ºÆ®ÀÇ HEAD·Î ȸ¼öÇÑ´Ù. // GetIoContext¿Í ÇÔ²² LIFO¸¦ ÀÌ·é´Ù. LIFO´Â Context Switching¸¦ ÃÖ¼ÒÈ­ Çϱâ À§ÇØ »ç¿ë void cIoContextPool::ReleaseIoContext(PerIoContext* perIoContext, bool deleteIoContext, DWORD* errorPtr) { cCSLock lock( &mCs ); u_long offset = perIoContext->offset + perIoContext->InternalHigh; // »ç¿ëµÈ ¿ÀÇÁ¼Â. if ( offset > perIoContext->length ) throw "Error - void cIoContextPool::ReleaseIoContext( ) is overflow."; if ( g_ioContextBuffer == true ) { if ( deleteIoContext != true && errorPtr != NULL ) { u_long len = perIoContext->length - offset; // »ç¿ëÈÄ »çÀÌÁî. char* buf = perIoContext->buffer + offset; // »ç¿ëÈÄ Æ÷ÀÎÅÍ. while ( len > 0 ) { if ( (*buf) != 0 ) { (*errorPtr)++; // ¿À·ù󸮷®. (*buf) = 0; // ÃʱâÈ­. } buf++; len--; } } } ZeroMemory( &perIoContext->wsaOverlapped, sizeof(WSAOVERLAPPED) ); // Overlapped ÃʱâÈ­. perIoContext->socket = INVALID_SOCKET; // ¼ÒÄÏ ÃʱâÈ­. ZeroMemory( &perIoContext->addr, sizeof(SOCKADDR_IN) ); // ÁÖ¼Ò ÃʱâÈ­. ZeroMemory( perIoContext->buffer, offset ); // ¸Þ¸ð¸® ÃʱâÈ­. perIoContext->offset = 0; // ¿ÀÇÁ¼Â ÃʱâÈ­. perIoContext->Internal = 0; // ³»ºÎ ÃʱâÈ­. perIoContext->InternalHigh = 0; // ³»ºÎ ÃʱâÈ­. perIoContext->requestType = IOCP_REQUEST_READ; // ¿ä±¸°ª ÃʱâÈ­. perIoContext->requestResult = IOCP_REQUEST_SUCCESS; // °á°ú°ª ÃʱâÈ­. perIoContext->iParam = 0; // ÆÄ¶ó¸ÞÅÍ ÃʱâÈ­. perIoContext->lParam = 0; // ÆÄ¶ó¸ÞÅÍ ÃʱâÈ­. ReleasePool( perIoContext, deleteIoContext ); }