forked from PowerShell/PowerShell
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJobProcessCollection.cs
More file actions
125 lines (109 loc) · 3.76 KB
/
Copy pathJobProcessCollection.cs
File metadata and controls
125 lines (109 loc) · 3.76 KB
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
125
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#nullable enable
#if !UNIX
using System;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Microsoft.Win32.SafeHandles;
namespace Microsoft.PowerShell.Commands;
/// <summary>
/// JobProcessCollection is a helper class used by Start-Process -Wait cmdlet to monitor the
/// child processes created by the main process hosted by the Start-process cmdlet.
/// </summary>
internal sealed class JobProcessCollection : IDisposable
{
/// <summary>
/// Stores the initialisation state of the job and completion port.
/// </summary>
private bool? _initStatus;
/// <summary>
/// JobObjectHandle is a reference to the job object used to track
/// the child processes created by the main process hosted by the Start-Process cmdlet.
/// </summary>
private Interop.Windows.SafeJobHandle? _jobObject;
/// <summary>
/// The completion port handle that is used to monitor job events.
/// </summary>
private Interop.Windows.SafeIoCompletionPort? _completionPort;
/// <summary>
/// Initializes a new instance of the <see cref="JobProcessCollection"/> class.
/// </summary>
public JobProcessCollection()
{ }
/// <summary>
/// Initializes the job and IO completion port and adds the process to the
/// job object.
/// </summary>
/// <param name="process">The process to add to the job.</param>
/// <returns>Whether the job creation and assignment worked or not.</returns>
public bool AssignProcessToJobObject(SafeProcessHandle process)
=> InitializeJob() && Interop.Windows.AssignProcessToJobObject(_jobObject, process);
/// <summary>
/// Blocks the current thread until all processes in the job have exited.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
public void WaitForExit(CancellationToken cancellationToken)
{
if (_completionPort is null)
{
return;
}
using var cancellationRegistration = cancellationToken.Register(() =>
{
Interop.Windows.PostQueuedCompletionStatus(
_completionPort,
Interop.Windows.JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO);
});
int completionCode = 0;
do
{
Interop.Windows.GetQueuedCompletionStatus(
_completionPort,
Interop.Windows.INFINITE,
out completionCode);
}
while (completionCode != Interop.Windows.JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO);
cancellationToken.ThrowIfCancellationRequested();
}
[MemberNotNullWhen(true, [nameof(_jobObject), nameof(_completionPort)])]
private bool InitializeJob()
{
if (_initStatus.HasValue)
{
return _initStatus.Value;
}
if (_jobObject is null)
{
_jobObject = Interop.Windows.CreateJobObject();
if (_jobObject.IsInvalid)
{
_initStatus = false;
_jobObject.Dispose();
_jobObject = null;
return false;
}
}
if (_completionPort is null)
{
_completionPort = Interop.Windows.CreateIoCompletionPort();
if (_completionPort.IsInvalid)
{
_initStatus = false;
_completionPort.Dispose();
_completionPort = null;
return false;
}
}
_initStatus = Interop.Windows.SetInformationJobObject(
_jobObject,
_completionPort);
return _initStatus.Value;
}
public void Dispose()
{
_jobObject?.Dispose();
_completionPort?.Dispose();
}
}
#endif