dotnet / dotnet/runtime

Process.Kill can hang indefinitely on macOS arm64

Open
#131,944 4 comments 1 reaction 1 assignee Claimed by @adamsitnik View on GitHub
area-System.Diagnostics.Process regression-from-last-release
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

On macOS arm64, `Process.Kill(entireProcessTree: true)` can block indefinitely while terminating process trees created by the `dotnet-watch` tests.

This appeared after consuming the runtime flow containing #128598, which introduced the two-phase stop-then-kill implementation on Unix.

Enable dotnet-watch tests on mac once fixed: https://github.com/dotnet/sdk/issues/55679

### Reproduction Steps

1. From a `dotnet/sdk` checkout at commit [`dc6cef6`](https://github.com/dotnet/sdk/commit/dc6cef6c6ceb55eacfcd244b9b812d7f464e1503), run the [`dotnet-watch.Tests`](https://github.com/dotnet/sdk/tree/dc6cef6c6ceb55eacfcd244b9b812d7f464e1503/test/dotnet-watch.Tests) suite on macOS 15 arm64. In CI, this is Helix shard `dotnet-watch.Tests.dll.2` on queue `osx.15.arm64.open`.

2. Allow tests to dispose their child processes using `Process.Kill(entireProcessTree: true)`.
3. Observe that some calls never return.

A standalone runtime-only reproduction has not yet been reduced. The failure reproduces in the SDK CI shard linked below.

### Expected behavior

`Process.Kill(entireProcessTree: true)` terminates the process tree and returns promptly.

### Actual behavior

Instrumentation logged nine calls entering `Process.Kill(entireProcessTree: true)`, but only three returned. Helix eventually detected the hang, collected dumps, and terminated the test process:

```text
[TEST AwaitableProcess.cs:237] Killing process tree for process 18251
Hang dump timeout of '00:48:00' expired
Test application process didn't exit gracefully, exit code is '137'
```

One separate call returned from `Kill`, but its process still did not exit within 30 seconds.

### Regression?

Observed after the SDK consumed the runtime flow containing #128598. That PR changed Unix process-tree termination to recursively stop the tree before killing it.

Confidence is high that the immediate hang occurs synchronously inside `Process.Kill(entireProcessTree: true)`. Confidence that #128598 introduced the regression is moderate pending a reduced runtime-only reproduction.

### Known Workarounds

None currently. Bounding the subsequent wait does not help because the call to `Process.Kill` itself does not return.

### Configuration

- macOS 15
- arm64
- Helix queue: `osx.15.arm64.open`
- Work item: `dotnet-watch.Tests.dll.2`
- .NET 11 runtime consumed by the SDK flow

### Other information

- SDK Known Build Error: https://github.com/dotnet/sdk/issues/55636
- Failing build: https://dev.azure.com/dnceng-public/public/_build/results?buildId=1542039
- Helix job: https://helix.dot.net/api/jobs/2393a91c-17df-4ae9-b32c-faab6d292cf1/details
- Suspected runtime change: https://github.com/dotnet/runtime/pull/128598

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.