Esempio n. 1
0
        public static async Task KillTreeAsync(int pid, Log log, bool?diagnostics = true)
        {
            var pids = new List <int> ();

            GetChildrenPS(log, pids, pid);
            if (diagnostics == true)
            {
                log.WriteLine($"Pids to kill: {string.Join (", ", pids.Select ((v) => v.ToString ()).ToArray ())}");
                using (var ps = new Process()) {
                    log.WriteLine("Writing process list:");
                    ps.StartInfo.FileName  = "ps";
                    ps.StartInfo.Arguments = "-A -o pid,ruser,ppid,pgid,%cpu=%CPU,%mem=%MEM,flags=FLAGS,lstart,rss,vsz,tty,state,time,command";
                    await ps.RunAsync(log, true, TimeSpan.FromSeconds(5), diagnostics : false);
                }

                foreach (var diagnose_pid in pids)
                {
                    var template = Path.GetTempFileName();
                    try {
                        var commands = new StringBuilder();
                        using (var dbg = new Process()) {
                            commands.AppendLine($"process attach --pid {diagnose_pid}");
                            commands.AppendLine("thread list");
                            commands.AppendLine("thread backtrace all");
                            commands.AppendLine("detach");
                            commands.AppendLine("quit");
                            dbg.StartInfo.FileName  = "/usr/bin/lldb";
                            dbg.StartInfo.Arguments = $"--source {StringUtils.Quote (template)}";
                            File.WriteAllText(template, commands.ToString());

                            log.WriteLine($"Printing backtrace for pid={pid}");
                            await dbg.RunAsync(log, true, TimeSpan.FromSeconds(30), diagnostics : false);
                        }
                    } finally {
                        try {
                            File.Delete(template);
                        } catch {
                            // Don't care
                        }
                    }
                }
            }

            // Send SIGABRT since that produces a crash report
            // lldb may fail to attach to system processes, but crash reports will still be produced with potentially helpful stack traces.
            for (int i = 0; i < pids.Count; i++)
            {
                ProcessHelper.kill(pids [i], 6);
            }

            // send kill -9 anyway as a last resort
            for (int i = 0; i < pids.Count; i++)
            {
                ProcessHelper.kill(pids [i], 9);
            }
        }
        public static async Task <ProcessExecutionResult> RunAsync(this Process process, TextWriter log, TextWriter StdoutStream, TextWriter StderrStream, TimeSpan?timeout = null, Dictionary <string, string> environment_variables = null, CancellationToken?cancellation_token = null)
        {
            var stdout_completion = new TaskCompletionSource <bool> ();
            var stderr_completion = new TaskCompletionSource <bool> ();
            var exit_completion   = new TaskCompletionSource <bool> ();
            var rv = new ProcessExecutionResult();

            process.StartInfo.RedirectStandardError  = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.UseShellExecute        = false;

            if (environment_variables != null)
            {
                foreach (var kvp in environment_variables)
                {
                    process.StartInfo.EnvironmentVariables [kvp.Key] = kvp.Value;
                }
            }

            process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                if (e.Data != null)
                {
                    lock (StdoutStream) {
                        StdoutStream.WriteLine(e.Data);
                        StdoutStream.Flush();
                    }
                }
                else
                {
                    stdout_completion.SetResult(true);
                }
            };

            process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
            {
                if (e.Data != null)
                {
                    lock (StderrStream) {
                        StderrStream.WriteLine(e.Data);
                        StderrStream.Flush();
                    }
                }
                else
                {
                    stderr_completion.SetResult(true);
                }
            };


            log.WriteLine("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments);
            process.Start();

            process.BeginErrorReadLine();
            process.BeginOutputReadLine();

            cancellation_token?.Register(() => {
                if (!exit_completion.Task.IsCompleted)
                {
                    StderrStream.WriteLine($"Execution was cancelled.");
                    ProcessHelper.kill(process.Id, 9);
                }
            });

            new Thread(() =>
            {
                if (timeout.HasValue)
                {
                    if (!process.WaitForExit((int)timeout.Value.TotalMilliseconds))
                    {
                        ProcessHelper.kill(process.Id, 9);
                        process.WaitForExit((int)TimeSpan.FromSeconds(5).TotalMilliseconds);                            // Wait 5s for the kill to work
                        rv.TimedOut = true;
                        lock (StderrStream)
                            log.WriteLine($"Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed.");
                    }
                }
                else
                {
                    process.WaitForExit();
                }
                exit_completion.TrySetResult(true);
            })
            {
                IsBackground = true,
            }.Start();

            await Task.WhenAll(stderr_completion.Task, stdout_completion.Task, exit_completion.Task);

            rv.ExitCode = process.ExitCode;
            return(rv);
        }
		public static async Task<ProcessExecutionResult> RunAsync (this Process process, Log log, TextWriter StdoutStream, TextWriter StderrStream, TimeSpan? timeout = null, Dictionary<string, string> environment_variables = null, CancellationToken? cancellation_token = null, bool? diagnostics = null)
		{
			var stdout_completion = new TaskCompletionSource<bool> ();
			var stderr_completion = new TaskCompletionSource<bool> ();
			var rv = new ProcessExecutionResult ();

			process.StartInfo.RedirectStandardError = true;
			process.StartInfo.RedirectStandardOutput = true;
			process.StartInfo.UseShellExecute = false;

			if (environment_variables != null) {
				foreach (var kvp in environment_variables)
					process.StartInfo.EnvironmentVariables [kvp.Key] = kvp.Value;
			}

			process.OutputDataReceived += (object sender, DataReceivedEventArgs e) =>
			{
				if (e.Data != null) {
					lock (StdoutStream) {
						StdoutStream.WriteLine (e.Data);
						StdoutStream.Flush ();
					}
				} else {
					stdout_completion.TrySetResult (true);
				}
			};

			process.ErrorDataReceived += (object sender, DataReceivedEventArgs e) =>
			{
				if (e.Data != null) {
					lock (StderrStream) {
						StderrStream.WriteLine (e.Data);
						StderrStream.Flush ();
					}
				} else {
					stderr_completion.TrySetResult (true);
				}
			};

			var sb = new StringBuilder ();
			if (process.StartInfo.EnvironmentVariables != null) {
				var currentEnvironment = Environment.GetEnvironmentVariables ().Cast<System.Collections.DictionaryEntry> ().ToDictionary ((v) => (string) v.Key, (v) => (string) v.Value, StringComparer.Ordinal);
				var processEnvironment = process.StartInfo.EnvironmentVariables.Cast<System.Collections.DictionaryEntry> ().ToDictionary ((v) => (string) v.Key, (v) => (string) v.Value, StringComparer.Ordinal);
				var allKeys = currentEnvironment.Keys.Union (processEnvironment.Keys).Distinct ();
				foreach (var key in allKeys) {
					string a = null, b = null;
					currentEnvironment.TryGetValue (key, out a);
					processEnvironment.TryGetValue (key, out b);
					if (a != b)
						sb.Append ($"{key}={StringUtils.Quote (b)} ");
				}
			}
			sb.Append ($"{StringUtils.Quote (process.StartInfo.FileName)} {process.StartInfo.Arguments}");
			log.WriteLine (sb);

			process.Start ();
			var pid = process.Id;

			process.BeginErrorReadLine ();
			process.BeginOutputReadLine ();

			cancellation_token?.Register (() => {
				if (!process.HasExited) {
					StderrStream.WriteLine ($"Execution was cancelled.");
					ProcessHelper.kill (process.Id, 9);
				}
			});

			if (timeout.HasValue) {
				if (!await process.WaitForExitAsync (timeout.Value)) {
					await process.KillTreeAsync (log, diagnostics ?? true);
					rv.TimedOut = true;
					lock (StderrStream)
						log.WriteLine ($"{pid} Execution timed out after {timeout.Value.TotalSeconds} seconds and the process was killed.");
				}
			}
			await process.WaitForExitAsync ();
			Task.WaitAll (new Task [] { stderr_completion.Task, stdout_completion.Task }, TimeSpan.FromSeconds (1));

			try {
				rv.ExitCode = process.ExitCode;
			} catch (Exception e) {
				rv.ExitCode = 12345678;
				log.WriteLine ($"Failed to get ExitCode: {e}");
			}
			return rv;
		}