Пример #1
0
PJOBOBJECT_BASIC_PROCESS_ID_LIST CJobObject::CreatePidList() const{
   DWORD dwMaxEntries = 8;
   JOBOBJECT_BASIC_PROCESS_ID_LIST *Structure;


   DestroyPidList();
   do {
      BOOL bRet;

      if (m_dwBuffer) {
         dwMaxEntries *= 2;
         delete [] m_dwBuffer;
         m_dwBuffer = NULL;
      }
      m_dwBuffer = new DWORD[dwMaxEntries + 2];
      Structure = (JOBOBJECT_BASIC_PROCESS_ID_LIST*)m_dwBuffer;

      memset(m_dwBuffer, 0, sizeof(m_dwBuffer));
      bRet = QueryInformationJobObject(GetHandle(), JobObjectBasicProcessIdList, 
         m_dwBuffer, sizeof(DWORD) * (dwMaxEntries + 2), NULL);
      if (bRet == 0 && GetLastError() != ERROR_MORE_DATA) {
         delete [] m_dwBuffer;
         throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__);
      }
   } while (Structure->NumberOfAssignedProcesses > Structure->NumberOfProcessIdsInList);

   return Structure;
}
Пример #2
0
Файл: Job.cpp Проект: stden/IJE
LONGLONG Job::infoMemoryUsagePeak()
{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
    tryApi(_T("QueryInformationJobObject"),
        QueryInformationJobObject(hJob,JobObjectExtendedLimitInformation,&info,sizeof info,NULL) != 0);
    return info.PeakJobMemoryUsed;
}
Пример #3
0
bool WindowsJob::queryInformation(JOBOBJECTINFOCLASS informationClass,
        LPVOID lpInformation,
        DWORD cbInformationLength,
        LPDWORD lpReturnLength)
{
    return !!QueryInformationJobObject(jobHandle_, informationClass, lpInformation,
        cbInformationLength, lpReturnLength);
}
Пример #4
0
const JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION& CJobObject::GetExtendedUsageInfo() const{
   BOOL bRet;

   bRet = QueryInformationJobObject(GetHandle(), JobObjectBasicAndIoAccountingInformation,
      (PVOID) &m_UsageInfo, sizeof(JOBOBJECT_BASIC_AND_IO_ACCOUNTING_INFORMATION), NULL);
   if (bRet == 0) {
      throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__);
   }
   return m_UsageInfo;
}
Пример #5
0
const JOBOBJECT_EXTENDED_LIMIT_INFORMATION& CJobObject::GetExtendedLimit() const {
   BOOL bRet;

   bRet = QueryInformationJobObject(GetHandle(), JobObjectExtendedLimitInformation,
      (PVOID) &m_Limit, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION), NULL);
   if (bRet == 0) {
      throw CCodineException(CError::GetErrorMessage(GetLastError()), __FILE__, __LINE__);
   }
   return m_Limit;
}
Пример #6
0
DWORD JobbedProcessManager::ShockerProc() {
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION extLimit;
	LARGE_INTEGER qpc;
	DWORD result;
	
	do {
		QueryPerformanceCounter(&qpc);
		execution_time = (qpc.QuadPart - liStart.QuadPart) * qpc_freq;
		if (time_limit && execution_time > time_limit) {
			TerminateProcess(hProcess, 0xDEADBEEF);
			tle_ = true;
			WaitForSingleObject(hProcess, INFINITE);
		}
		QueryInformationJobObject(hJob, JobObjectExtendedLimitInformation, &extLimit, sizeof extLimit, nullptr);
		memory_ = extLimit.PeakJobMemoryUsed;
		mle_ |= memory_limit && memory_ > memory_limit;
		Sleep(100);
		result = WaitForSingleObject(hProcess, 0);
	} while (!terminate_shocker && result == WAIT_TIMEOUT);
	return 0;
}
Пример #7
0
BOOL ProcessJob()
{
	BOOL foundProblem = FALSE;

	DWORD jobProcessStructSize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + sizeof(ULONG_PTR) * 1024;
	JOBOBJECT_BASIC_PROCESS_ID_LIST* jobProcessIdList = static_cast<JOBOBJECT_BASIC_PROCESS_ID_LIST*>(malloc(jobProcessStructSize));

	if (jobProcessIdList) {

		SecureZeroMemory(jobProcessIdList, jobProcessStructSize);

		jobProcessIdList->NumberOfProcessIdsInList = 1024;

		if (QueryInformationJobObject(NULL, JobObjectBasicProcessIdList, jobProcessIdList, jobProcessStructSize, NULL))
		{
			int ok_processes = 0;
			for (DWORD i = 0; i < jobProcessIdList->NumberOfAssignedProcesses; i++)
			{
				ULONG_PTR processId = jobProcessIdList->ProcessIdList[i];

				// is this the current process? if so that's ok
				if (processId == (ULONG_PTR)GetCurrentProcessId())
				{
					ok_processes++;
				}
				else
				{

					// find the process name for this job process
					HANDLE hJobProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, (DWORD)processId);
					if (hJobProcess != NULL)
					{
						const int processNameBufferSize = 4096;
						LPTSTR processName = static_cast<LPTSTR>(malloc(sizeof(TCHAR) * processNameBufferSize));
						if (processName) {
							SecureZeroMemory(processName, sizeof(TCHAR) * processNameBufferSize);

							if (GetProcessImageFileName(hJobProcess, processName, processNameBufferSize) > 0)
							{
								String pnStr(processName);

								// ignore conhost.exe (this hosts the al-khaser executable in a console)
								if (pnStr.find(String(L"\\Windows\\System32\\conhost.exe")) != std::string::npos)
								{
									ok_processes++;
								}
							}

							free(processName);
						}
						CloseHandle(hJobProcess);
					}
				}
			}

			// if we found other processes in the job other than the current process and conhost, report a problem
			foundProblem = ok_processes != jobProcessIdList->NumberOfAssignedProcesses;
		}

		free(jobProcessIdList);
	}
	return foundProblem;
}
Пример #8
0
/**
 * @brief
 * Internal session memory usage decoding routine.
 * Accepts a job pointer.  Returns the sum of all memory
 * consumed for all tasks executed by the job, in kilo bytes.
 *
 * NOTE: To retrieve a handle to any process in the system,
 *       the calling process should have a privilege "SeDebugPrivilege".
 *       A Win32 API OpenProcess() can be used in a calling process
 *       to obtain any desired process handle in the system.
 *
 *       In PBS, ena_privilege() function can be used to enable
 *       SeDebugPrivilege for calling process. For pbs_mom process,
 *       ena_privilege() has been used in it's main_thread() function.
 *
 * @param[in]	pjob - pointer to job
 *
 * @return      u_Long
 * @retval      0 - failure
 * @retval      memory usage of all the processes of a job - failure
 */
static u_Long
mem_sum(job *pjob)
{
	u_Long			mem = 0;
	int			nps = 0;
	DWORD			i;
	HANDLE			hProcess;
	DWORD			pidlistsize;
	DWORD			nwspages;
	SYSTEM_INFO		si;
	PJOBOBJECT_BASIC_PROCESS_ID_LIST	pProcessList;
	JOBOBJECT_BASIC_ACCOUNTING_INFORMATION	ji;
	pbs_task                *ptask = NULL;
	BOOL                    is_process_in_job = FALSE;

	/* Get the system info */
	GetSystemInfo(&si);

	/* Get the number of processes embedded in the job */
	if (pjob->ji_hJob != NULL &&
		QueryInformationJobObject(pjob->ji_hJob,
		JobObjectBasicAccountingInformation,
		&ji, sizeof(ji), NULL)) {
		nps = ji.TotalProcesses;
	}

	if (nps == 0) {
		pjob->ji_flags |= MOM_NO_PROC;
		return 0;
	}


	/* Compute the size of pid list */
	pidlistsize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +
		(nps-1) * sizeof(DWORD);

	pProcessList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) malloc(pidlistsize);
	if (pProcessList == NULL) {
		log_err(-1, "mem_sum:", "memory allocation failed");
		return (0);
	}

	pProcessList->NumberOfAssignedProcesses = nps;
	pProcessList->NumberOfProcessIdsInList = 0;

	/* Get the pid list */
	if (pjob->ji_hJob != NULL)
		QueryInformationJobObject(pjob->ji_hJob,
			JobObjectBasicProcessIdList,
			pProcessList, pidlistsize, NULL);

	/*
	 * Traverse through each process and find the
	 * memory used by that process during its execution.
	 */
	for (i = 0; i < (pProcessList->NumberOfProcessIdsInList); i++) {
		hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
			PROCESS_VM_READ,
			FALSE, pProcessList->ProcessIdList[i]);
		if (hProcess != NULL) {
			(void)QueryWorkingSet(hProcess, &nwspages, sizeof(nwspages));
			mem += nwspages * (si.dwPageSize >> 10);
			CloseHandle(hProcess);

		}
	}
Пример #9
0
/**
 *
 * @brief
 *	Is the process part of Windows job object.
 *
 * @param[in]	hProc - handle to process
 * @param[in]	hJob - handle to job
 * @param[out]	p_is_process_in_job - pointer to store a bool value indicating
 *              whether the process is part of the Windows job object
 *
 * @return      void
 **/
void
IsProcessInJob(HANDLE hProc, HANDLE hJob, BOOL *p_is_process_in_job)
{
	int			                nps = 0;
	DWORD			                i = 0;
	DWORD			                pidlistsize = 0;
	DWORD                                   pid = 0;
	PJOBOBJECT_BASIC_PROCESS_ID_LIST	pProcessList;
	JOBOBJECT_BASIC_ACCOUNTING_INFORMATION	ji;

	if (hJob == INVALID_HANDLE_VALUE || hJob == NULL
		|| hProc == INVALID_HANDLE_VALUE || hProc == NULL) {
		*p_is_process_in_job = FALSE;
		return;
	}

	/* Get the number of processes embedded in the job */
	if (QueryInformationJobObject(hJob,
		JobObjectBasicAccountingInformation,
		&ji, sizeof(ji), NULL)) {
		nps = ji.TotalProcesses;
	}

	if (nps == 0) {
		*p_is_process_in_job = FALSE;
		return;
	}

	/* Compute the size of pid list */
	pidlistsize = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) +
		(nps-1) * sizeof(DWORD);

	pProcessList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST) malloc(pidlistsize);
	if (pProcessList == NULL) {
		*p_is_process_in_job = FALSE;
		return;
	}

	pProcessList->NumberOfAssignedProcesses = nps;
	pProcessList->NumberOfProcessIdsInList = 0;

	/* Get the pid list */
	if (FALSE == QueryInformationJobObject(hJob,
		JobObjectBasicProcessIdList,
		pProcessList, pidlistsize, NULL))
		return;

	/*
	 * Traverse through each process and find the
	 * memory used by that process during its execution.
	 */
	pid = GetProcessId(hProc);
	for (i = 0; i < (pProcessList->NumberOfProcessIdsInList); i++) {
		if (pProcessList->ProcessIdList[i] == pid) {
			free(pProcessList);
			*p_is_process_in_job = TRUE;
			return;
		}
	}
	free(pProcessList);
	*p_is_process_in_job = FALSE;
	return;
}
HRESULT CNodeApplicationManager::Initialize(IHttpContext* context)
{
	HRESULT hr;
	BOOL isInJob, createJob;
	JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo;

	if (this->initialized)
	{
		return S_OK;
	}

	ErrorIf(NULL == (this->eventProvider = new CNodeEventProvider()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->eventProvider->Initialize());
	ErrorIf(NULL != this->asyncManager, ERROR_INVALID_OPERATION);
	ErrorIf(NULL == (this->asyncManager = new CAsyncManager()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->asyncManager->Initialize(context));
	ErrorIf(NULL == (this->fileWatcher = new CFileWatcher()), ERROR_NOT_ENOUGH_MEMORY);
	CheckError(this->fileWatcher->Initialize(context));

	// determine whether node processes should be created in a new job object
	// or whether current job object is adequate; the goal is to kill node processes when
	// the IIS worker process is killed while preserving current job limits, if any
	
	ErrorIf(!IsProcessInJob(GetCurrentProcess(), NULL, &isInJob), HRESULT_FROM_WIN32(GetLastError()));
	if (!isInJob)
	{
		createJob = TRUE;
	}
	else
	{
		ErrorIf(!QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo, NULL), 
			HRESULT_FROM_WIN32(GetLastError()));

        if (jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK )
        {
            createJob = TRUE;
        }
        else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE )
        {
            createJob = FALSE;
        }
        else if(jobInfo.BasicLimitInformation.LimitFlags & JOB_OBJECT_LIMIT_BREAKAWAY_OK )
        {
            createJob = TRUE;
			this->breakAwayFromJobObject = TRUE;
        }
        else
        {
            createJob = TRUE;
        }
	}

	if (createJob)
	{
		ErrorIf(NULL == (this->jobObject = CreateJobObject(NULL, NULL)), HRESULT_FROM_WIN32(GetLastError()));
		RtlZeroMemory(&jobInfo, sizeof jobInfo);
		jobInfo.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
		ErrorIf(!SetInformationJobObject(this->jobObject, JobObjectExtendedLimitInformation, &jobInfo, sizeof jobInfo), 
			HRESULT_FROM_WIN32(GetLastError()));
	}

	this->initialized = TRUE;

	this->GetEventProvider()->Log(L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO);

	return S_OK;
Error:

	this->GetEventProvider()->Log(L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR);

	if (NULL != this->asyncManager)
	{
		delete this->asyncManager;
		this->asyncManager = NULL;
	}

	if (NULL != this->jobObject)
	{
		CloseHandle(this->jobObject);
		this->jobObject = NULL;
	}

	if (NULL != this->fileWatcher)
	{
		delete this->fileWatcher;
		this->fileWatcher = NULL;
	}

	return hr;
}
Пример #11
0
static void
run_child(wchar_t * cmdline)
{
    HANDLE job;
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
    DWORD rc;
    BOOL ok;
    STARTUPINFOW si;
    PROCESS_INFORMATION pi;

#if defined(_WINDOWS)
    // When explorer launches a Windows (GUI) application, it displays
    // the "app starting" (the "pointer + hourglass") cursor for a number
    // of seconds, or until the app does something UI-ish (eg, creating a
    // window, or fetching a message).  As this launcher doesn't do this
    // directly, that cursor remains even after the child process does these
    // things.  We avoid that by doing a simple post+get message.
    // See http://bugs.python.org/issue17290 and
    // https://bitbucket.org/vinay.sajip/pylauncher/issue/20/busy-cursor-for-a-long-time-when-running
    MSG msg;

    PostMessage(0, 0, 0, 0);
    GetMessage(&msg, 0, 0, 0);
#endif

    job = CreateJobObject(NULL, NULL);
    ok = QueryInformationJobObject(job, JobObjectExtendedLimitInformation,
                                  &info, sizeof(info), &rc);
    if (!ok || (rc != sizeof(info)) || !job)
        error(RC_CREATE_PROCESS, L"Job information querying failed");
    info.BasicLimitInformation.LimitFlags |= JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
                                             JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    ok = SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info,
                                 sizeof(info));
    if (!ok)
        error(RC_CREATE_PROCESS, L"Job information setting failed");
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);
    ok = safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE), &si.hStdInput);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stdin duplication failed");
    ok = safe_duplicate_handle(GetStdHandle(STD_OUTPUT_HANDLE), &si.hStdOutput);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stdout duplication failed");
    ok = safe_duplicate_handle(GetStdHandle(STD_ERROR_HANDLE), &si.hStdError);
    if (!ok)
        error(RC_NO_STD_HANDLES, L"stderr duplication failed");

    ok = SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
    if (!ok)
        error(RC_CREATE_PROCESS, L"control handler setting failed");

    si.dwFlags = STARTF_USESTDHANDLES;
    ok = CreateProcessW(NULL, cmdline, NULL, NULL, TRUE,
                        0, NULL, NULL, &si, &pi);
    if (!ok)
        error(RC_CREATE_PROCESS, L"Unable to create process using '%ls'", cmdline);
    AssignProcessToJobObject(job, pi.hProcess);
    CloseHandle(pi.hThread);
    WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);
    ok = GetExitCodeProcess(pi.hProcess, &rc);
    if (!ok)
        error(RC_CREATE_PROCESS, L"Failed to get exit code of process");
    exit(rc);
}
Пример #12
0
/*! Iterates over all the threads associated with this job (as determined by
 * mJobHandle), and runs the given callback function on them. The callback
 * function need not close the handle to the thread.
 *
 * \param callback The callback function to run on each thread.
 *
 * \par A few notes on the necessity and implementation of IterateThreads:
 * Before going to far into this function, you must realize that as much as one
 * may hope to the contrary, windows has no concept of mass process management.
 * If you want to do something to multiple processes or threads, windows
 * provides a few mediocre iteration methods, but beyond that, you're on your
 * own to find the processes and/or threads and work with them one at a time.
 * The following function was written for that exact purpose, it searches
 * through the list of all threads present in the entire system, finds the ones
 * whose parent process is part of the job object and runs the given callback
 * function on the thread.
 *
 * \par
 * The reason this is written on the thread level as opposed to the process
 * level (which would have been much easier), is because windows has no concept
 * of suspending a process, it can only suspend threads. Since the ability to
 * suspend and resume jobs was something that I wanted in GamessQ, it has to be
 * done on the tread level. When it comes to terminating processes, simply
 * terminating all their threads works just as well as terminating the process
 * via windows TerminatProcess function.
 *
 * \note
 * As clumsy as this method may seem, and as much as you may think and hope
 * that there MUST be a better way to do it, there really isn't. So far as I
 * have been able to find (and I searched for a while) this is the cleanest,
 * most efficient way to handle windows processes and threads in mass.
 *
 * \sa mJobHandle
 */
bool WindowsJob::IterateThreads(bool (*callback)(HANDLE))
{
	// We'll need this for later
	bool retVal = true;

	// get all the process ids for the job object
	JOBOBJECT_BASIC_PROCESS_ID_LIST *info;
	int num = mNumProcessors + 15; // make sure there's enough space
	int size = sizeof(JOBOBJECT_BASIC_PROCESS_ID_LIST) + num * sizeof(DWORD);
	info = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)malloc(size);
	ZeroMemory(info, size);
	info->NumberOfAssignedProcesses = num;
	if (! QueryInformationJobObject(mJobHandle, JobObjectBasicProcessIdList,
			info, size, NULL)) {
		LOG_ERROR("QueryInformationJobObject");
		return false;
	}
	num = info->NumberOfProcessIdsInList;

	// get a thread snapshot
	HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
	THREADENTRY32 entry;
	ZeroMemory(&entry, sizeof(entry));
	entry.dwSize = sizeof(entry);
	if (! Thread32First(snapshot, &entry)) {
		LOG_ERROR("Thread32First");
		CloseHandle(snapshot);
		return false;
	}

	// iterate through all the threads in the system.
	bool more = true;
	while (more) {
		// search through the job ids
		for (int i = 0; i < num; i ++) {
			// if this thread's parent is in the list, run the callback on it
			if (entry.th32OwnerProcessID == info->ProcessIdList[i]) {
				HANDLE threadHandle = OpenThread(THREAD_TERMINATE |
						THREAD_SUSPEND_RESUME , false, entry.th32ThreadID);
				if (! threadHandle) {
					LOG_ERROR("OpenThread");
				} else {
					retVal = retVal && callback(threadHandle);
				}
				CloseHandle(threadHandle);
				break;
			}
		}

		// get the next thread, and make sure it's valid
		ZeroMemory(&entry, sizeof(entry));
		entry.dwSize = sizeof(entry);
		if (! Thread32Next(snapshot, &entry)) {
			if (GetLastError() == ERROR_NO_MORE_FILES) {
				more = false;
			} else {
				LOG_ERROR("Thread32Next");
				free(info);
				CloseHandle(snapshot);
				return false;
			}
		}
	}

	// clean up
	free(info);
	CloseHandle(snapshot);
	return retVal;
}