def is_in_job(self): try: if win32job.IsProcessInJob(self.get_ph(), 0): return 1 except: pass return 0
def _add_to_job_object(self): global _global_process_job_handle if _global_process_job_handle is not None: #This means that we are creating another process family - we'll all be in the same job return already_in_job = win32job.IsProcessInJob(win32api.GetCurrentProcess(), None) #Create a new job and put us in it before we create any children logger.debug("Creating job object and adding parent process to it") security_attrs = win32security.SECURITY_ATTRIBUTES() security_attrs.bInheritHandle = 0 _global_process_job_handle = win32job.CreateJobObject(security_attrs, self.get_job_object_name()) extended_info = win32job.QueryInformationJobObject(_global_process_job_handle, win32job.JobObjectExtendedLimitInformation) extended_info['BasicLimitInformation']['LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE win32job.SetInformationJobObject(_global_process_job_handle, win32job.JobObjectExtendedLimitInformation, extended_info) try: win32job.AssignProcessToJobObject(_global_process_job_handle, win32api.GetCurrentProcess()) except Exception as e: winv = sys.getwindowsversion() logger.error("Error raised during assignment of the current process to a new job object. " +\ "The process %s already in a job. " +\ "The windows version is %d.%d.\nError: %s", "is" if already_in_job else "is not", winv.major, winv.minor, _exception_str()) if already_in_job and not (winv.major >= 6 and winv.minor >= 2): raise JobObjectAssignError("On Windows versions older than Windows 8 / Windows Server 2012, ProcessFamily relies on the parent process NOT being in a job already", e, already_in_job) raise JobObjectAssignError("Error raised during assignment of the current process to a new job object.", e, already_in_job) logger.debug("Added to job object")
def get_response_object(self): if self.path.startswith('/injob'): return json.dumps(win32job.IsProcessInJob( win32api.GetCurrentProcess(), None), indent=3) if self.path.startswith('/job'): extended_info = win32job.QueryInformationJobObject( None, win32job.JobObjectExtendedLimitInformation) return json.dumps(extended_info, indent=3) if self.path.startswith('/close_file_and_delete_it'): try: if self.funkyserver._open_file_handle is not None: f = os.path.join(os.path.dirname(__file__), 'tmp', 'testfile.txt') logging.info("Closing test file handle") self.funkyserver._open_file_handle.close() self.funkyserver._open_file_handle = None assert os.path.exists(f) os.remove(f) assert not os.path.exists(f) return "OK" except Exception as e: logging.error( "Failed to close file handle and delete file: %s\n%s", e, _traceback_str()) return "FAIL" if self.path.startswith('/stop'): logging.info("Returning child_processes_terminated: %r", self.funkyserver.child_processes_terminated) return repr(self.funkyserver.child_processes_terminated) return "OK"
def SvcDoRun(self): if hasattr(sys, "frozen"): this_dir = os.path.dirname(win32api.GetModuleFileName(None)) else: this_dir = os.path.dirname(os.path.abspath(__file__)) # TODO: maybe it is better to run this in a job object too with open(os.path.join(this_dir, 'npm.log'), 'w') as npm_log: subprocess.check_call('npm install', cwd=this_dir, shell=True, stdin=None, stdout=npm_log, stderr=subprocess.STDOUT) security_attributes = win32security.SECURITY_ATTRIBUTES() security_attributes.bInheritHandle = True startup = win32process.STARTUPINFO() startup.dwFlags |= win32process.STARTF_USESTDHANDLES startup.hStdInput = None startup.hStdOutput = win32file.CreateFile( os.path.join(this_dir, "service_stderr.log"), win32file.GENERIC_WRITE, win32file.FILE_SHARE_READ, security_attributes, win32file.CREATE_ALWAYS, 0, None) startup.hStdError = win32file.CreateFile( os.path.join(this_dir, "service_stdout.log"), win32file.GENERIC_WRITE, win32file.FILE_SHARE_READ, security_attributes, win32file.CREATE_ALWAYS, 0, None) (hProcess, hThread, processId, threadId) = win32process.CreateProcess( None, r'"C:\Program Files\nodejs\node.exe" node_worker.js', None, None, True, win32process.CREATE_SUSPENDED | win32process.CREATE_BREAKAWAY_FROM_JOB, None, this_dir, startup) assert not win32job.IsProcessInJob(hProcess, None) self.hJob = win32job.CreateJobObject(None, "") extended_info = win32job.QueryInformationJobObject( self.hJob, win32job.JobObjectExtendedLimitInformation) extended_info['BasicLimitInformation'][ 'LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | win32job.JOB_OBJECT_LIMIT_BREAKAWAY_OK win32job.SetInformationJobObject( self.hJob, win32job.JobObjectExtendedLimitInformation, extended_info) win32job.AssignProcessToJobObject(self.hJob, hProcess) win32process.ResumeThread(hThread) win32api.CloseHandle(hThread) signalled = win32event.WaitForMultipleObjects( [self.hWaitStop, hProcess], False, win32event.INFINITE) if signalled == win32event.WAIT_OBJECT_0 + 1 and win32process.GetExitCodeProcess( hProcess) != 0: servicemanager.LogErrorMsg( self._svc_name_ + " process exited with non-zero status " + str(win32process.GetExitCodeProcess(hProcess))) win32api.CloseHandle(hProcess) win32api.CloseHandle(self.hJob) win32api.CloseHandle(self.hWaitStop) win32api.CloseHandle(startup.hStdOutput) win32api.CloseHandle(startup.hStdError)
def assign_job(hjob): global g_hjob hprocess = win32api.GetCurrentProcess() try: win32job.AssignProcessToJobObject(hjob, hprocess) g_hjob = hjob except win32job.error as e: if (e.winerror != winerror.ERROR_ACCESS_DENIED or sys.getwindowsversion() >= (6, 2) or not win32job.IsProcessInJob(hprocess, None)): raise warnings.warn('The process is already in a job. Nested jobs are not ' 'supported prior to Windows 8.')
def job(self) -> WIN32JOB: """Get the job associated with this process. Caches between calls for safety. Returns ------- WIN32JOB A Windows job which consists of one or more processes. In this case we just have the one process """ if not hasattr(self, "_job"): # First try to import stuff, an easy exception to catch and give good # information about try: import win32api import win32job import winerror except ModuleNotFoundError as e: raise ModuleNotFoundError(_win32_import_error_msg) from e # Here, we assign it to a windows "Job", whatever that is # If the process is already assigned to a job, then we have # to check if it's less than Windows 8 because apparently # nested jobs aren't supported there try: job = win32job.CreateJobObject(None, "") process = win32api.GetCurrentProcess() win32job.AssignProcessToJobObject(job, process) self._job = job except win32job.error as e: if (e.winerror != winerror.ERROR_ACCESS_DENIED or sys.getwindowsversion() >= (6, 2) # type: ignore or not win32job.IsProcessInJob(process, None)): raise e msg = ("The process is already in a job." " Nested jobs are not supported prior to Windows 8.") raise RuntimeError(msg) from e return self._job
job_info = win32job.QueryInformationJobObject( job_object, win32job.JobObjectExtendedLimitInformation) # Set up the job object so that closing the last handle to the job object # will terminate all associated processes and destroy the job object itself. job_info["BasicLimitInformation"]["LimitFlags"] |= \ win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE # Update the limits of the job object. win32job.SetInformationJobObject( job_object, win32job.JobObjectExtendedLimitInformation, job_info) return job_object # Don't create a job object if the current process is already inside one. if win32job.IsProcessInJob(win32process.GetCurrentProcess(), None): _JOB_OBJECT = None else: _JOB_OBJECT = _init_job_object() atexit.register(win32api.CloseHandle, _JOB_OBJECT) class Process(object): """Wrapper around subprocess.Popen class.""" # pylint: disable=protected-access def __init__(self, logger, args, env=None, env_vars=None): """Initialize the process with the specified logger, arguments, and environment.""" # Ensure that executable files that don't already have an
cad_job_driver = CADJobDriver(args.assembler, args.mesher, args.analyzer, args.mode) # cad_job_driver = CADJobDriver('ASSEMBLY_EXISTS', args.mesher, args.analyzer, args.mode, False) # cad_job_driver = CADJobDriver(args.assembler, args.mesher, args.analyzer, args.mode, False) if __name__ == '__main__': import win32api import win32job hProcess = win32api.GetCurrentProcess() def os_supports_nested_jobs(): "Nested jobs were introduced in Windows 8 and Windows Server 2012" return sys.getwindowsversion()[0:2] >= (6, 2) if not win32job.IsProcessInJob(hProcess, None) or os_supports_nested_jobs(): hJob = win32job.CreateJobObject(None, "") extended_info = win32job.QueryInformationJobObject( hJob, win32job.JobObjectExtendedLimitInformation) extended_info['BasicLimitInformation'][ 'LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | win32job.JOB_OBJECT_LIMIT_BREAKAWAY_OK win32job.SetInformationJobObject( hJob, win32job.JobObjectExtendedLimitInformation, extended_info) win32job.AssignProcessToJobObject(hJob, hProcess) # n.b. intentionally leak hJob. Otherwise, when running on Windows Server 2008R2 SP1, AssignProcessToJobObject closes hJob (try !handle # in windbg before and after), and we crash with invalid handle in CloseHandle on exit hJob.Detach() main()
command_line = "\"" + get_python_exe( ) + "\" scripts\simulate.py --tool Dymola" sa = win32security.SECURITY_ATTRIBUTES() sa.bInheritHandle = True startup = win32process.STARTUPINFO() startup.dwFlags += win32process.STARTF_USESTDHANDLES startup.hStdError = startup.hStdOutput = win32file.CreateFile( "test_dymola_output.txt", win32file.GENERIC_WRITE, 0, sa, win32file.CREATE_ALWAYS, win32file.FILE_ATTRIBUTE_NORMAL, None) startup.hStdInput = win32api.GetStdHandle(win32api.STD_INPUT_HANDLE) (hProcess, hThread, processId, threadId) = win32process.CreateProcess( None, command_line, None, None, True, win32process.CREATE_BREAKAWAY_FROM_JOB, None, None, startup) assert not win32job.IsProcessInJob(hProcess, None) hJob = win32job.CreateJobObject(None, "") extended_info = win32job.QueryInformationJobObject( hJob, win32job.JobObjectExtendedLimitInformation) extended_info['BasicLimitInformation'][ 'LimitFlags'] = win32job.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE win32job.SetInformationJobObject( hJob, win32job.JobObjectExtendedLimitInformation, extended_info) win32job.AssignProcessToJobObject(hJob, hProcess) status = win32event.WaitForSingleObject(hProcess, 45000) win32api.CloseHandle(startup.hStdError) if status == win32event.WAIT_TIMEOUT: print "Dymola timed out. Likely the license could not be acquired" sys.exit(2)