Implement SafeProcessHandle.Kill and Signal#126313
Conversation
|
Tagging subscribers to this area: @dotnet/area-system-diagnostics-process |
Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/f1233ff0-2352-488d-ae71-9947c67f09c6 Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
adamsitnik
left a comment
There was a problem hiding this comment.
@copilot address my feedback, also do search for other places in the repo where the new Signal API could be used
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Outdated
Show resolved
Hide resolved
...braries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs
Outdated
Show resolved
Hide resolved
...braries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs
Outdated
Show resolved
Hide resolved
...braries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs
Show resolved
Hide resolved
...ries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs
Show resolved
Hide resolved
...ries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs
Outdated
Show resolved
Hide resolved
...ries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/tests/SafeProcessHandleTests.cs
Show resolved
Hide resolved
…r handling Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/33138282-b24e-4a35-b495-385af456c851 Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
All feedback addressed in 7c03c8c. For other usages: the main candidate in the codebase is the |
There was a problem hiding this comment.
Pull request overview
Adds process-termination and signal-sending capabilities directly to SafeProcessHandle, enabling callers to manage processes via handles without going through Process, with platform-specific implementations for Windows and Unix plus corresponding test updates.
Changes:
- Added
SafeProcessHandle.Kill()andSafeProcessHandle.Signal(PosixSignal)public APIs (with ref-assembly updates). - Implemented
SignalCoreon Windows (viaTerminateProcess) and Unix (viakill(2)+GetPlatformSignalNumber). - Added/updated tests to validate new APIs and switched an existing Unix test to use
SafeProcessHandle.Signal.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs | Introduces the new public Kill/Signal APIs and validation path. |
| src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs | Implements Windows SignalCore mapping SIGKILL to TerminateProcess with exited-process detection. |
| src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Unix.cs | Implements Unix SignalCore using GetPlatformSignalNumber + kill, returning false on ESRCH. |
| src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj | Adds Interop.PosixSignal.cs to the Unix compile item group. |
| src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs | Updates the public ref surface for SafeProcessHandle with Kill/Signal. |
| src/libraries/System.Diagnostics.Process/tests/SafeProcessHandleTests.cs | Adds unit tests covering invalid-handle, running-process, exited-process, and platform-specific behaviors. |
| src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs | Updates signal-delivery test to use SafeProcessHandle.Signal instead of a raw P/Invoke helper. |
src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj
Outdated
Show resolved
Hide resolved
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
🤖 Copilot Code Review — PR #126313Note This review was generated by Copilot. Multi-model review: Claude Opus 4.6 (primary), Claude Sonnet 4.5, GPT-5.4. Holistic AssessmentMotivation: Justified. This is part of the approved API expansion (#125838, Approach: Clean and well-structured. Summary: Detailed Findings✅ API Approval — Matches approved shape exactlyThe approved API shape from #125838 (approved by public partial class SafeProcessHandle
{
public void Kill();
public bool Signal(PosixSignal signal);
}Implementation matches exactly: ✅ Implementation quality — Follows established patterns
✅ Tests — Comprehensive coverageTests cover: invalid handle validation (Kill, Signal), kill/signal running process, kill/signal already-exited process, Windows non-SIGKILL throws PNSE, Unix SIGTERM on running process, and the existing
|
...ries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.Windows.cs
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Show resolved
Hide resolved
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Outdated
Show resolved
Hide resolved
… in PROCESS_TERMINATE remarks Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/2db8e8e4-2b00-4c1a-990d-9e1137a16472 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
src/libraries/System.Diagnostics.Process/src/Microsoft/Win32/SafeHandles/SafeProcessHandle.cs
Show resolved
Hide resolved
|
@copilot fix following test failure: I believe you have to update this method: runtime/src/native/libs/System.Native/pal_process.c Lines 699 to 721 in 3b313ad You may need to use |
…impl detail from Kill() docs Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/a787bbc7-33f7-49aa-8dff-ad37c2cb68c3 Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
... Fixed in 1815c43. The root cause was that Changes made:
|
| return -1; | ||
| // Managed PosixSignal enum uses negative values for named signals. | ||
| // Convert to the native signal number. | ||
| signal = SystemNative_GetPlatformSignalNumber((PosixSignal)signal); |
There was a problem hiding this comment.
@copilot Change SystemNative_Kill to take the platform native signal number. It is consistent other System.Native APIs (e.g.SystemNative_EnablePosixSignalHandling) and it avoids mapping the managed PosixSignal enum to the native signal twice.
There was a problem hiding this comment.
Done in bddd72b.
SystemNative_Kill now just calls kill(pid, signal) directly — no PAL mapping switch. Changes:
SafeProcessHandle.Unix.cscallsGetPlatformSignalNumber(signal)once to get the native number and passes it directly toKill(no double mapping)Process.Unix.cscallers updated: SIGKILL viaGetPlatformSignalNumber(PosixSignal.SIGKILL), SIGSTOP via a newSystemNative_GetPlatformSIGSTOP()export (needed since SIGSTOP is Linux=19, macOS=17 and is not in the managedPosixSignalenum)ProcessWaitState.Unix.csandProcessManager.Unix.csnow pass0directly for the "probe" call- The
SignalsPAL enum removed frompal_process.h;Interop.Sys.Killnow takesintwith no enum wrapper
| } | ||
|
|
||
| // Pass the managed PosixSignal value (negative) directly; SystemNative_Kill handles the conversion. | ||
| int killResult = Interop.Sys.Kill(ProcessId, (Interop.Sys.Signals)(int)signal); |
There was a problem hiding this comment.
@copilot Delete Interop.Sys.Signals enum. It should not be needed once you address the other feedback
There was a problem hiding this comment.
Done in bddd72b — Interop.Sys.Signals enum deleted. Interop.Sys.Kill now takes a plain int (platform-native signal number) directly.
…date all callers Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/d6014d25-6dbe-476e-8aa9-3d6c82c86b05 Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Adds
Kill()andSignal(PosixSignal)toSafeProcessHandle, enabling callers to terminate or signal a process via a handle without going throughProcess.Description
Public API (
SafeProcessHandle.cs+ ref assembly)Kill()— sends a request to the OS to terminate the process; silently no-ops if already exited (matchesProcess.Killsemantics). On Windows, the handle must havePROCESS_TERMINATEaccess.Signal(PosixSignal)— sends an arbitrary signal; returnsfalseif process no longer exists (or never existed),trueon delivery, throwsPlatformNotSupportedExceptionfor unsupported signals. On Windows, the handle must havePROCESS_TERMINATEaccess.Both methods validate the handle (throw
InvalidOperationExceptionon invalid handle), carry the same[UnsupportedOSPlatform("ios/tvos")]/[SupportedOSPlatform("maccatalyst")]annotations asStart, and throwPlatformNotSupportedExceptionat runtime on iOS/tvOS (matching theProcessUtils.PlatformDoesNotSupportProcessStartAndKillpattern used byProcess.Kill).Windows (
SafeProcessHandle.Windows.cs)SignalCore: onlySIGKILLis supported (maps toTerminateProcess), matchingPosixSignalRegistration.Createexception behavior for unsupported signals. Retrieves the error code viaMarshal.GetLastWin32Error()before any checks and only constructsWin32Exception(errorCode)when actually throwing. Detects already-exited processes viaERROR_ACCESS_DENIED+GetExitCodeProcessreturning non-STILL_ACTIVE.KillCore;Kill()callsSignalCore(PosixSignal.SIGKILL)directly from the shared file.Unix (
SafeProcessHandle.Unix.cs)SignalCore: checksProcessUtils.PlatformDoesNotSupportProcessStartAndKillfirst (throwsPlatformNotSupportedExceptionon iOS/tvOS); usesInterop.Sys.GetPlatformSignalNumber(signal)to convert the managedPosixSignalto its platform-native signal number (throwsPlatformNotSupportedExceptionif unsupported, matchingPosixSignalRegistration.Createbehavior); passes the native signal number directly toInterop.Sys.Kill; returnsfalseonESRCH; usesInterop.Sys.GetLastErrorInfo()and passeserrorInfo.RawErrnoto theWin32Exceptionconstructor.KillCore;Kill()callsSignalCore(PosixSignal.SIGKILL)directly from the shared file.Native (
pal_process.c)SystemNative_Killsimplified to callkill(pid, signal)directly with no PAL mapping switch — it now takes the platform-native signal number, consistent with otherSystem.NativeAPIs such asSystemNative_EnablePosixSignalHandling. The oldSignalsPAL enum (PAL_NONE,PAL_SIGKILL,PAL_SIGSTOP) has been removed frompal_process.h.SystemNative_GetPlatformSIGSTOP()to expose the platform-nativeSIGSTOPvalue (varies by OS: Linux=19, macOS=17), used byProcess.KillTree.Process.Kill refactoring (
Process.Windows.cs)Process.Kill()on Windows now delegates toSafeProcessHandle.Kill()after obtaining the handle, eliminating the duplicatedTerminateProcess+ error-handling logic.Interop (
Interop.Kill.cs)Signalsmanaged enum;Interop.Sys.Killnow takes a plainintsignal parameter (platform-native number).Interop.Sys.GetPlatformSIGSTOP()P/Invoke.Process.Unix.csusesGetPlatformSignalNumber(PosixSignal.SIGKILL)andGetPlatformSIGSTOP();ProcessWaitState.Unix.csandProcessManager.Unix.cspass0directly for the "probe" call.Project / interop
Interop.PosixSignal.csto the UnixItemGroupinSystem.Diagnostics.Process.csprojto exposeGetPlatformSignalNumberin the main assembly.Tests
SafeProcessHandleTests.cs: Invalid handle →InvalidOperationException;Kill/Signal(SIGKILL)on running process terminates it;Killon exited process does not throw;Signal(SIGKILL)returnsfalseon exited process; Windows: non-SIGKILLsignal →PlatformNotSupportedException; Unix:Signal(SIGTERM)on running process returnstrueand terminates it; Windows:Kill_HandleWithoutTerminatePermission_ThrowsWin32Exception— opens a handle with onlyPROCESS_QUERY_LIMITED_INFORMATIONand verifiesKill()throwsWin32Exception.ProcessTests.Unix.cs: UpdatedChildProcess_WithParentSignalHandler_CanReceiveSignalsto useSafeProcessHandle.Signalinstead of the rawSendSignalhelper.ProcessTests.Unix.cs/ProcessTests.Windows.cs: RefactoredSendSignalhelper to accept aProcessparameter instead of a rawintPID — Windows continues to useprocess.IdforGenerateConsoleCtrlEvent, while Unix now callsprocess.SafeHandle.Signal(signal)directly (simplified to a single-lineAssert.True). All call sites inProcessTests.csupdated accordingly.ProcessTests.Unix.cs: Removed the class-levelSIGKILLconstant andkillP/Invoke declaration;Kill_ExitedNonChildProcess_DoesNotThrownow usesSafeHandle.Signal(PosixSignal.SIGKILL)to kill the process externally andProcess.HasExitedto poll for reaping.