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:
parent
d0941780f5
commit
a4ed556543
9 changed files with 428 additions and 28 deletions
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue