/********************************************************************* * _heapmin (MSVCRT.@) */ int CDECL _heapmin(void) { if (!HeapCompact( heap, 0 ) || (sb_heap && !HeapCompact( sb_heap, 0 ))) { if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) msvcrt_set_errno(GetLastError()); return -1; } return 0; }
//-------------------------------------------------------------------// // CompactHeap() // //-------------------------------------------------------------------// // This function compacts the application's heap(s) and returns // the maximum block size available after compaction. // // Not sure which of the heaps we encounter is the "default" used by // the program. We compact them all. // // If you want a heap count, provide the address of the integer // to set. // // NOTE: we only allow 25 heaps max here. //-------------------------------------------------------------------// unsigned int CompactHeap( int* pnHeapCount ) { // This does ALL heaps. unsigned int unLargestBlock = 0; HANDLE hHeaps[25]; DWORD dwHeaps = GetProcessHeaps( 25, hHeaps ); ASSERT( dwHeaps < 25 ); if ( dwHeaps < 25 ) { for ( int nA = 0; nA < dwHeaps; nA++ ) { unLargestBlock = max( unLargestBlock, HeapCompact( hHeaps[nA], 0 ) ); } } if ( pnHeapCount != 0 ) *pnHeapCount = dwHeaps; return unLargestBlock; /* // This does the default heap (the CRT heap? not according to // M$DN support...). return HeapCompact( GetProcessHeap(), 0 ); */ }
void __cdecl xf_dump() { PROCESS_HEAP_ENTRY ent = {NULL}; HeapLock(ghHeap); HeapCompact(ghHeap,0); char sBlockInfo[255]; while (HeapWalk(ghHeap, &ent)) { if (ent.wFlags & PROCESS_HEAP_ENTRY_BUSY) { xf_mem_block* p = (xf_mem_block*)ent.lpData; if (p->bBlockUsed==TRUE && p->nBlockSize==ent.cbData) { #ifndef _WIN64 wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%08X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, p->sCreatedFrom); #else wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%I64X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, p->sCreatedFrom); #endif } else { #ifndef _WIN64 wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%08X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, "<Header information broken!>"); #else wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%I64X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, "<Header information broken!>"); #endif } OutputDebugStringA(sBlockInfo); } } HeapUnlock(ghHeap); }
int __cdecl _heapmin(void) { if ((HeapCompact(_crtheap, 0) == 0) && (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)) { return -1; } return 0; }
void dm_HeapCompact() { HANDLE hHeap; if(hHeap = GetProcessHeap()) { HeapCompact(hHeap, 0); } }
/********************************************************************* * _heapmin (MSVCRT.@) */ int CDECL _heapmin(void) { if (!HeapCompact( GetProcessHeap(), 0 )) { if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) msvcrt_set_errno(GetLastError()); return -1; } return 0; }
static void SystemProcessTimer() { #ifdef _WIN32_WCE HeapCompact(); #endif SystemClockTimer(); CheckDisplayTimeOut(false); }
void xrMemory::mem_compact () { RegFlushKey ( HKEY_CLASSES_ROOT ); RegFlushKey ( HKEY_CURRENT_USER ); if (g_allow_heap_min) _heapmin ( ); HeapCompact (GetProcessHeap(),0); if (g_pStringContainer) g_pStringContainer->clean (); if (g_pSharedMemoryContainer) g_pSharedMemoryContainer->clean (); if (strstr(Core.Params,"-swap_on_compact")) SetProcessWorkingSetSize (GetCurrentProcess(),size_t(-1),size_t(-1)); }
void* prim_heapCompact(HANDLE arg1,DWORD arg2) { static struct {HsWord32 res1;HsInt gc_failed;HsPtr gc_failstring;} gc_result; UINT res1;int gc_failed; char* gc_failstring; do {res1 = HeapCompact(arg1, arg2); if ((gc_failed = ( res1==NULL ))) {gc_failstring = ErrorWin("HeapCompact") ;} else {gc_failed = 0;} gc_result.res1 = (UINT)(res1); gc_result.gc_failed = gc_failed; gc_result.gc_failstring = gc_failstring; return(&gc_result);} while(0); }
int __cdecl _heapmin(void) { if ( HeapCompact( _crtheap, 0 ) == 0 ) { if ( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED ) { _doserrno = ERROR_CALL_NOT_IMPLEMENTED; errno = ENOSYS; } return -1; } else { return 0; } }
// This is necessary to be called periodically to get rid of // memory defragmentation, since on pocket pc platforms there is no // automatic defragmentation. void MyCompactHeaps() { #if defined(GNAV) && !defined(__GNUC__) HeapCompact(GetProcessHeap(), 0); #else typedef DWORD (_stdcall *CompactAllHeapsFn) (void); static CompactAllHeapsFn CompactAllHeaps = NULL; static bool init = false; if (!init) { // get the pointer to the function CompactAllHeaps = (CompactAllHeapsFn)GetProcAddress( LoadLibrary(_T("coredll.dll")), _T("CompactAllHeaps")); init = true; } if (CompactAllHeaps) CompactAllHeaps(); #endif }
/** * Allocates the specified number of bytes from the heap. * @param flags Allocation attributes * @param size Number of bytes to allocate */ static MEM_NODE *MemoryAlloc(long size) { MEM_NODE *pHeap = &heapSentinel; #ifdef SCUMM_NEED_ALIGNMENT const int alignPadding = sizeof(void*) - 1; size = (size + alignPadding) & ~alignPadding; //round up to nearest multiple of sizeof(void*), this ensures the addresses that are returned are alignment-safe. #endif // compact the heap to make up room for 'size' bytes, if necessary if (!HeapCompact(size)) return 0; // success! we may allocate a new node of the right size // Allocate a node. MEM_NODE *pNode = AllocMemNode(); // Allocate memory for the node. pNode->pBaseAddr = (byte *)malloc(size); // Verify that we got the memory. // TODO: If this fails, we should first try to compact the heap some further. assert(pNode->pBaseAddr); // Subtract size of new block from total heapSentinel.size -= size; #ifdef DEBUG MemoryStats(); #endif // Set flags, LRU time and size pNode->flags = DWM_USED; pNode->lruTime = DwGetCurrentTime() + 1; pNode->size = size; // set mnode at the end of the list pNode->pPrev = pHeap->pPrev; pNode->pNext = pHeap; // fix links to this mnode pHeap->pPrev->pNext = pNode; pHeap->pPrev = pNode; return pNode; }
/* * @implemented */ int _heapmin(void) { if (!HeapCompact(GetProcessHeap(), 0)) return -1; return 0; }
int _cdecl main() { struct _heapinfo info; PROCESS_HEAP_ENTRY Entry; size_t i; LPBYTE s; info._pentry = NULL; setvbuf( stdout, MyBuffer, _IOFBF, sizeof( MyBuffer ) ); _heapset( 0xAE ); while (_heapwalk( &info ) == _HEAPOK) { printf( "%08x: %05x - %s", info._pentry, info._size, info._useflag ? "busy" : "free" ); if (info._useflag == _FREEENTRY) { s = (LPBYTE)info._pentry; for (i=0; i<info._size; i++) { if (s[i] != 0xAE) { printf( " *** free block invalid at offset %x [%x]", i, s[i] ); break; } } } printf( "\n" ); fflush( stdout ); } printf( "*** end of heap ***\n\n" ); fflush( stdout ); NumberOfHeaps = GetProcessHeaps( 64, ProcessHeaps ); Entry.lpData = NULL; for (i=0; i<NumberOfHeaps; i++) { printf( "Heap[ %u ]: %x HeapCompact result: %lx\n", i, ProcessHeaps[ i ], HeapCompact( ProcessHeaps[ i ], 0 ) ); while (HeapWalk( ProcessHeaps[ i ], &Entry )) { if (Entry.wFlags & PROCESS_HEAP_REGION) { printf( " %08x: %08x - Region(First: %08x Last: %08x Committed: %x Uncommitted: %08x)\n", Entry.lpData, Entry.cbData, Entry.Region.lpFirstBlock, Entry.Region.lpLastBlock, Entry.Region.dwCommittedSize, Entry.Region.dwUnCommittedSize ); } else if (Entry.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) { printf( " %08x: %08x - Uncommitted\n", Entry.lpData, Entry.cbData ); } else if (Entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) { printf( " %08x: %08x - Busy", Entry.lpData, Entry.cbData ); if (Entry.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) { printf( " hMem: %08x", Entry.Block.hMem ); } if (Entry.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) { printf( " DDE" ); } printf( "\n" ); } else { printf( " %08x: %08x - Free\n", Entry.lpData, Entry.cbData ); } fflush( stdout ); } printf( "*** end of heap ***\n\n" ); fflush( stdout ); } return 0; }
void theLoop::AcceptUser(AcceptedSocket *AccptSocket) { bool bIPv6 = false; char sIP[46]; uint8_t ui128IpHash[16]; memset(ui128IpHash, 0, 16); uint16_t ui16IpTableIdx = 0; if(AccptSocket->addr.ss_family == AF_INET6) { memcpy(ui128IpHash, &((struct sockaddr_in6 *)&AccptSocket->addr)->sin6_addr.s6_addr, 16); if(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&AccptSocket->addr)->sin6_addr)) { in_addr ipv4addr; memcpy(&ipv4addr, ((struct sockaddr_in6 *)&AccptSocket->addr)->sin6_addr.s6_addr + 12, 4); strcpy(sIP, inet_ntoa(ipv4addr)); ui16IpTableIdx = ui128IpHash[14] * ui128IpHash[15]; } else { bIPv6 = true; #ifdef _WIN32 win_inet_ntop(&((struct sockaddr_in6 *)&AccptSocket->addr)->sin6_addr, sIP, 46); #else inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&AccptSocket->addr)->sin6_addr, sIP, 46); #endif ui16IpTableIdx = GetIpTableIdx(ui128IpHash); } } else { strcpy(sIP, inet_ntoa(((struct sockaddr_in *)&AccptSocket->addr)->sin_addr)); ui128IpHash[10] = 255; ui128IpHash[11] = 255; memcpy(ui128IpHash+12, &((struct sockaddr_in *)&AccptSocket->addr)->sin_addr.s_addr, 4); ui16IpTableIdx = ui128IpHash[14] * ui128IpHash[15]; } // set the recv buffer #ifdef _WIN32 int32_t bufsize = 8192; if(setsockopt(AccptSocket->s, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)) == SOCKET_ERROR) { int iError = WSAGetLastError(); int imsgLen = sprintf(msg, "[SYS] setsockopt failed on attempt to set SO_RCVBUF. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError); #else int bufsize = 8192; if(setsockopt(AccptSocket->s, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) == -1) { int imsgLen = sprintf(msg, "[SYS] setsockopt failed on attempt to set SO_RCVBUF. IP: %s Err: %d", sIP, errno); #endif if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser1") == true) { UdpDebug->Broadcast(msg, imsgLen); } #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif return; } // set the send buffer bufsize = 32768; #ifdef _WIN32 if(setsockopt(AccptSocket->s, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, sizeof(bufsize)) == SOCKET_ERROR) { int iError = WSAGetLastError(); int imsgLen = sprintf(msg, "[SYS] setsockopt failed on attempt to set SO_SNDBUF. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError); #else if(setsockopt(AccptSocket->s, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) == -1) { int imsgLen = sprintf(msg, "[SYS] setsockopt failed on attempt to set SO_SNDBUF. IP: %s Err: %d", sIP, errno); #endif if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser2") == true) { UdpDebug->Broadcast(msg, imsgLen); } #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif return; } // set sending of keepalive packets #ifdef _WIN32 bool bKeepalive = true; setsockopt(AccptSocket->s, SOL_SOCKET, SO_KEEPALIVE, (char *)&bKeepalive, sizeof(bKeepalive)); #else int iKeepAlive = 1; if(setsockopt(AccptSocket->s, SOL_SOCKET, SO_KEEPALIVE, &iKeepAlive, sizeof(iKeepAlive)) == -1) { int imsgLen = sprintf(msg, "[SYS] setsockopt failed on attempt to set SO_KEEPALIVE. IP: %s Err: %d", sIP, errno); if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser3") == true) { UdpDebug->Broadcast(msg, imsgLen); } shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); return; } #endif // set non-blocking mode #ifdef _WIN32 uint32_t block = 1; if(ioctlsocket(AccptSocket->s, FIONBIO, (unsigned long *)&block) == SOCKET_ERROR) { int iError = WSAGetLastError(); int imsgLen = sprintf(msg, "[SYS] ioctlsocket failed on attempt to set FIONBIO. IP: %s Err: %s (%d)", sIP, WSErrorStr(iError), iError); #else int oldFlag = fcntl(AccptSocket->s, F_GETFL, 0); if(fcntl(AccptSocket->s, F_SETFL, oldFlag | O_NONBLOCK) == -1) { int imsgLen = sprintf(msg, "[SYS] fcntl failed on attempt to set O_NONBLOCK. IP: %s Err: %d", sIP, errno); #endif if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser3") == true) { UdpDebug->Broadcast(msg, imsgLen); } #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif return; } if(SettingManager->bBools[SETBOOL_REDIRECT_ALL] == true) { if(SettingManager->sPreTexts[SetMan::SETPRETXT_REDIRECT_ADDRESS] != NULL) { int imsgLen = sprintf(msg, "<%s> %s %s|%s", SettingManager->sPreTexts[SetMan::SETPRETXT_HUB_SEC], LanguageManager->sTexts[LAN_YOU_REDIR_TO], SettingManager->sTexts[SETTXT_REDIRECT_ADDRESS], SettingManager->sPreTexts[SetMan::SETPRETXT_REDIRECT_ADDRESS]); if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser4") == true) { send(AccptSocket->s, msg, imsgLen, 0); ui64BytesSent += imsgLen; } } #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif return; } time_t acc_time; time(&acc_time); BanItem * Ban = hashBanManager->FindFull(ui128IpHash, acc_time); if(Ban != NULL) { if(((Ban->ui8Bits & hashBanMan::FULL) == hashBanMan::FULL) == true) { int imsglen; char *messg = GenerateBanMessage(Ban, imsglen, acc_time); send(AccptSocket->s, messg, imsglen, 0); #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RD); close(AccptSocket->s); #endif /* int imsgLen = sprintf(msg, "[SYS] Banned ip %s - connection closed.", sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser5") == true) { UdpDebug->Broadcast(msg, imsgLen); }*/ return; } } RangeBanItem * RangeBan = hashBanManager->FindFullRange(ui128IpHash, acc_time); if(RangeBan != NULL) { if(((RangeBan->ui8Bits & hashBanMan::FULL) == hashBanMan::FULL) == true) { int imsglen; char *messg = GenerateRangeBanMessage(RangeBan, imsglen, acc_time); send(AccptSocket->s, messg, imsglen, 0); #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RD); close(AccptSocket->s); #endif /* int imsgLen = sprintf(msg, "[SYS] Range Banned ip %s - connection closed.", sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::AcceptUser6") == true) { UdpDebug->Broadcast(msg, imsgLen); }*/ return; } } ui32Joins++; // set properties of the new user object User * pUser = new User(); if(pUser == NULL) { #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif AppendDebugLog("%s - [MEM] Cannot allocate pUser in theLoop::AcceptUser\n", 0); return; } pUser->uLogInOut = new LoginLogout(); if(pUser->uLogInOut == NULL) { #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif delete pUser; AppendDebugLog("%s - [MEM] Cannot allocate uLogInOut in theLoop::AcceptUser\n", 0); return; } pUser->uLogInOut->logonClk = ui64ActualTick; pUser->Sck = AccptSocket->s; pUser->ui8State = User::STATE_KEY_OR_SUP; memcpy(pUser->ui128IpHash, ui128IpHash, 16); pUser->ui16IpTableIdx = ui16IpTableIdx; UserSetIP(pUser, sIP); if(bIPv6 == true) { pUser->ui32BoolBits |= User::BIT_IPV6; } else { pUser->ui32BoolBits |= User::BIT_IPV4; } if(UserMakeLock(pUser) == false) { #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif delete pUser; return; } if(Ban != NULL) { uint32_t hash = 0; if(((Ban->ui8Bits & hashBanMan::NICK) == hashBanMan::NICK) == true) { hash = Ban->ui32NickHash; } int imsglen; char *messg = GenerateBanMessage(Ban, imsglen, acc_time); pUser->uLogInOut->uBan = new UserBan(messg, imsglen, hash); if(pUser->uLogInOut->uBan == NULL || pUser->uLogInOut->uBan->sMessage == NULL) { #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif if(pUser->uLogInOut->uBan == NULL) { AppendDebugLog("%s - [MEM] Cannot allocate new uBan in theLoop::AcceptUser\n", 0); } else { AppendDebugLog("%s - [MEM] Cannot allocate uBan->sMessage in theLoop::AcceptUser\n", 0); } delete pUser; return; } } else if(RangeBan != NULL) { int imsglen; char *messg = GenerateRangeBanMessage(RangeBan, imsglen, acc_time); pUser->uLogInOut->uBan = new UserBan(messg, imsglen, 0); if(pUser->uLogInOut->uBan == NULL || pUser->uLogInOut->uBan->sMessage == NULL) { #ifdef _WIN32 shutdown(AccptSocket->s, SD_SEND); closesocket(AccptSocket->s); #else shutdown(AccptSocket->s, SHUT_RDWR); close(AccptSocket->s); #endif if(pUser->uLogInOut->uBan == NULL) { AppendDebugLog("%s - [MEM] Cannot allocate new uBan in theLoop::AcceptUser1\n", 0); } else { AppendDebugLog("%s - [MEM] Cannot allocate uBan->sMessage in theLoop::AcceptUser1\n", 0); } delete pUser; return; } } // Everything is ok, now add to users... colUsers->AddUser(pUser); } //--------------------------------------------------------------------------- void theLoop::ReceiveLoop() { #ifndef _WIN32 while((iSIG = sigtimedwait(&sst, &info, &zerotime)) != -1) { if(iSIG == SIGSCRTMR) { ScriptOnTimer((ScriptTimer *)info.si_value.sival_ptr); } else if(iSIG == SIGREGTMR) { RegTimerHandler(); } } #endif // Receiving loop for process all incoming data and store in queues uint32_t iRecvRests = 0; ui8SrCntr++; if(ui8SrCntr >= 7 || (colUsers->ui16ActSearchs + colUsers->ui16PasSearchs) > 8 || colUsers->ui16ActSearchs > 5) { ui8SrCntr = 0; } if(ui64ActualTick-iLstUptmTck > 60) { time_t acctime; time(&acctime); acctime -= starttime; uint64_t iValue = acctime / 86400; acctime -= (time_t)(86400*iValue); iDays = iValue; iValue = acctime / 3600; acctime -= (time_t)(3600*iValue); iHours = iValue; iValue = acctime / 60; iMins = iValue; #ifdef _WIN32 if(iMins == 0 || iMins == 15 || iMins == 30 || iMins == 45) { if(HeapValidate(GetProcessHeap(), 0, 0) == 0) { AppendDebugLog("%s - [ERR] Process memory heap corrupted\n", 0); } HeapCompact(GetProcessHeap(), 0); if(HeapValidate(hPtokaXHeap, HEAP_NO_SERIALIZE, 0) == 0) { AppendDebugLog("%s - [ERR] PtokaX memory heap corrupted\n", 0); } HeapCompact(hPtokaXHeap, HEAP_NO_SERIALIZE); if(HeapValidate(hRecvHeap, HEAP_NO_SERIALIZE, 0) == 0) { AppendDebugLog("%s - [ERR] Recv memory heap corrupted\n", 0); } HeapCompact(hRecvHeap, HEAP_NO_SERIALIZE); if(HeapValidate(hSendHeap, HEAP_NO_SERIALIZE, 0) == 0) { AppendDebugLog("%s - [ERR] Send memory heap corrupted\n", 0); } HeapCompact(hSendHeap, HEAP_NO_SERIALIZE); if(HeapValidate(hLuaHeap, 0, 0) == 0) { AppendDebugLog("%s - [ERR] Lua memory heap corrupted\n", 0); } HeapCompact(hLuaHeap, 0); } #endif iLstUptmTck = ui64ActualTick; } AcceptedSocket *NextSck = NULL; #ifdef _WIN32 EnterCriticalSection(&csAcceptQueue); #else pthread_mutex_lock(&mtxAcceptQueue); #endif if(AcceptedSocketsS != NULL) { NextSck = AcceptedSocketsS; AcceptedSocketsS = NULL; AcceptedSocketsE = NULL; } #ifdef _WIN32 LeaveCriticalSection(&csAcceptQueue); #else pthread_mutex_unlock(&mtxAcceptQueue); #endif while(NextSck != NULL) { AcceptedSocket *CurSck = NextSck; NextSck = CurSck->next; AcceptUser(CurSck); delete CurSck; } User *nextUser = colUsers->llist; while(nextUser != 0 && bServerTerminated == false) { User *curUser = nextUser; nextUser = curUser->next; // PPK ... true == we have rest ;) if(UserDoRecv(curUser) == true) { iRecvRests++; //Memo("Rest " + string(curUser->Nick, curUser->NickLen) + ": '" + string(curUser->recvbuf) + "'"); } // curUser->ProcessLines(); //} switch(curUser->ui8State) { case User::STATE_KEY_OR_SUP:{ // check logon timeout for iState 1 if(ui64ActualTick - curUser->uLogInOut->logonClk > 20) { int imsgLen = sprintf(msg, "[SYS] Login timeout 1 for %s - user disconnected.", curUser->sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop3") == true) { UdpDebug->Broadcast(msg, imsgLen); } UserClose(curUser); continue; } break; } case User::STATE_IPV4_CHECK: { // check IPv4Check timeout if((ui64ActualTick - curUser->uLogInOut->ui64IPv4CheckTick) > 10) { int imsgLen = sprintf(msg, "[SYS] IPv4Check timeout for %s (%s).", curUser->sNick, curUser->sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop31") == true) { UdpDebug->Broadcast(msg, imsgLen); } curUser->ui8State = User::STATE_ADDME; continue; } break; } case User::STATE_ADDME: { // PPK ... Add user, but only if send $GetNickList (or have quicklist supports) <- important, used by flooders !!! if(((curUser->ui32BoolBits & User::BIT_GETNICKLIST) == User::BIT_GETNICKLIST) == false && ((curUser->ui32SupportBits & User::SUPPORTBIT_QUICKLIST) == User::SUPPORTBIT_QUICKLIST) == false && ((curUser->ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true) continue; int imsgLen = GetWlcmMsg(msg); UserSendCharDelayed(curUser, msg, imsgLen); curUser->ui8State = User::STATE_ADDME_1LOOP; continue; } case User::STATE_ADDME_1LOOP: { // PPK ... added login delay. if(dLoggedUsers >= dActualSrvLoopLogins && ((curUser->ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == false) { if(ui64ActualTick - curUser->uLogInOut->logonClk > 300) { int imsgLen = sprintf(msg, "[SYS] Login timeout (%d) 3 for %s (%s) - user disconnected.", (int)curUser->ui8State, curUser->sNick, curUser->sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop4") == true) { UdpDebug->Broadcast(msg, imsgLen); } UserClose(curUser); } continue; } // PPK ... is not more needed, free mem ;) if(curUser->uLogInOut->pBuffer != NULL) { #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)curUser->uLogInOut->pBuffer) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate curUser->uLogInOut->pBuffer in theLoop::ReceiveLoop\n", 0); } #else free(curUser->uLogInOut->pBuffer); #endif curUser->uLogInOut->pBuffer = NULL; } if((curUser->ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6 && ((curUser->ui32BoolBits & User::SUPPORTBIT_IPV4) == User::SUPPORTBIT_IPV4) == false) { in_addr ipv4addr; ipv4addr.s_addr = INADDR_NONE; if(curUser->ui128IpHash[0] == 32 && curUser->ui128IpHash[1] == 2) { // 6to4 tunnel memcpy(&ipv4addr, curUser->ui128IpHash + 2, 4); } else if(curUser->ui128IpHash[0] == 32 && curUser->ui128IpHash[1] == 1 && curUser->ui128IpHash[2] == 0 && curUser->ui128IpHash[3] == 0) { // teredo tunnel uint32_t ui32Ip = 0; memcpy(&ui32Ip, curUser->ui128IpHash + 12, 4); ui32Ip ^= 0xffffffff; memcpy(&ipv4addr, &ui32Ip, 4); } if(ipv4addr.s_addr != INADDR_NONE) { strcpy(curUser->sIPv4, inet_ntoa(ipv4addr)); curUser->ui8IPv4Len = (uint8_t)strlen(curUser->sIPv4); curUser->ui32BoolBits |= User::BIT_IPV4; } } //New User Connected ... the user is operator ? invoke lua User/OpConnected uint32_t iBeforeLuaLen = curUser->sbdatalen; bool bRet = ScriptManager->UserConnected(curUser); if(curUser->ui8State >= User::STATE_CLOSING) {// connection closed by script? if(bRet == false) { // only when all scripts process userconnected ScriptManager->UserDisconnected(curUser); } continue; } if(iBeforeLuaLen < curUser->sbdatalen) { size_t szNeededLen = curUser->sbdatalen-iBeforeLuaLen; void * sOldBuf = curUser->uLogInOut->pBuffer; #ifdef _WIN32 if(curUser->uLogInOut->pBuffer == NULL) { curUser->uLogInOut->pBuffer = (char *)HeapAlloc(hPtokaXHeap, HEAP_NO_SERIALIZE, szNeededLen+1); } else { curUser->uLogInOut->pBuffer = (char *)HeapReAlloc(hPtokaXHeap, HEAP_NO_SERIALIZE, sOldBuf, szNeededLen+1); } #else curUser->uLogInOut->pBuffer = (char *)realloc(sOldBuf, szNeededLen+1); #endif if(curUser->uLogInOut->pBuffer == NULL) { curUser->ui32BoolBits |= User::BIT_ERROR; UserClose(curUser); AppendDebugLog("%s - [MEM] Cannot allocate %" PRIu64 " bytes for sLockUsrConn in theLoop::ReceiveLoop\n", (uint64_t)(szNeededLen+1)); continue; } memcpy(curUser->uLogInOut->pBuffer, curUser->sendbuf+iBeforeLuaLen, szNeededLen); curUser->uLogInOut->iUserConnectedLen = (uint32_t)szNeededLen; curUser->uLogInOut->pBuffer[curUser->uLogInOut->iUserConnectedLen] = '\0'; curUser->sbdatalen = iBeforeLuaLen; curUser->sendbuf[curUser->sbdatalen] = '\0'; } // PPK ... wow user is accepted, now add it :) if(((curUser->ui32BoolBits & User::BIT_HAVE_BADTAG) == User::BIT_HAVE_BADTAG) == true) { UserHasSuspiciousTag(curUser); } UserAdd2Userlist(curUser); dLoggedUsers++; curUser->ui8State = User::STATE_ADDME_2LOOP; ui64TotalShare += curUser->ui64SharedSize; curUser->ui32BoolBits |= User::BIT_HAVE_SHARECOUNTED; #ifdef _BUILD_GUI if(::SendMessage(pMainWindowPageUsersChat->hWndPageItems[MainWindowPageUsersChat::BTN_AUTO_UPDATE_USERLIST], BM_GETCHECK, 0, 0) == BST_CHECKED) { pMainWindowPageUsersChat->AddUser(curUser); } #endif // if(sqldb) sqldb->AddVisit(curUser); // PPK ... change to NoHello supports int imsgLen = sprintf(msg, "$Hello %s|", curUser->sNick); if(CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop6") == true) { g_GlobalDataQueue->AddQueueItem(msg, imsgLen, NULL, 0, GlobalDataQueue::CMD_HELLO); } g_GlobalDataQueue->UserIPStore(curUser); switch(SettingManager->ui8FullMyINFOOption) { case 0: g_GlobalDataQueue->AddQueueItem(curUser->sMyInfoLong, curUser->ui16MyInfoLongLen, NULL, 0, GlobalDataQueue::CMD_MYINFO); break; case 1: g_GlobalDataQueue->AddQueueItem(curUser->sMyInfoShort, curUser->ui16MyInfoShortLen, curUser->sMyInfoLong, curUser->ui16MyInfoLongLen, GlobalDataQueue::CMD_MYINFO); break; case 2: g_GlobalDataQueue->AddQueueItem(curUser->sMyInfoShort, curUser->ui16MyInfoShortLen, NULL, 0, GlobalDataQueue::CMD_MYINFO); break; default: break; } if(((curUser->ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == true) { g_GlobalDataQueue->OpListStore(curUser->sNick); } curUser->iLastMyINFOSendTick = ui64ActualTick; break; } case User::STATE_ADDED: if(curUser->cmdToUserStrt != NULL) { PrcsdToUsrCmd *next = curUser->cmdToUserStrt; curUser->cmdToUserStrt = NULL; curUser->cmdToUserEnd = NULL; while(next != NULL) { PrcsdToUsrCmd *cur = next; next = cur->next; if(cur->iLoops >= 2) { User * ToUser = hashManager->FindUser(cur->ToNick, cur->iToNickLen); if(ToUser == cur->To) { if(SettingManager->iShorts[SETSHORT_MAX_PM_COUNT_TO_USER] == 0 || cur->iPmCount == 0) { UserSendCharDelayed(cur->To, cur->sCommand, cur->iLen); } else { if(cur->To->iReceivedPmCount == 0) { cur->To->iReceivedPmTick = ui64ActualTick; } else if(cur->To->iReceivedPmCount >= (uint32_t)SettingManager->iShorts[SETSHORT_MAX_PM_COUNT_TO_USER]) { if(cur->To->iReceivedPmTick+60 < ui64ActualTick) { cur->To->iReceivedPmTick = ui64ActualTick; cur->To->iReceivedPmCount = 0; } else { bool bSprintfCheck; int imsgLen; if(cur->iPmCount == 1) { imsgLen = sprintf(msg, "$To: %s From: %s $<%s> %s %s %s!|", curUser->sNick, cur->ToNick, SettingManager->sPreTexts[SetMan::SETPRETXT_HUB_SEC], LanguageManager->sTexts[LAN_SRY_LST_MSG_BCS], cur->ToNick, LanguageManager->sTexts[LAN_EXC_MSG_LIMIT]); bSprintfCheck = CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop1"); } else { imsgLen = sprintf(msg, "$To: %s From: %s $<%s> %s %d %s %s %s!|", curUser->sNick, cur->ToNick, SettingManager->sPreTexts[SetMan::SETPRETXT_HUB_SEC], LanguageManager->sTexts[LAN_SORRY_LAST], cur->iPmCount, LanguageManager->sTexts[LAN_MSGS_NOT_SENT], cur->ToNick, LanguageManager->sTexts[LAN_EXC_MSG_LIMIT]); bSprintfCheck = CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop2"); } if(bSprintfCheck == true) { UserSendCharDelayed(curUser, msg, imsgLen); } #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)cur->sCommand) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate cur->sCommand in theLoop::ReceiveLoop\n", 0); } #else free(cur->sCommand); #endif cur->sCommand = NULL; #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)cur->ToNick) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate cur->ToNick in theLoop::ReceiveLoop\n", 0); } #else free(cur->ToNick); #endif cur->ToNick = NULL; delete cur; continue; } } UserSendCharDelayed(cur->To, cur->sCommand, cur->iLen); cur->To->iReceivedPmCount += cur->iPmCount; } } } else { cur->iLoops++; if(curUser->cmdToUserStrt == NULL) { cur->next = NULL; curUser->cmdToUserStrt = cur; curUser->cmdToUserEnd = cur; } else { curUser->cmdToUserEnd->next = cur; curUser->cmdToUserEnd = cur; } continue; } #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)cur->sCommand) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate cur->sCommand1 in theLoop::ReceiveLoop\n", 0); } #else free(cur->sCommand); #endif cur->sCommand = NULL; #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)cur->ToNick) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate cur->ToNick1 in theLoop::ReceiveLoop\n", 0); } #else free(cur->ToNick); #endif cur->ToNick = NULL; delete cur; } } if(ui8SrCntr == 0) { if(curUser->cmdActive6Search != NULL) { if(curUser->cmdActive4Search != NULL) { g_GlobalDataQueue->AddQueueItem(curUser->cmdActive6Search->sCommand, curUser->cmdActive6Search->iLen, curUser->cmdActive4Search->sCommand, curUser->cmdActive4Search->iLen, GlobalDataQueue::CMD_ACTIVE_SEARCH_V64); } else { g_GlobalDataQueue->AddQueueItem(curUser->cmdActive6Search->sCommand, curUser->cmdActive6Search->iLen, NULL, 0, GlobalDataQueue::CMD_ACTIVE_SEARCH_V6); } } else if(curUser->cmdActive4Search != NULL) { g_GlobalDataQueue->AddQueueItem(curUser->cmdActive4Search->sCommand, curUser->cmdActive4Search->iLen, NULL, 0, GlobalDataQueue::CMD_ACTIVE_SEARCH_V4); } if(curUser->cmdPassiveSearch != NULL) { uint8_t ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V4; if((curUser->ui32BoolBits & User::BIT_IPV6) == User::BIT_IPV6) { if((curUser->ui32BoolBits & User::BIT_IPV4) == User::BIT_IPV4) { if((curUser->ui32BoolBits & User::BIT_IPV6_ACTIVE) == User::BIT_IPV6_ACTIVE) { ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V4_ONLY; } else if((curUser->ui32BoolBits & User::BIT_IPV4_ACTIVE) == User::BIT_IPV4_ACTIVE) { ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V6_ONLY; } else { ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V64; } } else { ui8CmdType = GlobalDataQueue::CMD_PASSIVE_SEARCH_V6; } } g_GlobalDataQueue->AddQueueItem(curUser->cmdPassiveSearch->sCommand, curUser->cmdPassiveSearch->iLen, NULL, 0, ui8CmdType); UserDeletePrcsdUsrCmd(curUser->cmdPassiveSearch); curUser->cmdPassiveSearch = NULL; } } // PPK ... deflood memory cleanup, if is not needed anymore if(ui8SrCntr == 0) { if(curUser->sLastChat != NULL && curUser->ui16LastChatLines < 2 && (curUser->ui64SameChatsTick+SettingManager->iShorts[SETSHORT_SAME_MAIN_CHAT_TIME]) < ui64ActualTick) { #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)curUser->sLastChat) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate curUser->sLastChat in theLoop::ReceiveLoop\n", 0); } #else free(curUser->sLastChat); #endif curUser->sLastChat = NULL; curUser->ui16LastChatLen = 0; curUser->ui16SameMultiChats = 0; curUser->ui16LastChatLines = 0; } if(curUser->sLastPM != NULL && curUser->ui16LastPmLines < 2 && (curUser->ui64SamePMsTick+SettingManager->iShorts[SETSHORT_SAME_PM_TIME]) < ui64ActualTick) { #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)curUser->sLastPM) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate curUser->sLastPM in theLoop::ReceiveLoop\n", 0); } #else free(curUser->sLastPM); #endif curUser->sLastPM = NULL; curUser->ui16LastPMLen = 0; curUser->ui16SameMultiPms = 0; curUser->ui16LastPmLines = 0; } if(curUser->sLastSearch != NULL && (curUser->ui64SameSearchsTick+SettingManager->iShorts[SETSHORT_SAME_SEARCH_TIME]) < ui64ActualTick) { #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)curUser->sLastSearch) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate curUser->sLastSearch in theLoop::ReceiveLoop\n", 0); } #else free(curUser->sLastSearch); #endif curUser->sLastSearch = NULL; curUser->ui16LastSearchLen = 0; } } continue; case User::STATE_CLOSING: { if(((curUser->ui32BoolBits & User::BIT_ERROR) == User::BIT_ERROR) == false && curUser->sbdatalen != 0) { if(curUser->uLogInOut->iToCloseLoops != 0 || ((curUser->ui32BoolBits & User::BIT_PINGER) == User::BIT_PINGER) == true) { UserTry2Send(curUser); curUser->uLogInOut->iToCloseLoops--; continue; } } curUser->ui8State = User::STATE_REMME; continue; } // if user is marked as dead, remove him case User::STATE_REMME: { #ifdef _WIN32 shutdown(curUser->Sck, SD_SEND); closesocket(curUser->Sck); #else shutdown(curUser->Sck, SHUT_RD); close(curUser->Sck); #endif // linked list colUsers->RemUser(curUser); delete curUser; continue; } default: { // check logon timeout if(ui64ActualTick - curUser->uLogInOut->logonClk > 60) { int imsgLen = sprintf(msg, "[SYS] Login timeout (%d) 2 for %s (%s) - user disconnected.", (int)curUser->ui8State, curUser->sNick, curUser->sIP); if(CheckSprintf(imsgLen, 1024, "theLoop::ReceiveLoop7") == true) { UdpDebug->Broadcast(msg, imsgLen); } UserClose(curUser); continue; } break; } } } if(ui8SrCntr == 0) { colUsers->ui16ActSearchs = 0; colUsers->ui16PasSearchs = 0; } iLastRecvRest = iRecvRests; iRecvRestsPeak = iRecvRests > iRecvRestsPeak ? iRecvRests : iRecvRestsPeak; } //--------------------------------------------------------------------------- void theLoop::SendLoop() { g_GlobalDataQueue->PrepareQueueItems(); // PPK ... send loop // now logging users get changed myinfo with myinfos // old users get it in this loop from queue -> badwith saving !!! no more twice myinfo =) // Sending Loop uint32_t iSendRests = 0; User *nextUser = colUsers->llist; while(nextUser != 0 && bServerTerminated == false) { User *curUser = nextUser; nextUser = curUser->next; switch(curUser->ui8State) { case User::STATE_ADDME_2LOOP: { ui32Logged++; if(ui32Peak < ui32Logged) { ui32Peak = ui32Logged; if(SettingManager->iShorts[SETSHORT_MAX_USERS_PEAK] < (int16_t)ui32Peak) SettingManager->SetShort(SETSHORT_MAX_USERS_PEAK, (int16_t)ui32Peak); } curUser->ui8State = User::STATE_ADDED; // finaly send the nicklist/myinfos/oplist UserAddUserList(curUser); // PPK ... UserIP2 supports if(((curUser->ui32SupportBits & User::SUPPORTBIT_USERIP2) == User::SUPPORTBIT_USERIP2) == true && ((curUser->ui32BoolBits & User::BIT_QUACK_SUPPORTS) == User::BIT_QUACK_SUPPORTS) == false && ProfileMan->IsAllowed(curUser, ProfileManager::SENDALLUSERIP) == false) { int imsgLen = sprintf(msg, "$UserIP %s %s|", curUser->sNick, (curUser->sIPv4[0] == '\0' ? curUser->sIP : curUser->sIPv4)); if(CheckSprintf(imsgLen, 1024, "theLoop::SendLoop1") == true) { UserSendCharDelayed(curUser, msg, imsgLen); } } curUser->ui32BoolBits &= ~User::BIT_GETNICKLIST; // PPK ... send motd ??? if(SettingManager->ui16PreTextsLens[SetMan::SETPRETXT_MOTD] != 0) { if(SettingManager->bBools[SETBOOL_MOTD_AS_PM] == true) { int imsgLen = sprintf(g_sBuffer, SettingManager->sPreTexts[SetMan::SETPRETXT_MOTD], curUser->sNick); if(CheckSprintf(imsgLen, g_szBufferSize, "theLoop::SendLoop2") == true) { UserSendCharDelayed(curUser, g_sBuffer, imsgLen); } } else { UserSendCharDelayed(curUser, SettingManager->sPreTexts[SetMan::SETPRETXT_MOTD], SettingManager->ui16PreTextsLens[SetMan::SETPRETXT_MOTD]); } } // check for Debug subscription if(((curUser->ui32BoolBits & User::BIT_OPERATOR) == User::BIT_OPERATOR) == true) UdpDebug->CheckUdpSub(curUser, true); if(curUser->uLogInOut->iUserConnectedLen != 0) { UserPutInSendBuf(curUser, curUser->uLogInOut->pBuffer, curUser->uLogInOut->iUserConnectedLen); #ifdef _WIN32 if(HeapFree(hPtokaXHeap, HEAP_NO_SERIALIZE, (void *)curUser->uLogInOut->pBuffer) == 0) { AppendDebugLog("%s - [MEM] Cannot deallocate curUser->uLogInOut->pBuffer in theLoop::SendLoop\n", 0); } #else free(curUser->uLogInOut->pBuffer); #endif curUser->uLogInOut->pBuffer = NULL; } // Login struct no more needed, free mem ! ;) delete curUser->uLogInOut; curUser->uLogInOut = NULL; // PPK ... send all login data from buffer ! if(curUser->sbdatalen > 0) { UserTry2Send(curUser); } // apply one loop delay to avoid double sending of hello and oplist continue; } case User::STATE_ADDED: { if(((curUser->ui32BoolBits & User::BIT_GETNICKLIST) == User::BIT_GETNICKLIST) == true) { UserAddUserList(curUser); curUser->ui32BoolBits &= ~User::BIT_GETNICKLIST; } // process global data queues if(g_GlobalDataQueue->pQueueItems != NULL) { g_GlobalDataQueue->ProcessQueues(curUser); } if(g_GlobalDataQueue->pSingleItems != NULL) { g_GlobalDataQueue->ProcessSingleItems(curUser); } // send data acumulated by queues above // if sending caused error, close the user if(curUser->sbdatalen != 0) { // PPK ... true = we have rest ;) if(UserTry2Send(curUser) == true) { iSendRests++; } } break; } case User::STATE_CLOSING: case User::STATE_REMME: continue; default: if(curUser->sbdatalen > 0) { UserTry2Send(curUser); } break; } } g_GlobalDataQueue->ClearQueues(); if(iLoopsForLogins >= 40) { dLoggedUsers = 0; iLoopsForLogins = 0; dActualSrvLoopLogins = 0; } dActualSrvLoopLogins += (double)SettingManager->iShorts[SETSHORT_MAX_SIMULTANEOUS_LOGINS]/40; iLoopsForLogins++; iLastSendRest = iSendRests; iSendRestsPeak = iSendRests > iSendRestsPeak ? iSendRests : iSendRestsPeak; }
TEST(MallocTests, HeapCompact) { HANDLE heap = GetProcessHeap(); ASSERT_NE(heap, (HANDLE)NULL); SIZE_T largest = HeapCompact(heap, 0); ASSERT_GT(largest, 1024); }
void ProcessTimer::SystemProcessTimer() { HeapCompact(); }
// Perform a compacting GC size_t ObjectMemory::compact(Oop* const sp) { TRACE("Compacting OT, size %d, free %d, ...\n", m_nOTSize, m_pOT + m_nOTSize - m_pFreePointerList); EmptyZct(sp); // First perform a normal GC reclaimInaccessibleObjects(GCNormal); Interpreter::freePools(); // Walk the OT from the bottom to locate free entries, and from the top to locate candidates to move // size_t moved = 0; OTE* last = m_pOT + m_nOTSize - 1; OTE* first = m_pOT; #pragma warning(push) #pragma warning(disable : 4127) while(true) #pragma warning(pop) { // Look for a tail ender while (last > first && last->isFree()) last--; // Look for a free slot while (first < last && !first->isFree()) first++; if (first == last) break; // Met in the middle, we're done HARDASSERT(first->isFree()); HARDASSERT(!last->isFree()); // Copy the tail ender over the free slot *first = *last; moved++; // Leave forwarding pointer in the old slot last->m_location = reinterpret_cast<POBJECT>(first); last->beFree(); last->m_count = 0; // Advance last as we've moved this slot last--; } HARDASSERT(last == first); // At this point, last == first, and the first free slot will be that after last TRACE("%d OTEs compacted\n", moved); // Now we can update the objects using the forwarding pointers in the old slots // We must remove the const. spaces memory protect for the duration of the pointer update ProtectConstSpace(PAGE_READWRITE); // New head of free list is first OTE after the single contiguous block of used OTEs // Need to set this before compacting as m_pFreePointerList = last+1; // Now run through the new OT and update the Oops in the objects OTE* pOTE = m_pOT; while (pOTE <= last) { compactObject(pOTE); pOTE++; } // Note that this copies VMPointers to cache area ProtectConstSpace(PAGE_READONLY); // We must inform the interpreter that it needs to update any cached Oops from the forward pointers // before we rebuild the free list (which will destroy those pointers to the new OTEs) Interpreter::OnCompact(); // The last used slot will be the slot before the first entry in the free list // Using this, round up from the last used slot to the to commit granularity, then uncommit any later slots // OTE* end = (OTE*)_ROUND2(reinterpret_cast<ULONG_PTR>(m_pFreePointerList + 1), dwAllocationGranularity); #ifdef _DEBUG m_nFreeOTEs = end - m_pFreePointerList; #endif SIZE_T bytesToDecommit = reinterpret_cast<ULONG_PTR>(m_pOT + m_nOTSize) - reinterpret_cast<ULONG_PTR>(end); ::VirtualFree(end, bytesToDecommit, MEM_DECOMMIT); m_nOTSize = end - m_pOT; // Now fix up the free list OTE* cur = m_pFreePointerList; while (cur < end) { HARDASSERT(cur->isFree()); cur->m_location = reinterpret_cast<POBJECT>(cur + 1); cur++; } // Could do this before or after check refs, since that can account for Zct state PopulateZct(sp); CHECKREFERENCES HeapCompact(); TRACE("... OT compacted, size %d, free %d.\n", m_nOTSize, end - m_pFreePointerList); Interpreter::scheduleFinalization(); return m_pFreePointerList - m_pOT; }