Use job object to control child process

This commit is contained in:
Hongtao Zhang 2024-02-06 13:07:21 -06:00
parent 73f2c3b503
commit a524096fc2
2 changed files with 19 additions and 6 deletions

View file

@ -55,6 +55,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Droplex" Version="1.7.0" /> <PackageReference Include="Droplex" Version="1.7.0" />
<PackageReference Include="FSharp.Core" Version="7.0.401" /> <PackageReference Include="FSharp.Core" Version="7.0.401" />
<PackageReference Include="Meziantou.Framework.Win32.Jobs" Version="3.2.1" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" /> <PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" /> <PackageReference Include="squirrel.windows" Version="1.5.2" NoWarn="NU1701" />
<PackageReference Include="StreamJsonRpc" Version="2.17.8" /> <PackageReference Include="StreamJsonRpc" Version="2.17.8" />

View file

@ -5,12 +5,24 @@ using System.IO.Pipelines;
using System.Threading.Tasks; using System.Threading.Tasks;
using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using Meziantou.Framework.Win32;
using Nerdbank.Streams; using Nerdbank.Streams;
namespace Flow.Launcher.Core.Plugin namespace Flow.Launcher.Core.Plugin
{ {
internal abstract class ProcessStreamPluginV2 : JsonRPCPluginV2 internal abstract class ProcessStreamPluginV2 : JsonRPCPluginV2
{ {
private static JobObject _jobObject = new JobObject();
static ProcessStreamPluginV2()
{
_jobObject.SetLimits(new JobObjectLimits()
{
Flags = JobObjectLimitFlags.KillOnJobClose | JobObjectLimitFlags.DieOnUnhandledException
});
_jobObject.AssignProcess(Process.GetCurrentProcess());
}
public override string SupportedLanguage { get; set; } public override string SupportedLanguage { get; set; }
protected sealed override IDuplexPipe ClientPipe { get; set; } protected sealed override IDuplexPipe ClientPipe { get; set; }
@ -30,22 +42,22 @@ namespace Flow.Launcher.Core.Plugin
ClientProcess = Process.Start(StartInfo); ClientProcess = Process.Start(StartInfo);
ArgumentNullException.ThrowIfNull(ClientProcess); ArgumentNullException.ThrowIfNull(ClientProcess);
SetupPipe(ClientProcess); SetupPipe(ClientProcess);
ErrorStream = ClientProcess.StandardError; ErrorStream = ClientProcess.StandardError;
await base.InitAsync(context); await base.InitAsync(context);
} }
private void SetupPipe(Process process) private void SetupPipe(Process process)
{ {
var (reader, writer) = (PipeReader.Create(process.StandardOutput.BaseStream), var (reader, writer) = (PipeReader.Create(process.StandardOutput.BaseStream),
PipeWriter.Create(process.StandardInput.BaseStream)); PipeWriter.Create(process.StandardInput.BaseStream));
ClientPipe = new DuplexPipe(reader, writer); ClientPipe = new DuplexPipe(reader, writer);
} }
public override async Task ReloadDataAsync() public override async Task ReloadDataAsync()
{ {
var oldProcess = ClientProcess; var oldProcess = ClientProcess;
@ -57,8 +69,8 @@ namespace Flow.Launcher.Core.Plugin
await oldProcess.WaitForExitAsync(); await oldProcess.WaitForExitAsync();
oldProcess.Dispose(); oldProcess.Dispose();
} }
public override async ValueTask DisposeAsync() public override async ValueTask DisposeAsync()
{ {
ClientProcess.Kill(true); ClientProcess.Kill(true);