void CArchonProcess::CollectGarbage (void) // CollectGarbage // // Collects garbage { CString sTask; try { int i; // Compute how long it's been since we last collected garbage DWORD dwStart = sysGetTickCount(); DWORD dwTimeSinceLastCollection = dwStart - m_dwLastGarbageCollect; // If it has been less than a certain time, then only collect garbage if // all engines are idle. if (dwTimeSinceLastCollection < MAX_GARBAGE_COLLECT_WAIT) { // Check to see if engines are idle bool bEnginesIdle = true; for (i = 0; i < m_Engines.GetCount(); i++) if (!m_Engines[i].pEngine->IsIdle()) { bEnginesIdle = false; break; } // If the engines are busy, then check to see if we have enough // memory to wait some more. if (!bEnginesIdle) { CProcess CurrentProc; CurrentProc.CreateCurrentProcess(); CProcess::SMemoryInfo MemoryInfo; if (!CurrentProc.GetMemoryInfo(&MemoryInfo)) { LogBlackBox(ERR_CANT_GET_MEMORY_INFO); return; } // If we have enough memory, then wait to collect garbage if (MemoryInfo.dwCurrentAlloc < MAX_GARBAGE_COLLECT_MEMORY) return; // Warning that we're running out of memory LogBlackBox(ERR_MEMORY_WARNING); } } // Collect #ifdef DEBUG_GARBAGE_COLLECTION printf("[%s] Collecting garbage.\n", (LPSTR)m_sName); #endif m_dwLastGarbageCollect = dwStart; m_RunEvent.Reset(); m_PauseEvent.Set(); // Keep track of how long each engine takes to pause (for diagnostic // purposes). TArray<DWORD> PauseTime; PauseTime.InsertEmpty(m_Engines.GetCount()); // Some engines still need an explicit call (because they don't have // their own main thread). for (i = 0; i < m_Engines.GetCount(); i++) m_Engines[i].pEngine->SignalPause(); // Wait for the engines to stop for (i = 0; i < m_Engines.GetCount(); i++) { DWORD dwStart = sysGetTickCount(); m_Engines[i].pEngine->WaitForPause(); PauseTime[i] = sysGetTicksElapsed(dwStart); } // Wait for our threads to stop m_EventThread.WaitForPause(); m_ImportThread.WaitForPause(); // Now we ask all engines to mark their data in use for (i = 0; i < m_Engines.GetCount(); i++) { sTask = strPattern("Marking data: %s engine.", m_Engines[i].pEngine->GetName()); m_Engines[i].pEngine->Mark(); } // Now we mark our own structures sTask = STR_MARKING_MNEMOSYNTH; m_MnemosynthDb.Mark(); sTask = STR_MARKING_EVENT_THREAD; m_EventThread.Mark(); sTask = STR_MARKING_IMPORT_THREAD; m_ImportThread.Mark(); // Now we sweep all unused sTask = STR_MARK_AND_SWEEP; DWORD dwSweepStart = sysGetTickCount(); CDatum::MarkAndSweep(); DWORD dwSweepTime = sysGetTickCount() - dwSweepStart; sTask = NULL_STR; // Now we start all engines up again m_PauseEvent.Reset(); m_RunEvent.Set(); // If garbage collection took too long, then we need to log it. DWORD dwTime = sysGetTickCount() - dwStart; if (dwTime >= 500) { // Log each engine that took too long for (i = 0; i < m_Engines.GetCount(); i++) if (PauseTime[i] >= 500) Log(MSG_LOG_INFO, strPattern(STR_ENGINE_PAUSE_TIME, m_Engines[i].pEngine->GetName(), PauseTime[i] / 1000, (PauseTime[i] % 1000) / 10)); // Log overall time Log(MSG_LOG_INFO, strPattern(STR_GARBAGE_COLLECTION, dwTime / 1000, (dwTime % 1000) / 10, dwSweepTime / 1000, (dwSweepTime % 1000) / 10)); } } catch (...) { if (sTask.IsEmpty()) CriticalError(ERR_CRASH_IN_COLLECT_GARBAGE); else CriticalError(strPattern("CRASH: %s", sTask)); } }
void CEsperEngine::ProcessMessage (const SArchonMessage &Msg, CHexeSecurityCtx *pSecurityCtx) // ProcessMessage // // Processes messages { try { DWORD dwStartTime = sysGetTickCount(); // Arc.fileMsg if (strEquals(Msg.sMsg, MSG_ARC_FILE_MSG)) { SArchonMessage NewMsg; CInterprocessMessageQueue::DecodeFileMsg(Msg, &NewMsg); SendMessage(NewMsg); } // Arc.getStatus else if (strEquals(Msg.sMsg, MSG_ARC_GET_STATUS)) MsgGetStatus(Msg, pSecurityCtx); // Arc.housekeeping else if (strEquals(Msg.sMsg, MSG_ARC_HOUSEKEEPING)) MsgHousekeeping(Msg, pSecurityCtx); // Arc.sandboxMsg else if (strEquals(Msg.sMsg, MSG_ARC_SANDBOX_MSG)) { SArchonMessage SandboxMsg; CHexeSecurityCtx SecurityCtx; SandboxMsg.sMsg = Msg.dPayload.GetElement(0); SandboxMsg.sReplyAddr = Msg.sReplyAddr; SandboxMsg.dwTicket = Msg.dwTicket; SandboxMsg.dPayload = Msg.dPayload.GetElement(1); SecurityCtx.Init(Msg.dPayload.GetElement(2)); return ProcessMessage(SandboxMsg, &SecurityCtx); } // Esper messages else if (strEquals(Msg.sMsg, MSG_ESPER_HTTP)) MsgEsperHTTP(Msg); else if (strEquals(Msg.sMsg, MSG_ESPER_GET_USAGE_HISTORY)) MsgEsperGetUsageHistory(Msg, pSecurityCtx); // Else, unhandled message else { CString sError = strPattern(ERR_INVALID_MSG, Msg.sMsg); SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, sError, Msg); m_pProcess->Log(MSG_LOG_ERROR, sError); } DWORD dwTime = sysGetTicksElapsed(dwStartTime); if (dwTime >= 1000) Log(MSG_LOG_INFO, strPattern(ERR_MSG_TIMING, Msg.sMsg, dwTime)); } catch (...) { m_pProcess->Log(MSG_LOG_ERROR, strPattern(ERR_CRASH_MSG, Msg.sMsg)); SendMessageReplyError(MSG_ERROR_UNABLE_TO_COMPLY, ERR_INTERNAL_SERVER_ERROR, Msg); } }