| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- // Copyright (c) .NET Foundation. All rights reserved.
- // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- namespace Microsoft.Extensions.Internal
- {
- internal static class ProcessExtensions
- {
- private static readonly bool _isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
- private static readonly TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);
- public static void KillTree(this Process process)
- {
- process.KillTree(_defaultTimeout);
- }
- public static void KillTree(this Process process, TimeSpan timeout)
- {
- string stdout;
- if (_isWindows)
- {
- RunProcessAndWaitForExit(
- "taskkill",
- $"/T /F /PID {process.Id}",
- timeout,
- out stdout);
- }
- else
- {
- var children = new HashSet<int>();
- GetAllChildIdsUnix(process.Id, children, timeout);
- foreach (var childId in children)
- {
- KillProcessUnix(childId, timeout);
- }
- KillProcessUnix(process.Id, timeout);
- }
- }
- private static void GetAllChildIdsUnix(int parentId, ISet<int> children, TimeSpan timeout)
- {
- string stdout;
- var exitCode = RunProcessAndWaitForExit(
- "pgrep",
- $"-P {parentId}",
- timeout,
- out stdout);
- if (exitCode == 0 && !string.IsNullOrEmpty(stdout))
- {
- using (var reader = new StringReader(stdout))
- {
- while (true)
- {
- var text = reader.ReadLine();
- if (text == null)
- {
- return;
- }
- int id;
- if (int.TryParse(text, out id))
- {
- children.Add(id);
- // Recursively get the children
- GetAllChildIdsUnix(id, children, timeout);
- }
- }
- }
- }
- }
- private static void KillProcessUnix(int processId, TimeSpan timeout)
- {
- string stdout;
- RunProcessAndWaitForExit(
- "kill",
- $"-TERM {processId}",
- timeout,
- out stdout);
- }
- private static int RunProcessAndWaitForExit(string fileName, string arguments, TimeSpan timeout, out string stdout)
- {
- var startInfo = new ProcessStartInfo
- {
- FileName = fileName,
- Arguments = arguments,
- RedirectStandardOutput = true,
- UseShellExecute = false
- };
- var process = Process.Start(startInfo);
- stdout = null;
- if (process.WaitForExit((int)timeout.TotalMilliseconds))
- {
- stdout = process.StandardOutput.ReadToEnd();
- }
- else
- {
- process.Kill();
- }
- return process.ExitCode;
- }
- }
- }
|