Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

`wait4` and `waitid` never return `EINTR` when a handled signal arrives

オープン
#461 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 3 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
54/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
c

調査の方向性

Start in src/syscall/proc.c at the polling loops in sys_wait4 and sys_waitid, then compare how the poll, futex and pipe paths use signal_claim_interruption(). The issue describes the required behavior for handlers with and without SA_RESTART and provides a reproducer. Add regression coverage for wait4(pid), wait4(-1) and waitid, checking EINTR without SA_RESTART and successful reap with it.

索引モデルが issue の本文から書いたものです。

説明

On Linux, a blocking wait4 or waitid sleeps in do_wait (kernel/exit.c) with TASK_INTERRUPTIBLE and leaves the loop with -ERESTARTSYS once a signal is pending. Signal delivery turns that into EINTR when the handler lacks SA_RESTART, and restarts the wait when it has it. Under elfuse the wait ignores the signal and returns only when the child exits: the polling loops in sys_wait4 and sys_waitid (src/syscall/proc.c) check thread_stop_requested() but never signal_claim_interruption(), which the poll, futex and pipe paths use for the same purpose.

Reproducer (the child signals the parent at 0.2 s and exits 1 s later; the handler has no SA_RESTART):

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static void on_usr1(int sig)
{
    (void) sig;
}

static double now(void)
{
    struct timespec t;
    clock_gettime(CLOCK_MONOTONIC, &t);
    return t.tv_sec + t.tv_nsec / 1e9;
}

static void run(const char *name, int mode)
{
    pid_t child = fork();
    if (child == 0) {
        usleep(200000);
        kill(getppid(), SIGUSR1);
        sleep(1);
        _exit(0);
    }
    double t0 = now();
    int status;
    siginfo_t si;
    long ret;
    if (mode == 0)
        ret = waitpid(child, &status, 0);
    else if (mode == 1)
        ret = waitpid(-1, &status, 0);
    else
        ret = waitid(P_PID, child, &si, WEXITED);
    int err = errno;
    printf("%-10s ret=%ld %s after %.2fs\n", name, ret,
           ret < 0 ? strerror(err) : "", now() - t0);
    if (ret < 0)
        waitpid(child, &status, 0);
}

int main(void)
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = on_usr1;
    sigaction(SIGUSR1, &sa, NULL);
    run("wait4(pid)", 0);
    run("wait4(-1)", 1);
    run("waitid", 2);
    return 0;
}
wait4(pid) wait4(-1) waitid
elfuse c2785c7 child pid after 1.2 s child pid after 1.2 s 0 after 1.2 s
Linux 6.12 under qemu -1, EINTR after 0.2 s -1, EINTR after 0.2 s -1, EINTR after 0.2 s

The SA_RESTART half needs its own handling: elfuse has no general ERESTARTSYS path, so a loop that starts honoring the claimed signal has to keep waiting when that signal's handler has SA_RESTART. A regression test needs the child to stay alive until the handler releases it, and should cover EINTR without SA_RESTART and a successful reap with it, for wait4(pid), wait4(-1) and waitid.

Found by jserv in https://github.com/sysprog21/elfuse/pull/460#discussion_r4348510702: the race fixed there never showed under elfuse for this reason.

主要言語
C
スター
275
フォーク
29
平均マージ
2日 22時間
マージ済み PR(30日)
18

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

sysprog21/elfuse のほかの issue

sysprog21/elfuse の issue をすべて見る

似ている issue

C の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。