syd 3.54.1

rock-solid application kernel
Documentation
/*
 * Syd: rock-solid application kernel
 * src/waitid.c: Safe waitid with sigsetjmp/siglongjmp
 *
 * Copyright (c) 2026 Ali Polatel <alip@chesswob.org>
 * SPDX-License-Identifier: GPL-3.0
 */

#define _BSD_SOURCE
#define _DEFAULT_SOURCE
#define _POSIX_C_SOURCE 200809L

#include <setjmp.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/syscall.h>
#include <sys/wait.h>

#ifndef __WNOTHREAD
#define __WNOTHREAD 0x20000000
#endif

// C99 requires statics zero-initialised.
static sigjmp_buf syd_jmpbuf;
static volatile sig_atomic_t syd_armed;

// Signal handler for the ptrace wakeup realtime signal.
//
// 1. When armed by syd_safe_wait_all, longjmp back.
// 2. When not armed, return normally causing EINTR.
void handle_sig_ptrace(int sig)
{
	(void)sig;
	if (syd_armed) {
		syd_armed = 0;
		siglongjmp(syd_jmpbuf, 1);
	}
}

/*
 * Safe waitid(2) with syscall cookie.
 *
 * Returns 0 if siglongjmp fired.
 * Returns 1 if child event with info filled.
 * Returns negated errno(3) on errors.
 */
int syd_safe_wait_all(siginfo_t *info, unsigned long cookie)
{
	sigset_t mask;
	long ret;

	if (info == NULL)
		return -EFAULT;
	memset(info, 0, sizeof(*info));

	sigemptyset(&mask);
	sigaddset(&mask, SIGRTMIN);

	if (sigsetjmp(syd_jmpbuf, 0) != 0) {
		sigprocmask(SIG_BLOCK, &mask, NULL);
		return (info->si_pid != 0);
	}

	syd_armed = 1;
	sigprocmask(SIG_UNBLOCK, &mask, NULL);

	ret = syscall(SYS_waitid, P_ALL, 0, info,
	              WEXITED | __WNOTHREAD, NULL, cookie);

	syd_armed = 0;
	sigprocmask(SIG_BLOCK, &mask, NULL);

	if (ret < 0)
		return -errno;

	return (info->si_pid != 0) ? 1 : -EINTR;
}