//telo provadeciho vlakna procesu DWORD CProcess::Start() { Run(); // popis aktivnich fazi procesu // po jejich vykonani: CProcess* next; if (event != NULL) // pokud ma proces zaznam o udalosti { next=NextEv(); event->Out(); delete(event); // odstrani jej event = NULL; if (next!=NULL) // v SQS je zaznam o dalsim procesu // tady nekde prerusit pri krokovani next->Resume(); // aktivuj tento proces } terminated = true; // oznac proces za ukonceny return 0; // a ukonci proceduru vlakna }
void CJobObject::Suspend() { CMutex::CEnter MutexEnter(m_Mutex); map<DWORD, int> ErrorProcesses; map<DWORD, int>::iterator ErrorProcess; map<DWORD, BOOL> Processes; map<DWORD, BOOL>::iterator CurrentProcess; map<DWORD, CProcess*>::iterator OldProcess; BOOL bNewProcesses; // Clear all Threads contained in the m_Threads member for (OldProcess = m_Processes.begin(); OldProcess != m_Processes.end(); OldProcess++) { delete OldProcess->second; } m_Processes.clear(); // A) // Seach all threads which belong to this process and suspend them. To do this we create // a snapshot and suspend all threads contained in the snapshot. // Between A1 and A2 it is possible that new threads will be created. This makes it necessary to // create a new snapshot and to suspend all new threads which we not suspended in a previous // iteration. bNewProcesses = TRUE; while (bNewProcesses) { PJOBOBJECT_BASIC_PROCESS_ID_LIST pPidList; bNewProcesses = FALSE; pPidList = CreatePidList(); // A1 if (pPidList == NULL) { throw CCodineException(L"Pid List is NULL", __FILE__, __LINE__); } else { for (int i = 0; i < pPidList->NumberOfProcessIdsInList; i++) { if (m_Processes.find(pPidList->ProcessIdList[i]) == m_Processes.end()) { CProcess *NewProcess = NULL; try { NewProcess = new CProcess(pPidList->ProcessIdList[i]); NewProcess->Suspend(); m_Processes[pPidList->ProcessIdList[i]] = NewProcess; Processes[pPidList->ProcessIdList[i]] = true; bNewProcesses = TRUE; } catch (CCodineException& ex) { ErrorProcess = ErrorProcesses.find(pPidList->ProcessIdList[i]); if (ErrorProcess == ErrorProcesses.end() || (ErrorProcess != ErrorProcesses.end() && ErrorProcess->second < 3)) { // Possible reasons for the exception // * We didn't get a handle // - Thread exited // * Thread belongs to a different process // (no access) // - Thread exited and another process created // a thread with the same id between A1 and A2 // // => we try it once more -> the next snapshot won't // contain the current thread CTrace::Print(CTrace::Layer::TEST, L"Catched Exception during suspended" L" for thread %ld", pPidList->ProcessIdList[i]); ErrorProcesses[pPidList->ProcessIdList[i]]++; bNewProcesses = TRUE; } else { // If we get an error three times for the same thread // then we will assume that this thread belongs really // to this process // // => we could not solve the problem => ERROR throw ex; } } } } // A2 } DestroyPidList(); } // B // Between A and B we created a map of suspended threads (Threads) // but we can not be sure that all these threads belong to this process // (=> recycling of thread id's). It is possible, that we suspended // threads of foreign processes!. Now we will set pair.second to false // for all threads which belong to the current process { PJOBOBJECT_BASIC_PROCESS_ID_LIST pPidList; int i; pPidList = CreatePidList(); if (pPidList == NULL) { throw CCodineException(L"Pid List is NULL", __FILE__, __LINE__); } else { try { for (i = 0; i < pPidList->NumberOfProcessIdsInList; i++) { CurrentProcess = Processes.find(pPidList->ProcessIdList[i]); if (CurrentProcess == Processes.end()) { // If we get a new thread id here, then someone else // created a new thread for this process (CreateRemoteThread()) CTrace::Print(CTrace::Layer::TEST, L"Unexpected new thread %ld", pPidList->ProcessIdList[i]); throw CCodineException(L"", __FILE__, __LINE__); } else { CurrentProcess->second = FALSE; } } } catch (CCodineException& ex) { map<DWORD, CProcess*>::iterator TheProcess; // If we come here then we will rollback previous activities // Therefore we have to resume all threads contained in Threads for (TheProcess = m_Processes.begin(); TheProcess != m_Processes.end(); TheProcess++) { try { (*TheProcess).second->Resume(); } catch (CCodineException&) { ; } } throw ex; } } DestroyPidList(); } // C // Between B and C we set pair.second to false for all threads // which belong to the current process // Now we have to resume the remaining threads // We will also add the suspended threads of this process to // the member m_Threads. try { // Resume and copy for (CurrentProcess = Processes.begin(); CurrentProcess != Processes.end(); CurrentProcess++) { if (CurrentProcess->second == TRUE) { CProcess *ForeignProcess = m_Processes[CurrentProcess->first]; ForeignProcess->Resume(); m_Processes.erase(CurrentProcess->first); CTrace::Print(CTrace::Layer::TEST, L"Resumed foreign thread %ld", CurrentProcess->first); break; } } } catch (CCodineException& ex) { // What can we do here? throw ex; } }