feat(wait): wait/waitpid/waitid and status macros
This commit is contained in:
@@ -0,0 +1,207 @@
|
||||
#ifndef VLIBC_SYS_WAIT_H
|
||||
#define VLIBC_SYS_WAIT_H
|
||||
|
||||
/*
|
||||
* vlibc — <sys/wait.h>.
|
||||
*
|
||||
* Child-process status collection (POSIX.1-2008) and the wait status macros.
|
||||
* Everything here is a pass-through to the kernel: wait/waitpid/wait3/wait4
|
||||
* ride SYS_wait4, waitid rides SYS_waitid, and failures are reported as -1
|
||||
* (or the child pid on success) with errno set by the syscall layer.
|
||||
*
|
||||
* Level 1 (onlyposix): wait, waitpid, waitid + the W* status macros.
|
||||
* Level 2 (muslmimic): wait3, wait4 (XSI).
|
||||
*
|
||||
* The W* decode macros follow the kernel's wait status encoding: bits 0-6
|
||||
* hold the terminating signal (or 0x7f for a stop), bit 7 the core-dump
|
||||
* flag, bits 8-15 the exit status, and the word 0xffff marks a continued
|
||||
* child. WEXITED/WSTOPPED/WNOWAIT are the waitid-only option bits (XSI;
|
||||
* kernel-identical values) and WCOREDUMP is an XSI/Linux extension (bit
|
||||
* 0x80) kept alongside the POSIX set for source compatibility.
|
||||
*
|
||||
* None of the declarations carry an intent attribute: every function has
|
||||
* kernel-visible side effects and reports failures through errno.
|
||||
*
|
||||
* <signal.h> does not exist yet (a later todo owns it). The minimal
|
||||
* siginfo_t below and the CLD_* constants live here under guards so that
|
||||
* header can take them over without conflict; see the notes by each.
|
||||
*/
|
||||
|
||||
#include <vlibc/features.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Selector type for waitid(). POSIX defines idtype_t as an integer type and
|
||||
* places it in <sys/types.h>, which does not define it yet; it is provided
|
||||
* here under a VLIBC_ guard so sys/types.h can take it over later without a
|
||||
* redefinition. int matches the kernel's `which` argument on x86_64.
|
||||
*/
|
||||
#ifndef VLIBC_DEFINED_IDTYPE_T
|
||||
#define VLIBC_DEFINED_IDTYPE_T
|
||||
typedef int idtype_t;
|
||||
#endif
|
||||
|
||||
/* waitid() idtype selectors (kernel-identical). */
|
||||
#define P_ALL 0 /* wait for any child */
|
||||
#define P_PID 1 /* wait for the specific child */
|
||||
#define P_PGID 2 /* wait for any child in the process group */
|
||||
|
||||
/* wait/waitpid option bits (kernel-identical). */
|
||||
#define WNOHANG 1 /* do not block; return 0 if no child has exited */
|
||||
#define WUNTRACED 2 /* also report stopped children */
|
||||
#define WCONTINUED 8 /* also report continued children */
|
||||
|
||||
/*
|
||||
* waitid-only option bits (kernel-identical; XSI). WSTOPPED shares its
|
||||
* value with WUNTRACED, so the two names are interchangeable where both
|
||||
* apply.
|
||||
*/
|
||||
#define WEXITED 4 /* wait for exited children */
|
||||
#define WSTOPPED 2 /* wait for stopped children */
|
||||
#define WNOWAIT 0x01000000 /* report but do not reap */
|
||||
|
||||
/* Status decode macros. The argument is the raw wait status word. */
|
||||
|
||||
/* True when the child terminated normally via exit() or _exit(). */
|
||||
#define WIFEXITED(s) (((s) & 0x7f) == 0)
|
||||
|
||||
/* Exit status of a normally terminated child (WIFEXITED true). */
|
||||
#define WEXITSTATUS(s) (((s) & 0xff00) >> 8)
|
||||
|
||||
/*
|
||||
* True when the child was killed by a signal. The 0x7f exclusion keeps the
|
||||
* stop code (0x7f) from being misread as a terminating signal.
|
||||
*/
|
||||
#define WIFSIGNALED(s) (((s) & 0x7f) != 0 && ((s) & 0x7f) != 0x7f)
|
||||
|
||||
/* Number of the signal that killed the child (WIFSIGNALED true). */
|
||||
#define WTERMSIG(s) ((s) & 0x7f)
|
||||
|
||||
/* True when the child is stopped by a signal (WUNTRACED). */
|
||||
#define WIFSTOPPED(s) (((s) & 0xff) == 0x7f)
|
||||
|
||||
/* Number of the signal that stopped the child (WIFSTOPPED true). */
|
||||
#define WSTOPSIG(s) WEXITSTATUS(s)
|
||||
|
||||
/* True when the child was resumed by SIGCONT (WCONTINUED). */
|
||||
#define WIFCONTINUED(s) ((s) == 0xffff)
|
||||
|
||||
/* True when the killed child dumped core (XSI/Linux extension, bit 0x80). */
|
||||
#define WCOREDUMP(s) (((s) & 0x80) != 0)
|
||||
|
||||
/*
|
||||
* si_code values reported by waitid() (kernel-identical). POSIX defines
|
||||
* these in <signal.h>, which does not exist yet; guarded per name so the
|
||||
* future signal.h can define them without a redefinition warning.
|
||||
*/
|
||||
#ifndef CLD_EXITED
|
||||
#define CLD_EXITED 1 /* child exited normally */
|
||||
#define CLD_KILLED 2 /* child killed by a signal */
|
||||
#define CLD_DUMPED 3 /* child killed by a signal and dumped core */
|
||||
#define CLD_TRAPPED 4 /* child stopped by a trace event */
|
||||
#define CLD_STOPPED 5 /* child stopped by a signal */
|
||||
#define CLD_CONTINUED 6 /* child resumed by SIGCONT */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Minimal siginfo_t, sized and laid out to match the kernel's x86_64
|
||||
* siginfo_t (128 bytes) for the fields waitid() fills: si_signo, si_errno,
|
||||
* si_code at offsets 0/4/8, then the wait-fields si_pid/si_uid/si_status at
|
||||
* offsets 16/20/24. The union is 8-aligned (si_utime/si_stime are 8-byte
|
||||
* clock_t in both the kernel and glibc layouts), so it starts at offset 16
|
||||
* with implicit padding after si_code. The kernel copies the full 128 bytes,
|
||||
* so the size must stay 128; the pad member guarantees it and the static
|
||||
* asserts pin the layout. The signal-handling fields (si_addr, si_value,
|
||||
* timers, ...) are deliberately absent — the future <signal.h> owns the
|
||||
* complete siginfo_t and must reconcile this guard.
|
||||
*/
|
||||
#ifndef VLIBC_INTERNAL_SIGINFO_DEFINED
|
||||
#define VLIBC_INTERNAL_SIGINFO_DEFINED
|
||||
typedef struct
|
||||
{
|
||||
int si_signo;
|
||||
int si_errno;
|
||||
int si_code;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
pid_t si_pid; /* 16 */
|
||||
uid_t si_uid; /* 20 */
|
||||
int si_status; /* 24 */
|
||||
long si_utime; /* 32 — 8-byte clock_t, matches the kernel/glibc ABI */
|
||||
long si_stime; /* 40 */
|
||||
};
|
||||
int vlibc_siginfo_pad[28]; /* union sized 112 so the struct stays 128 */
|
||||
};
|
||||
} siginfo_t;
|
||||
|
||||
_Static_assert(sizeof(siginfo_t) == 128, "siginfo_t must match the kernel size");
|
||||
_Static_assert(offsetof(siginfo_t, si_pid) == 16, "si_pid must sit at offset 16");
|
||||
#endif
|
||||
|
||||
/* Level 1 (POSIX base). */
|
||||
|
||||
/*
|
||||
* Wait for any child to terminate or stop and store its status in
|
||||
* *stat_loc (NULL skips the store); return the child pid, or -1 with
|
||||
* errno set. Equivalent to waitpid(-1, stat_loc, 0).
|
||||
*/
|
||||
pid_t
|
||||
wait(int *stat_loc);
|
||||
|
||||
/*
|
||||
* Wait for the child identified by pid (-1: any child, 0: any child in the
|
||||
* calling process group, < -1: any child in the process group -pid) and
|
||||
* store its status in *stat_loc (NULL skips the store). options are the
|
||||
* WNOHANG/WUNTRACED/WCONTINUED bits. Return the child pid, 0 when WNOHANG
|
||||
* found nothing, or -1 with errno set.
|
||||
*/
|
||||
pid_t
|
||||
waitpid(pid_t pid, int *stat_loc, int options);
|
||||
|
||||
/*
|
||||
* Wait for a child selected by idtype/id (P_ALL, P_PID, P_PGID) and fill
|
||||
* *infop with the siginfo details (si_pid, si_uid, si_status and a CLD_*
|
||||
* si_code); options are the WEXITED/WSTOPPED/WCONTINUED/WNOHANG/WNOWAIT
|
||||
* bits. Return 0, or -1 with errno set. infop must point to at least
|
||||
* 128 bytes (the kernel writes a full siginfo).
|
||||
*/
|
||||
int
|
||||
waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
|
||||
|
||||
#if VLIBC_LEVEL_GE(2)
|
||||
/* Level 2 (muslmimic): XSI. */
|
||||
|
||||
/*
|
||||
* struct rusage is defined by <sys/resource.h>, which does not exist yet;
|
||||
* a forward declaration is enough to pass a pointer through to the kernel.
|
||||
*/
|
||||
struct rusage;
|
||||
|
||||
/*
|
||||
* Like waitpid(-1, stat_loc, options), and additionally store resource
|
||||
* usage in *rusage (NULL skips the store); return the child pid, or -1
|
||||
* with errno set. XSI.
|
||||
*/
|
||||
pid_t
|
||||
wait3(int *stat_loc, int options, struct rusage *rusage);
|
||||
|
||||
/*
|
||||
* Like waitpid(), and additionally store resource usage in *rusage (NULL
|
||||
* skips the store); return the child pid, or -1 with errno set. XSI.
|
||||
*/
|
||||
pid_t
|
||||
wait4(pid_t pid, int *stat_loc, int options, struct rusage *rusage);
|
||||
#endif /* VLIBC_LEVEL_GE(2) */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* VLIBC_SYS_WAIT_H */
|
||||
Reference in New Issue
Block a user