|
7 | 7 | using System.Threading;
|
8 | 8 | using System.Threading.Tasks;
|
9 | 9 | using GitCommands.Logging;
|
| 10 | +using GitUI; |
10 | 11 | using GitUIPluginInterfaces;
|
11 | 12 | using JetBrains.Annotations;
|
12 | 13 |
|
@@ -53,17 +54,15 @@ public IProcess Start(ArgumentString arguments = default, bool createWindow = fa
|
53 | 54 | private sealed class ProcessWrapper : IProcess
|
54 | 55 | {
|
55 | 56 | // TODO should this use TaskCreationOptions.RunContinuationsAsynchronously
|
56 |
| - private readonly TaskCompletionSource<int?> _exitTaskCompletionSource = new TaskCompletionSource<int?>(); |
| 57 | + private readonly TaskCompletionSource<int> _exitTaskCompletionSource = new TaskCompletionSource<int>(); |
57 | 58 |
|
| 59 | + private readonly object _syncRoot = new object(); |
58 | 60 | private readonly Process _process;
|
59 | 61 | private readonly ProcessOperation _logOperation;
|
60 | 62 | private readonly bool _redirectInput;
|
61 | 63 | private readonly bool _redirectOutput;
|
62 | 64 |
|
63 |
| - private int _disposed; |
64 |
| - |
65 |
| - /// <inheritdoc /> |
66 |
| - public int? ExitCode { get; private set; } |
| 65 | + private bool _disposed; |
67 | 66 |
|
68 | 67 | [SuppressMessage("ReSharper", "AssignNullToNotNullAttribute")]
|
69 | 68 | public ProcessWrapper(string fileName, string arguments, string workDir, bool createWindow, bool redirectInput, bool redirectOutput, [CanBeNull] Encoding outputEncoding)
|
@@ -102,15 +101,17 @@ public ProcessWrapper(string fileName, string arguments, string workDir, bool cr
|
102 | 101 |
|
103 | 102 | private void OnProcessExit(object sender, EventArgs eventArgs)
|
104 | 103 | {
|
105 |
| - // The Exited event can be raised after the process is disposed, however |
106 |
| - // if the Process is disposed then reading ExitCode will throw. |
107 |
| - if (_disposed == 0) |
| 104 | + lock (_syncRoot) |
108 | 105 | {
|
109 |
| - ExitCode = _process.ExitCode; |
| 106 | + // The Exited event can be raised after the process is disposed, however |
| 107 | + // if the Process is disposed then reading ExitCode will throw. |
| 108 | + if (!_disposed) |
| 109 | + { |
| 110 | + var exitCode = _process.ExitCode; |
| 111 | + _logOperation.LogProcessEnd(exitCode); |
| 112 | + _exitTaskCompletionSource.TrySetResult(exitCode); |
| 113 | + } |
110 | 114 | }
|
111 |
| - |
112 |
| - _logOperation.LogProcessEnd(ExitCode); |
113 |
| - _exitTaskCompletionSource.TrySetResult(ExitCode); |
114 | 115 | }
|
115 | 116 |
|
116 | 117 | /// <inheritdoc />
|
@@ -159,32 +160,30 @@ public StreamReader StandardError
|
159 | 160 | public void WaitForInputIdle() => _process.WaitForInputIdle();
|
160 | 161 |
|
161 | 162 | /// <inheritdoc />
|
162 |
| - public Task<int?> WaitForExitAsync() => _exitTaskCompletionSource.Task; |
| 163 | + public Task<int> WaitForExitAsync() => _exitTaskCompletionSource.Task; |
163 | 164 |
|
164 | 165 | /// <inheritdoc />
|
165 |
| - public int? WaitForExit() |
| 166 | + public int WaitForExit() |
166 | 167 | {
|
167 |
| - if (_disposed != 0) |
168 |
| - { |
169 |
| - return ExitCode; |
170 |
| - } |
171 |
| - |
172 |
| - _process.WaitForExit(); |
173 |
| - |
174 |
| - return GitUI.ThreadHelper.JoinableTaskFactory.Run(() => _exitTaskCompletionSource.Task); |
| 168 | + return ThreadHelper.JoinableTaskFactory.Run(() => WaitForExitAsync()); |
175 | 169 | }
|
176 | 170 |
|
177 | 171 | /// <inheritdoc />
|
178 | 172 | public void Dispose()
|
179 | 173 | {
|
180 |
| - if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) |
| 174 | + lock (_syncRoot) |
181 | 175 | {
|
182 |
| - return; |
| 176 | + if (_disposed) |
| 177 | + { |
| 178 | + return; |
| 179 | + } |
| 180 | + |
| 181 | + _disposed = true; |
183 | 182 | }
|
184 | 183 |
|
185 | 184 | _process.Exited -= OnProcessExit;
|
186 | 185 |
|
187 |
| - _exitTaskCompletionSource.TrySetResult(null); |
| 186 | + _exitTaskCompletionSource.TrySetCanceled(); |
188 | 187 |
|
189 | 188 | _process.Dispose();
|
190 | 189 |
|
|
0 commit comments