Coder Social home page Coder Social logo

williamb1024 / fs-processes Goto Github PK

View Code? Open in Web Editor NEW
10.0 2.0 4.0 687 KB

A library for Windows Processes and JobObjects

Home Page: https://williamb1024.github.io/fs-processes/

License: MIT License

C# 100.00%
csharp windows process jobobject async-await

fs-processes's Issues

JobObject.SetLimits fails if CpuRate is not set

Repro:

using (var jobObject = new JobObject())
{
    var jobLimits = new JobLimits();
    jobLimits.Options = JobOptions.TerminateProcessesWhenJobClosed;
    jobLimits.ActiveProcesses = 1;
    jobObject.SetLimits(jobLimits);
}

Output:

Unhandled Exception:
System.ComponentModel.Win32Exception (0x80004005): The parameter is incorrect
   at Fs.Processes.JobObjects.JobObject.SetLimits(JobLimits& newLimits)

Cause:

Looks like SetInformationJobObject fails if JOBOBJECT_CPU_RATE_CONTROL_INFORMATION.ControlFlags or .CpuRate is 0, which is the default value for both. This doc points out that CpuRate must not be 0, and for ControlFlags:

The scheduling policy for CPU rate control. This member can be one of the following values.
(continues to list flag values; 0 is not in the list)

However judging by a second repro, this issue only manifests if CPU limits have not been set before. If they have, the following code seems to works to disable the previous limits:

using (var jobObject = new JobObject())
{
    var firstLimits = new JobLimits();
    firstLimits.CpuRate = new CpuRateLimit(20, false);
    jobObject.SetLimits(firstLimits);

    var jobLimits = new JobLimits();
    jobLimits.Options = JobOptions.TerminateProcessesWhenJobClosed;
    jobLimits.ActiveProcesses = 1;
    jobObject.SetLimits(jobLimits);
}

Fix:

CPU limits should only be set if they contain any values, or if they are currently enabled and should be disabled. Pseudo-code:

if (newCpuLimits.ControlFlags != 0 || currentCpuLimits.ControlFlags != 0)
    SetInformationJobObject(...);

ObjectDisposedException

Hello. Thanks for this awesome library. It's very useful!

I've just integrated it into my app and it works most of the time, but sometimes I get this exception:

System.ObjectDisposedException: Safe handle has been closed.
Object name: 'SafeHandle'.
   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)
   at Fs.Processes.JobObjects.JobObject.Notification(JobObjectMessage notifyMessage, IntPtr notifyData)
   at Fs.Processes.JobObjects.JobObjectCompletionPort.IoCompletionPort.IoCompletionPortReader()
--- End of stack trace from previous location ---
   at Fs.Processes.JobObjects.JobObjectCompletionPort.IoCompletionPort.<>c.<IoCompletionPortReader>b__6_0(Object edi)
   at System.Threading.ThreadPoolWorkQueue.Dispatch()

Do you have an idea what's wrong? Shouldn't I dispose the JobObject?

Here is my code:

private async Task<ProcessRunner> Start() {
	Console.WriteLine($"starting process. {this.ToString()}");
	await Task.Run(async () => {
		try {
			using var jobObject = new JobObject();
			var startInfo = new Fs.Processes.CreateProcessInfo() {
				FileName = executable,
				WorkingDirectory = workingDir.FullName,
				Arguments = string.Join(" ", arguments),
				RedirectStandardOutput = redirectOutput,
				RedirectStandardError = redirectError,
				WindowShow = Fs.Processes.WindowShow.Hidden
			};

			using var process = StartProcess(jobObject, startInfo);

			Task outTask = null;
			Task errTask = null;
			if (redirectOutput) {
				process.OutputDataReceived += (s, d) => { if (d.Data != null) stdOutSb.AppendLine(d.Data); };
				outTask = process.BeginReadingStandardOutputAsync();
			}
			if (redirectError) {
				process.ErrorDataReceived += (s, d) => { if (d.Data != null) stdErrSb.AppendLine(d.Data); };
				errTask = process.BeginReadingStandardErrorAsync();
			}
			if (outTask != null) await outTask;
			if (errTask != null) await errTask;

			await process.Exited;
			ExitCode = process.ExitCode ?? -1;
			
		} catch (Exception e) {
			throw new ProcessRunnerException($"An exception occurred while starting a process: {this.ToString()}", e);
		}
	});
	return this;
}

private Fs.Processes.Process StartProcess(JobObject jobObjects, Fs.Processes.CreateProcessInfo startInfo) {
	if (maxMemoryMb.HasValue || maxCpuPercent.HasValue) {
		var jobLimits = new JobLimits();
		if (maxMemoryMb.HasValue) {
			jobLimits.MaximumProcessMemory = maxMemoryMb.Value * 1024 * 1024;
		}
		if (maxCpuPercent.HasValue) {
			jobLimits.CpuRate = new CpuRateLimit(maxCpuPercent.Value, true);
		}
		jobObjects.SetLimits(jobLimits);
		return jobObjects.CreateProcess(startInfo);
	} else {
		return new Fs.Processes.Process(startInfo);
	}
}

I'd be grateful for any hints :).

Signed version?

First thank you so much for writing this nice bridge library! It's very easy to use!

However our project needs to be signed so could you publish a signed version of this?

Thank you!

State and direction of this project

Hi,

I recently found this project, and found its coverage of windows jobs very appealing. I've attempted to replace my old, minimal job object wrapper with this package, but ran into several problems.

I use job objects for browser testing. More specifically, in automated browser tests, I launch the browser in jobs configured to kill their processes when the job ends, so that there are no browser processes hanging around after the process running the tests, terminates. There is also the twist that sometimes I would like for the browser to not be killed along when the testing process terminates, so that I can interact with the browser. To do that, I give the jobs names, and attach to them from a separate application, which keeps the
jobs alive.

The issues that I ran into when I tried to replace my own wrapper with this one, are roughly the following:

First, opening a job by name fails. I made it work by changing two lines.

Then, I wanted to set the job setting/flag JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE that causes windows to kill processes in the job when the job ends. That caused the Selenium browser testing library to fail a moment later, claiming that the started process did not exist. Commenting out most of the job configuration code in JobObject.SetLimits made the problem go away. The job setup that I did at this point was nothing more than the following:

_windowsJobObject = JobObject.Open("MyJobName");
_windowsJobObject.SetLimits(new JobLimits() {  });

I would think that a job set up in that way should not put up much restriction for the processes that are assigned to it, but as mentioned it turned out otherwise.

The first problem (opening the named job) has a tiny fix, and I could easily make a PR for that. But the second problem probably requires more changes. I was considering making those changes, but the apparent complete lack of tests made me reconsider.

So my question is whether this project would be open to adressing these issues and getting some unit tests? If so, I might open some PRs.

OS: Windows 11
.NET version: 4.8
VS Version: VS 2022

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.