// TODO: double check and maybe change order of parameters public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable<string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; using (var restrictedProcess = new RestrictedProcess(fileName, workingDirectory, executionArguments, Math.Max(4096, (inputData.Length * 2) + 4))) { // Write to standard input using another thread restrictedProcess.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure if (!restrictedProcess.IsDisposed) { // ReSharper disable once AccessToDisposedClosure restrictedProcess.StandardInput.FlushAsync().ContinueWith( delegate { restrictedProcess.StandardInput.Close(); }); } }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = restrictedProcess.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = restrictedProcess.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = restrictedProcess.PeakWorkingSetSize; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Start the process restrictedProcess.Start(timeLimit, memoryLimit); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = restrictedProcess.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { restrictedProcess.Kill(); result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(restrictedProcess.HasExited, "Restricted process didn't exit!"); // Report exit code and total process working time result.ExitCode = restrictedProcess.ExitCode; result.TimeWorked = restrictedProcess.ExitTime - restrictedProcess.StartTime; result.PrivilegedProcessorTime = restrictedProcess.PrivilegedProcessorTime; result.UserProcessorTime = restrictedProcess.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return result; }
public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable <string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; var processStartInfo = new ProcessStartInfo(fileName) { Arguments = executionArguments == null ? string.Empty : string.Join(" ", executionArguments), WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, WorkingDirectory = workingDirectory }; using (var process = System.Diagnostics.Process.Start(processStartInfo)) { if (process == null) { throw new Exception($"Could not start process: {fileName}!"); } process.PriorityClass = ProcessPriorityClass.High; // Write to standard input using another thread process.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure process.StandardInput.FlushAsync().ContinueWith( delegate { process.StandardInput.Close(); }); }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = process.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = process.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure if (process.HasExited) { return; } // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = process.PeakWorkingSet64; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = process.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { // Double check if the process has exited before killing it if (!process.HasExited) { process.Kill(); // Approach: https://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill(v=vs.110).aspx#Anchor_2 process.WaitForExit(); } result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(process.HasExited, "Standard process didn't exit!"); // Report exit code and total process working time result.ExitCode = process.ExitCode; result.TimeWorked = process.ExitTime - process.StartTime; result.PrivilegedProcessorTime = process.PrivilegedProcessorTime; result.UserProcessorTime = process.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return(result); }
public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable<string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; var processStartInfo = new ProcessStartInfo(fileName) { Arguments = executionArguments == null ? string.Empty : string.Join(" ", executionArguments), WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, WorkingDirectory = workingDirectory }; using (var process = System.Diagnostics.Process.Start(processStartInfo)) { if (process == null) { throw new Exception($"Could not start process: {fileName}!"); } process.PriorityClass = ProcessPriorityClass.High; // Write to standard input using another thread process.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure process.StandardInput.FlushAsync().ContinueWith( delegate { process.StandardInput.Close(); }); }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = process.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = process.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure if (process.HasExited) { return; } // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = process.PeakWorkingSet64; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = process.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { // Double check if the process has exited before killing it if (!process.HasExited) { process.Kill(); // Approach: https://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill(v=vs.110).aspx#Anchor_2 process.WaitForExit(); } result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(process.HasExited, "Standard process didn't exit!"); // Report exit code and total process working time result.ExitCode = process.ExitCode; result.TimeWorked = process.ExitTime - process.StartTime; result.PrivilegedProcessorTime = process.PrivilegedProcessorTime; result.UserProcessorTime = process.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return result; }
// TODO: double check and maybe change order of parameters public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable <string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; using (var restrictedProcess = new RestrictedProcess(fileName, workingDirectory, executionArguments, Math.Max(4096, (inputData.Length * 2) + 4))) { // Write to standard input using another thread restrictedProcess.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure if (!restrictedProcess.IsDisposed) { // ReSharper disable once AccessToDisposedClosure restrictedProcess.StandardInput.FlushAsync().ContinueWith( delegate { restrictedProcess.StandardInput.Close(); }); } }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = restrictedProcess.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = restrictedProcess.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = restrictedProcess.PeakWorkingSetSize; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Start the process restrictedProcess.Start(timeLimit, memoryLimit); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = restrictedProcess.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { restrictedProcess.Kill(); result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(restrictedProcess.HasExited, "Restricted process didn't exit!"); // Report exit code and total process working time result.ExitCode = restrictedProcess.ExitCode; result.TimeWorked = restrictedProcess.ExitTime - restrictedProcess.StartTime; result.PrivilegedProcessorTime = restrictedProcess.PrivilegedProcessorTime; result.UserProcessorTime = restrictedProcess.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return(result); }