Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Implement ProcessStartInfo.KillOnParentExit for Windows - #126699

Merged
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property
Apr 11, 2026
Merged

Implement ProcessStartInfo.KillOnParentExit for Windows#126699
adamsitnik merged 25 commits into
mainfrom
copilot/add-kill-on-parent-exit-property

Conversation

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Description

Implements the ProcessStartInfo.KillOnParentExit property for Windows, which terminates child processes when the parent process exits. This is the Windows part of the KillOnParentExit feature.

API approved at #125838 (comment)

Changes Made

New API surface:

  • Added KillOnParentExit property to ProcessStartInfo with [SupportedOSPlatform("windows")] attribute (linux support will be added in upcoming PRs)
  • Added to reference assembly (ref/System.Diagnostics.Process.cs) with matching [SupportedOSPlatformAttribute("windows")]
  • Added XML documentation with a link to the Windows SDK description of JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE

Windows implementation (SafeProcessHandle.Windows.cs):

  • Added a lazily-initialized static SafeJobHandle with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, shared across all child processes with KillOnParentExit=true
  • For CreateProcess path (no user credentials): uses PROC_THREAD_ATTRIBUTE_JOB_LIST in the extended startup info for atomic job assignment at process creation
  • For CreateProcessWithLogonW path (with user credentials): starts the process suspended, assigns it to the job object via AssignProcessToJobObject, then resumes the thread only on the happy path — on failure, the suspended process is terminated
  • ResumeThread return value is checked; failure throws Win32Exception and the suspended process is terminated
  • AssignJobAndResumeThread takes (IntPtr hThread, SafeProcessHandle procSH) and uses procSH consistently for all process handle operations (no mixing of processInfo.hProcess and procSH)
  • ConfigureExtendedStartupInfo returns bool and the caller sets creationFlags, startupInfoEx.StartupInfo.cb, and startupInfoEx.lpAttributeList to reduce the number of method arguments
  • Uses string.IsNullOrEmpty(startInfo.UserName) for defensive checks when determining the code path

P/Invoke definitions:

  • Interop.JobObjects.cs: CreateJobObjectW, SetInformationJobObject, AssignProcessToJobObject (accepts SafeProcessHandle), JOBOBJECT_EXTENDED_LIMIT_INFORMATION, IO_COUNTERS, JOBOBJECTINFOCLASS structs/enums, SafeJobHandle, PROC_THREAD_ATTRIBUTE_JOB_LIST constant
  • Interop.ResumeThread.cs: ResumeThread P/Invoke returning uint (matching native DWORD) in its own dedicated file (following the pattern of Interop.TerminateProcess.cs, Interop.GetExitCodeProcess.cs, etc.)
  • IO_COUNTERS and JOBOBJECT_EXTENDED_LIMIT_INFORMATION use nuint for fields representing numerical values (sizes, limits, affinity masks) per interop convention
  • Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread, eliminating the duplicate declaration and aligning the test code with the production uint/0xFFFFFFFF pattern

Validation:

  • Extended ProcessStartInfo.ThrowIfInvalid to throw InvalidOperationException when KillOnParentExit is combined with UseShellExecute
  • Added KillOnParentExitCannotBeUsedWithUseShellExecute string resource

Tests (KillOnParentExitTests.cs):

  • KillOnParentExit_DefaultsToFalse / KillOnParentExit_CanBeSetToTrue — property basics
  • KillOnParentExit_WithUseShellExecute_Throws — validation test
  • KillOnParentExit_ProcessStartsAndExitsNormally — smoke test
  • KillOnParentExit_KillsTheChild_WhenParentExits — verifies child is killed (enabled=true) or survives (enabled=false) on normal parent exit, reports grandchild pid via stdout
  • KillOnParentExit_KillsTheChild_WhenParentIsKilled — same when parent is forcefully killed
  • KillOnParentExit_KillsTheChild_WhenParentCrashes — same when parent crashes (access violation)
  • User credentials code path is exercised via the updated ProcessStartInfoTests.TestUserCredentialsPropertiesOnWindows (admin/OuterLoop)

Add KillOnParentExit property to ProcessStartInfo that terminates child
processes when the parent process exits. Windows implementation uses Job
Objects with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag.
For CreateProcess: uses PROC_THREAD_ATTRIBUTE_JOB_LIST for atomic assignment.
For CreateProcessWithLogonW: starts suspended, assigns to job, then resumes.
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/61612ca1-930c-4836-8554-d143d05c8321
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@adamsitnikadamsitnik added this to the 11.0.0 milestone Apr 9, 2026
@adamsitnikadamsitnik added the NO-REVIEW Experimental/testing PR, do NOT review it label Apr 9, 2026
…py path, add user credentials test, fix pid reporting via stdout, remove nop UseShellExecute test
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/c4dd95b4-cd8e-4740-83f9-7358444c04ce
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 9, 2026 12:50

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in 31f6e6b. All 403 tests pass.

CopilotAI changed the title Implementing KillOnParentExit property in ProcessStartInfo classImplement ProcessStartInfo.KillOnParentExit for WindowsApr 9, 2026
CopilotAI requested a review from adamsitnikApril 9, 2026 12:53
- simplify the tests
- avoid duplication!!
CopilotAI review requested due to automatic review settings April 9, 2026 14:13
@adamsitnik
adamsitnik marked this pull request as ready for review April 9, 2026 14:20

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements Windows support for ProcessStartInfo.KillOnParentExit by using Windows Job Objects to ensure spawned processes are terminated when the parent exits.

Changes:

  • Added ProcessStartInfo.KillOnParentExit API surface (implementation + ref assembly) and validation against UseShellExecute.
  • Implemented Windows job-object based process start paths (CreateProcess job-list attribute, and CreateProcessWithLogonW suspended + assign + resume).
  • Added Windows-focused tests validating the behavior.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
FileDescription
src/libraries/System.Diagnostics.Process/tests/System.Diagnostics.Process.Tests.csprojIncludes the new KillOnParentExit test file in the test project.
src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.csExtends existing Windows credential tests to cover KillOnParentExit on that path.
src/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.csAdds new Windows tests validating KillOnParentExit behavior under various parent-exit scenarios.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessStartInfo.csAdds the KillOnParentExit property, docs, and validation with UseShellExecute.
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csprojLinks in the new Windows job-object interop file.
src/libraries/System.Diagnostics.Process/src/Resources/Strings.resxAdds a resource string for the KillOnParentExit + UseShellExecute validation.
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.csWindows implementation: shared job handle, job-list attribute support, and logon path job assignment.
src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.csAdds the KillOnParentExit property to the reference assembly surface.
src/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.csAdds required job-object P/Invokes/structs/constants.
src/libraries/Common/src/Interop/Windows/Advapi32/Interop.ProcessOptions.csAdds CREATE_SUSPENDED for the CreateProcessWithLogonW suspended-start path.

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
@github-actions

This comment has been minimized.

@adamsitnikadamsitnik left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
Comment threadsrc/libraries/System.Diagnostics.Process/tests/KillOnParentExitTests.cs Outdated
…sumeThread return, remove unused using, improve VerifyProcessIsRunning polling
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/06c58cfa-bdef-4f35-9345-9ab03e7dc542
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>

CopilotAI commented Apr 9, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot address my feedback

All feedback addressed in cc04598. Source builds and all 401 tests pass.

@jkotas

Copy link
Copy Markdown
Member

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the production code's uint/0xFFFFFFFF pattern.

@copilot Address this feedback by replacing the local ResumeThread with the shared copy

…d Interop.Kernel32.ResumeThread
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

ProcessHandlesTests.Windows.cs (line 187) has a local private static partial int ResumeThread(nint hThread) with == -1 check. This is technically correct (same bit pattern) but inconsistent with the...

Replaced the local ResumeThread P/Invoke in ProcessHandlesTests.Windows.cs with the shared Interop.Kernel32.ResumeThread (returns uint, check == 0xFFFFFFFF) in c5b7d59. Also added the Interop.ResumeThread.cs reference to the test csproj.

…al ResumeThread P/Invoke
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/e8bb36bc-5c71-4723-a32c-17e87d762370
Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 17:16
Comment threadsrc/libraries/Common/src/Interop/Windows/Kernel32/Interop.JobObjects.cs Outdated
@adamsitnik

Copy link
Copy Markdown
Member

@copilot please address @jkotas feedback

…, unnecessary assert, reduce ConfigureExtendedStartupInfo args
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2dd25b7c-da4a-4ed0-a9b3-cc6561f14aeb
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
CopilotAI requested review from Copilot and removed request for CopilotApril 11, 2026 19:34

CopilotAI commented Apr 11, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot please address @jkotas feedback

All four items addressed in f497166.

Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Kill System.Diagnostics.Process on parent death

4 participants

@adamsitnik@jkotas