This repository has been archived by the owner on Oct 16, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 771
/
WorkerProcess.cs
124 lines (114 loc) · 3.91 KB
/
WorkerProcess.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Pipes;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Threading;
namespace ICSharpCode.SharpDevelop.Project
{
/// <summary>
/// Manages a worker process that communicates with the host using a bidirectional named pipe.
/// </summary>
sealed class WorkerProcess : IDisposable
{
readonly AnonymousPipeServerStream hostToWorkerPipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable);
readonly AnonymousPipeServerStream workerToHostPipe = new AnonymousPipeServerStream(PipeDirection.In, HandleInheritability.Inheritable);
readonly Process process = new Process();
readonly Thread readerThread;
int id;
volatile bool isDisposed;
readonly Action<string, BinaryReader> dataArrived;
public WorkerProcess(Action<string, BinaryReader> dataArrived)
{
this.dataArrived = dataArrived;
readerThread = new Thread(ReaderThread);
readerThread.IsBackground = true;
}
public void Start(ProcessStartInfo info)
{
if (info == null)
throw new ArgumentNullException("info");
process.StartInfo = info;
Debug.WriteLine("WorkerProcess starting...");
string oldArguments = info.Arguments;
try {
info.Arguments += " " + hostToWorkerPipe.GetClientHandleAsString() + " " + workerToHostPipe.GetClientHandleAsString();
if (!process.Start())
throw new InvalidOperationException("Process.Start() failed");
} finally {
info.Arguments = oldArguments;
// client handles were inherited into started process, dispose our copy
hostToWorkerPipe.DisposeLocalCopyOfClientHandle();
workerToHostPipe.DisposeLocalCopyOfClientHandle();
}
id = process.Id;
readerThread.Start();
this.Writer = new BinaryWriter(hostToWorkerPipe);
Debug.WriteLine("WorkerProcess " + id + " started");
}
void ReaderThread()
{
try {
using (BinaryReader reader = new BinaryReader(workerToHostPipe)) {
while (!isDisposed) {
string text;
try {
text = reader.ReadString();
} catch (EndOfStreamException) {
Core.LoggingService.Debug("Cannot read from WorkerProcess " + id + ": end of stream");
break;
}
dataArrived(text, reader);
}
}
Core.LoggingService.Debug("Stopped reading from WorkerProcess " + id + ".");
if (ProcessExited != null)
ProcessExited(this, EventArgs.Empty);
} catch (Exception ex) {
Core.MessageService.ShowException(ex);
} finally {
Core.LoggingService.Debug("End of reader thread on WorkerProcess " + id + ".");
}
}
public event EventHandler ProcessExited;
public BinaryWriter Writer { get; private set; }
public void Kill()
{
try {
if (!process.HasExited) {
process.Kill();
}
} catch (InvalidOperationException) {
// may occur when the worker process crashes
}
}
public void Dispose()
{
isDisposed = true;
Core.LoggingService.Debug("Telling worker process to exit");
hostToWorkerPipe.Dispose(); // send "end-of-stream" to worker
if (Thread.CurrentThread != readerThread) {
// don't deadlock when disposing from within ReaderThread event
Core.LoggingService.Debug("Waiting for thread-join");
if (!readerThread.Join(3000)) {
Core.LoggingService.Debug("Thread-join failed. Killing worker process.");
Kill();
Core.LoggingService.Debug("Waiting for thread-join");
readerThread.Join();
}
Core.LoggingService.Debug("Joined!");
}
workerToHostPipe.Dispose();
process.Dispose();
}
}
}