kernel: timers that fire, raw ping, and the sockets X needs

alarm() and setitimer() stored a countdown nothing counted down, so no
timer has ever fired; setitimer and getitimer were also registered with
no Linux number. alarmd now posts SIGALRM on the tick, while any process
has a timer armed. busybox's ping, /bin/ping on the Alpine root, sends
every request after the first from its SIGALRM handler.

It also opens SOCK_RAW, which was EPROTOTYPE. A raw ICMP socket is now a
ping socket whose reads start at the IP header. And a blocked socket
call gives up for a signal with a handler, not only for a kill: the
alarm woke recvfrom, and the wait put it straight back to sleep.

For Xorg: AF_UNIX abstract names, which read as the empty path and so as
EADDRINUSE ("server already running"); and getsockname and getpeername,
which did not exist, so libxcb sent no cookie and the server refused
every client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-24 19:44:10 +02:00
commit a4ed556543
9 changed files with 428 additions and 28 deletions

View file

@ -10,14 +10,36 @@
#include "core/uaccess.h"
#include "uapi/errno.h"
// Timer values in ticks, rounding a nonzero time up: POSIX says a timer set
// to 1 us goes off, not that it is disarmed.
static uint
tv_ticks(struct timeval *tv)
{
if (tv->tv_sec < 0 || tv->tv_usec < 0)
return 0;
uint64 t = (uint64)tv->tv_sec * HZ +
((uint64)tv->tv_usec + USEC_PER_TICK - 1) / USEC_PER_TICK;
return t > 0x7fffffff ? 0x7fffffff : (uint)t;
}
static void
ticks_tv(uint t, struct timeval *tv)
{
tv->tv_sec = t / HZ;
tv->tv_usec = (t % HZ) * USEC_PER_TICK;
}
// The seconds left on the previous alarm, rounded up, as POSIX asks.
addr_t
sys_alarm(void)
{
int seconds;
if (argint(0, &seconds) < 0)
return -1;
myproc()->alarm_ticks = seconds * HZ;
return 0;
struct proc *p = myproc();
uint left = alarm_left(p);
alarm_arm(p, seconds > 0 ? (uint)seconds * HZ : 0, 0);
return (left + HZ - 1) / HZ;
}
addr_t
@ -77,21 +99,52 @@ sys_clock_gettime(void)
return 0;
}
addr_t sys_getitimer(void) { return 0; } // stub
// ITIMER_REAL only. ITIMER_VIRTUAL and ITIMER_PROF count CPU time, which
// nothing here measures per tick, and are refused rather than accepted and
// never fired -- which is what all three used to be.
static int
itimer_get(struct proc *p, struct itimerval *iv)
{
ticks_tv(p->alarm_every, &iv->it_interval);
ticks_tv(alarm_left(p), &iv->it_value);
return 0;
}
addr_t
sys_getitimer(void)
{
int which;
addr_t curp;
argint(0, &which); argaddr(1, &curp);
if (which != 0)
return -EINVAL;
struct itimerval iv;
itimer_get(myproc(), &iv);
if (copy_to_user(curp, &iv, sizeof(iv)) != 0)
return -EFAULT;
return 0;
}
addr_t
sys_setitimer(void)
{
int which;
addr_t newp;
argint(0, &which); argaddr(1, &newp);
// We don't implement interval timers; just track the alarm if it's ITIMER_REAL.
if (which == 0 && newp) {
struct itimerval iv;
if (copy_from_user(&iv, newp, sizeof(iv)) == 0)
myproc()->alarm_ticks = (int)(iv.it_value.tv_sec * HZ +
iv.it_value.tv_usec / USEC_PER_TICK);
addr_t newp, oldp;
argint(0, &which); argaddr(1, &newp); argaddr(2, &oldp);
if (which != 0)
return -EINVAL;
struct proc *p = myproc();
struct itimerval iv;
if (oldp) {
itimer_get(p, &iv);
if (copy_to_user(oldp, &iv, sizeof(iv)) != 0)
return -EFAULT;
}
if (newp == 0)
return 0;
if (copy_from_user(&iv, newp, sizeof(iv)) != 0)
return -EFAULT;
alarm_arm(p, tv_ticks(&iv.it_value), tv_ticks(&iv.it_interval));
return 0;
}