kernel: HTTPS through wget, half-close, and /proc/<pid>/fd
busybox wget hands TLS to ssl_client over a socketpair and then does shutdown(SHUT_WR). That cut the AF_UNIX link both ways, so ssl_client's reply was a SIGPIPE and every https:// download hung. SHUT_WR is now a half-close: the peer reads EOF and can still answer. TCP sockets get shutdown() at all (tcp_shutdown for the FIN); it used to do nothing. - exec keeps ignored signals and the signal mask, as execve(2) says. - /proc/<pid>/fd: a link per descriptor -- the path it was opened by, socket:[n], pipe:[n], anon_inode:[eventpoll]. /proc/self too. The global inode bit moves above pid << 8; at 0x10000 it was /proc/256. - fstat on a socket or pipe answers S_IFSOCK / S_IFIFO instead of EINVAL. - poll, select and epoll wake as soon as a pipe, socket or input device changes, not on the next tick. - Pipes are 64 KB of lazily allocated pages, copied in blocks, with PIPE_BUF atomicity: 300 MB through `yes | head | wc` in 7 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
906318f2b6
commit
8351e0323b
15 changed files with 434 additions and 71 deletions
|
|
@ -113,19 +113,13 @@ clock_ns(int clock)
|
|||
return sec * 1000000000ULL + usec * 1000ULL;
|
||||
}
|
||||
|
||||
// One tick, or until a signal or kill makes waiting pointless.
|
||||
// One tick, a poll_kick, or a signal or kill that makes waiting pointless:
|
||||
// poll's wait, so data arriving wakes an epoll_wait as it wakes a poll.
|
||||
// Returns 1 for a tick, 0 for a kick, -EINTR.
|
||||
static int
|
||||
ev_block(void)
|
||||
{
|
||||
struct proc *p = myproc();
|
||||
if (p->killed || (p->pending_signals & ~p->signal_mask))
|
||||
return -EINTR;
|
||||
acquire(&tickslock);
|
||||
uint t0 = ticks;
|
||||
while (ticks == t0 && !p->killed && !(p->pending_signals & ~p->signal_mask))
|
||||
sleep(&ticks, &tickslock);
|
||||
release(&tickslock);
|
||||
return 0;
|
||||
return poll_wait_tick();
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -178,6 +172,19 @@ ev_arg(int n, int kind, struct file **pf)
|
|||
return f->ev;
|
||||
}
|
||||
|
||||
// The name Linux gives each kind in /proc/<pid>/fd.
|
||||
const char *
|
||||
ev_kind_name(struct evobj *o)
|
||||
{
|
||||
switch (o ? o->kind : 0) {
|
||||
case EV_EVENTFD: return "anon_inode:[eventfd]";
|
||||
case EV_TIMERFD: return "anon_inode:[timerfd]";
|
||||
case EV_SIGNALFD: return "anon_inode:[signalfd]";
|
||||
case EV_EPOLL: return "anon_inode:[eventpoll]";
|
||||
}
|
||||
return "anon_inode:[event]";
|
||||
}
|
||||
|
||||
// Called by fileclose() for the last reference.
|
||||
void
|
||||
ev_close(struct evobj *o)
|
||||
|
|
@ -714,11 +721,12 @@ epoll_wait_common(int timeout_ms)
|
|||
got = ep_ready(o, buf, max);
|
||||
if (got > 0 || ticks_left == 0)
|
||||
break;
|
||||
if (ev_block() < 0) {
|
||||
int w = ev_block();
|
||||
if (w < 0) {
|
||||
got = -EINTR;
|
||||
break;
|
||||
}
|
||||
if (ticks_left > 0)
|
||||
if (w > 0 && ticks_left > 0)
|
||||
ticks_left--;
|
||||
}
|
||||
if (got > 0 && copy_to_user(uevents, buf, got * sizeof(*buf)) < 0)
|
||||
|
|
|
|||
Loading…
Reference in a new issue