Skip to content

Make ProcessWaitState store ProcessExitStatus instead of int? exit code#127010

Closed
Copilot wants to merge 2 commits intomainfrom
copilot/update-processwaitstate-to-support-exitstatus
Closed

Make ProcessWaitState store ProcessExitStatus instead of int? exit code#127010
Copilot wants to merge 2 commits intomainfrom
copilot/update-processwaitstate-to-support-exitstatus

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 16, 2026

Description

Changes ProcessWaitState to store a ProcessExitStatus (with signal information) instead of a bare int? exit code, as groundwork for upcoming APIs (#126293).

Native (System.Native)

  • Extended SystemNative_WaitPidExitedNoHang with a new int32_t* terminatingSignal out parameter
  • On WIFSIGNALED, extracts the signal via WTERMSIG and maps it to PosixSignal using TryConvertSignalCodeToPosixSignal; on normal exit, sets terminatingSignal to 0
  • Made TryConvertSignalCodeToPosixSignal non-static in pal_signal.c and declared it in pal_signal.h so pal_process.c can call it
  • Updated pal_process.h, pal_process_wasi.c signatures accordingly

Managed

  • Updated P/Invoke Interop.Sys.WaitPidExitedNoHang to include out int terminatingSignal
  • Changed ProcessWaitState._exitCode (int?) → _exitStatus (ProcessExitStatus?)
  • Updated GetExited, ChildReaped, TryReapChild, and CheckChildren to propagate signal information through ProcessExitStatus
  • Updated Process.Unix.cs.UpdateHasExited to consume ProcessExitStatus?
- private int? _exitCode;
+ private ProcessExitStatus? _exitStatus;
  [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_WaitPidExitedNoHang", SetLastError = true)]
- internal static partial int WaitPidExitedNoHang(int pid, out int exitCode);
+ internal static partial int WaitPidExitedNoHang(int pid, out int exitCode, out int terminatingSignal);

Copilot AI and others added 2 commits April 16, 2026 15:57
- Change _exitCode (int?) to _exitStatus (ProcessExitStatus?) in ProcessWaitState.Unix.cs
- Update GetExited to return ProcessExitStatus? instead of int?
- Extend Interop.Sys.WaitPidExitedNoHang with out int terminatingSignal parameter
- Update SystemNative_WaitPidExitedNoHang native implementation to extract
  terminating signal via WTERMSIG and map it using TryConvertSignalCodeToPosixSignal
- Make TryConvertSignalCodeToPosixSignal non-static in pal_signal.c and declare it in pal_signal.h
- Update pal_process.h, pal_process_wasi.c signatures accordingly
- Update ChildReaped and all callers to pass signal information through

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3692424a-4bc2-4eca-84fe-0eb8b7981738

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
…posixSignal

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/3692424a-4bc2-4eca-84fe-0eb8b7981738

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI self-assigned this Apr 16, 2026
Copilot AI review requested due to automatic review settings April 16, 2026 16:01
Copilot AI review requested due to automatic review settings April 16, 2026 16:01
@adamsitnik adamsitnik marked this pull request as ready for review April 16, 2026 16:01
Copilot AI review requested due to automatic review settings April 16, 2026 16:01
@adamsitnik adamsitnik added this to the 11.0.0 milestone Apr 16, 2026
@adamsitnik adamsitnik requested a review from tmds April 16, 2026 16:05
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates Unix process reaping plumbing so ProcessWaitState can cache a richer ProcessExitStatus (including terminating signal info) rather than only an int? exit code, as groundwork for upcoming SafeProcessHandle.WaitForExit* APIs.

Changes:

  • Extend SystemNative_WaitPidExitedNoHang / Interop.Sys.WaitPidExitedNoHang to return an additional “terminating signal” out parameter.
  • Plumb signal information through ProcessWaitState.Unix via ProcessExitStatus? caching.
  • Make TryConvertSignalCodeToPosixSignal callable from pal_process.c by moving it to a header-visible helper.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/native/libs/System.Native/pal_signal.h Declares TryConvertSignalCodeToPosixSignal for cross-file use.
src/native/libs/System.Native/pal_signal.c Makes TryConvertSignalCodeToPosixSignal non-static so pal_process.c can call it.
src/native/libs/System.Native/pal_process.h Updates WaitPidExitedNoHang signature and documents new out parameter semantics.
src/native/libs/System.Native/pal_process.c Populates terminating-signal info when reaping children.
src/native/libs/System.Native/pal_process_wasi.c Updates WASI stub signature for the new out parameter.
src/libraries/Common/src/Interop/Unix/System.Native/Interop.WaitPid.cs Updates managed P/Invoke signature to include terminating signal out parameter.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessWaitState.Unix.cs Switches cached exit info from int? to ProcessExitStatus? and plumbs signal data.
src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Unix.cs Consumes ProcessExitStatus? and continues populating Process.ExitCode.
Comments suppressed due to low confidence (2)

src/native/libs/System.Native/pal_process.c:961

  • If the status is neither WIFEXITED nor WIFSIGNALED, the code only assert(false) and may leave exitCode / terminatingSignal uninitialized in release builds. Even if this path is expected to be unreachable with WNOHANG, it should still write safe values (and/or translate it to an error) before returning.
        else
        {
            assert(false);
        }

src/native/libs/System.Native/pal_process.c:940

  • Consider initializing *exitCode / *terminatingSignal to deterministic defaults at the start of this function (before calling waitpid). When waitpid returns 0 or -1, the current implementation returns without writing either out parameter; even if callers typically ignore them in those cases, the marshaller still copies them back to managed code.
int32_t SystemNative_WaitPidExitedNoHang(int32_t pid, int32_t* exitCode, int32_t* terminatingSignal)
{
    assert(exitCode != NULL);
    assert(terminatingSignal != NULL);

    int32_t result;
    int status;
    while (CheckInterrupted(result = waitpid(pid, &status, WNOHANG)));

@@ -338,7 +338,7 @@ internal bool GetExited(out int? exitCode, bool refresh)

// We now have an up-to-date snapshot for whether we've exited,
// and if we have, what the exit code is (if we were able to find out).
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

This comment still refers to caching the "exit code", but the method now tracks ProcessExitStatus?. Update the wording to reflect that we cache the exit status (and that it may be null when it can't be determined).

Suggested change
// and if we have, what the exit code is (if we were able to find out).
// and if we have, what the exit status is (which may be null if it couldn't be determined).

Copilot uses AI. Check for mistakes.

int32_t SystemNative_WaitPidExitedNoHang(int32_t pid, int32_t* exitCode)
int32_t SystemNative_WaitPidExitedNoHang(int32_t pid, int32_t* exitCode, int32_t* terminatingSignal)
{
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

SystemNative_WaitPidExitedNoHang returns -1 here without initializing exitCode / terminatingSignal (and without setting errno). Since these are out parameters, managed marshalling will still read back whatever is in those stack locations, which can lead to nondeterministic values if this stub is ever invoked. Initialize both outputs (e.g., to 0) and set errno = ENOTSUP (or the appropriate error) before returning.

Suggested change
{
{
assert(exitCode != NULL);
assert(terminatingSignal != NULL);
*exitCode = 0;
*terminatingSignal = 0;
errno = ENOTSUP;

Copilot uses AI. Check for mistakes.
@adamsitnik
Copy link
Copy Markdown
Member

@tmds if your preference is to review it all together with new public API, I am going to get #127022 to a point where I am happy about it and then ask you for reviewing it.

@tmds
Copy link
Copy Markdown
Member

tmds commented Apr 17, 2026

@adamsitnik, I'm not reviewing anything today. You can include it in the other PR. It makes more clear why this is being refactored.

@adamsitnik adamsitnik closed this Apr 17, 2026
@adamsitnik adamsitnik deleted the copilot/update-processwaitstate-to-support-exitstatus branch April 17, 2026 07:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants