Add missing ICANON features

This commit is contained in:
Justine Tunney 2024-09-05 03:17:19 -07:00
parent dd8544c3bd
commit 03875beadb
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
22 changed files with 526 additions and 251 deletions

View file

@ -161,12 +161,12 @@ void Connect(void) {
CHECK_NE(-1,
(g_sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)));
expo = INITIAL_CONNECT_TIMEOUT;
deadline = timespec_add(timespec_real(),
deadline = timespec_add(timespec_mono(),
timespec_fromseconds(MAX_WAIT_CONNECT_SECONDS));
LOGIFNEG1(sigaction(SIGALRM, &(struct sigaction){.sa_handler = OnAlarm}, 0));
DEBUGF("connecting to %s (%hhu.%hhu.%hhu.%hhu) to run %s", g_hostname, ip4[0],
ip4[1], ip4[2], ip4[3], g_prog);
struct timespec start = timespec_real();
struct timespec start = timespec_mono();
TryAgain:
alarmed = false;
LOGIFNEG1(setitimer(
@ -178,7 +178,7 @@ TryAgain:
if (rc == -1) {
if (err == EINTR) {
expo *= 1.5;
if (timespec_cmp(timespec_real(), deadline) >= 0) {
if (timespec_cmp(timespec_mono(), deadline) >= 0) {
FATALF("timeout connecting to %s (%hhu.%hhu.%hhu.%hhu:%d)", g_hostname,
ip4[0], ip4[1], ip4[2], ip4[3],
ntohs(((struct sockaddr_in *)ai->ai_addr)->sin_port));
@ -193,7 +193,7 @@ TryAgain:
}
setitimer(ITIMER_REAL, &(const struct itimerval){0}, 0);
freeaddrinfo(ai);
connect_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
connect_latency = timespec_tomicros(timespec_sub(timespec_mono(), start));
}
bool Send(int tmpfd, const void *output, size_t outputsize) {
@ -309,7 +309,7 @@ bool Recv(char *p, int n) {
int ReadResponse(void) {
int exitcode;
struct timespec start = timespec_real();
struct timespec start = timespec_mono();
for (;;) {
char msg[5];
if (!Recv(msg, 5)) {
@ -354,7 +354,7 @@ int ReadResponse(void) {
break;
}
}
execute_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
execute_latency = timespec_tomicros(timespec_sub(timespec_mono(), start));
close(g_sock);
return exitcode;
}
@ -379,9 +379,9 @@ int RunOnHost(char *spec) {
for (;;) {
Connect();
EzFd(g_sock);
struct timespec start = timespec_real();
struct timespec start = timespec_mono();
err = EzHandshake2();
handshake_latency = timespec_tomicros(timespec_sub(timespec_real(), start));
handshake_latency = timespec_tomicros(timespec_sub(timespec_mono(), start));
if (!err)
break;
WARNF("handshake with %s:%d failed -0x%04x (%s)", //

View file

@ -453,8 +453,8 @@ void *ClientWorker(void *arg) {
char *addrstr, *origname;
unsigned char msg[4 + 1 + 4 + 4 + 4];
ts0 = timespec_real();
ts1 = timespec_real();
ts0 = timespec_mono();
ts1 = timespec_mono();
SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, g_psk);
defer(FreeClient, client);
@ -466,14 +466,14 @@ void *ClientWorker(void *arg) {
addrstr = DescribeAddress(&client->addr);
DEBUF("%s %s %s", DescribeAddress(&g_servaddr), "accepted", addrstr);
DEBUF("it took %'zu us to handshake client",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
// get the executable
ts1 = timespec_real();
ts2 = timespec_real();
ts1 = timespec_mono();
ts2 = timespec_mono();
Recv(client, msg, sizeof(msg));
DEBUF("it took %'zu us to receive #1",
timespec_tomicros(timespec_sub(timespec_real(), ts2)));
timespec_tomicros(timespec_sub(timespec_mono(), ts2)));
if (READ32BE(msg) != RUNITD_MAGIC) {
WARNF("%s magic mismatch!", addrstr);
pthread_exit(0);
@ -486,19 +486,19 @@ void *ClientWorker(void *arg) {
filesize = READ32BE(msg + 9);
crc = READ32BE(msg + 13);
origname = gc(calloc(1, namesize + 1));
ts2 = timespec_real();
ts2 = timespec_mono();
Recv(client, origname, namesize);
DEBUF("it took %'zu us to receive #2",
timespec_tomicros(timespec_sub(timespec_real(), ts2)));
timespec_tomicros(timespec_sub(timespec_mono(), ts2)));
VERBF("%s sent %#s (%'u bytes @ %#s)", addrstr, origname, filesize,
client->tmpexepath);
char *exedata = gc(malloc(filesize));
ts2 = timespec_real();
ts2 = timespec_mono();
Recv(client, exedata, filesize);
DEBUF("it took %'zu us to receive #3",
timespec_tomicros(timespec_sub(timespec_real(), ts2)));
timespec_tomicros(timespec_sub(timespec_mono(), ts2)));
DEBUF("it took %'zu us to receive executable from network",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (crc32_z(0, exedata, filesize) != crc) {
WARNF("%s crc mismatch! %#s", addrstr, origname);
pthread_exit(0);
@ -509,7 +509,7 @@ void *ClientWorker(void *arg) {
// condition can happen, where etxtbsy is raised by our execve
// we're using o_cloexec so it's guaranteed to fix itself fast
// thus we use an optimistic approach to avoid expensive locks
ts1 = timespec_real();
ts1 = timespec_mono();
sprintf(client->tmpexepath, "o/%s.XXXXXX",
basename(stripext(gc(strdup(origname)))));
int exefd = openatemp(AT_FDCWD, client->tmpexepath, 0, O_CLOEXEC, 0700);
@ -533,7 +533,7 @@ void *ClientWorker(void *arg) {
pthread_exit(0);
}
DEBUF("it took %'zu us to write executable to disk",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
// do the args
int i = 0;
@ -574,7 +574,7 @@ RetryOnEtxtbsyRaceCondition:
posix_spawnattr_t spawnattr;
posix_spawn_file_actions_t spawnfila;
sigemptyset(&sigmask);
started = timespec_real();
started = timespec_mono();
pipe2(client->pipe, O_CLOEXEC);
posix_spawnattr_init(&spawnattr);
posix_spawnattr_setflags(&spawnattr,
@ -584,11 +584,11 @@ RetryOnEtxtbsyRaceCondition:
posix_spawn_file_actions_adddup2(&spawnfila, g_bogusfd, 0);
posix_spawn_file_actions_adddup2(&spawnfila, client->pipe[1], 1);
posix_spawn_file_actions_adddup2(&spawnfila, client->pipe[1], 2);
ts1 = timespec_real();
ts1 = timespec_mono();
err = posix_spawn(&client->pid, client->tmpexepath, &spawnfila, &spawnattr,
args, environ);
DEBUF("it took %'zu us to call posix_spawn",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (err) {
if (err == ETXTBSY) {
goto RetryOnEtxtbsyRaceCondition;
@ -603,7 +603,7 @@ RetryOnEtxtbsyRaceCondition:
DEBUF("communicating %s[%d]", origname, client->pid);
struct timespec deadline =
timespec_add(timespec_real(), timespec_fromseconds(DEATH_CLOCK_SECONDS));
timespec_add(timespec_mono(), timespec_fromseconds(DEATH_CLOCK_SECONDS));
for (;;) {
if (g_interrupted) {
WARNF("killing %d %s and hanging up %d due to interrupt", client->fd,
@ -615,7 +615,7 @@ RetryOnEtxtbsyRaceCondition:
PrintProgramOutput(client);
pthread_exit(0);
}
struct timespec now = timespec_real();
struct timespec now = timespec_mono();
if (timespec_cmp(now, deadline) >= 0) {
WARNF("killing %s (pid %d) which timed out after %d seconds", origname,
client->pid, DEATH_CLOCK_SECONDS);
@ -626,11 +626,11 @@ RetryOnEtxtbsyRaceCondition:
fds[0].events = POLLIN;
fds[1].fd = client->pipe[0];
fds[1].events = POLLIN;
ts1 = timespec_real();
ts1 = timespec_mono();
int64_t ms = timespec_tomillis(timespec_sub(deadline, now));
events = poll(fds, ARRAYLEN(fds), MIN(ms, -1u));
DEBUF("it took %'zu us to call poll",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (events == -1) {
if (errno == EINTR) {
INFOF("poll interrupted");
@ -645,10 +645,10 @@ RetryOnEtxtbsyRaceCondition:
if (fds[0].revents) {
int received;
char buf[512];
ts1 = timespec_real();
ts1 = timespec_mono();
received = mbedtls_ssl_read(&ezssl, buf, sizeof(buf));
DEBUF("it took %'zu us to call mbedtls_ssl_read",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (!received) {
WARNF("%s client disconnected so killing worker %d", origname,
client->pid);
@ -673,10 +673,10 @@ RetryOnEtxtbsyRaceCondition:
}
if (fds[1].revents) {
char buf[512];
ts1 = timespec_real();
ts1 = timespec_mono();
ssize_t got = read(client->pipe[0], buf, sizeof(buf));
DEBUF("it took %'zu us to call read",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (got == -1) {
WARNF("got %s reading %s output", strerror(errno), origname);
goto HangupClientAndTerminateJob;
@ -694,10 +694,10 @@ RetryOnEtxtbsyRaceCondition:
WaitAgain:
DEBUF("waitpid");
struct rusage rusage;
ts1 = timespec_real();
ts1 = timespec_mono();
int wrc = wait4(client->pid, &wstatus, 0, &rusage);
DEBUF("it took %'zu us to call wait4",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (wrc == -1) {
if (errno == EINTR) {
WARNF("waitpid interrupted; killing %s pid %d", origname, client->pid);
@ -715,7 +715,7 @@ WaitAgain:
}
client->pid = 0;
int exitcode;
struct timespec ended = timespec_real();
struct timespec ended = timespec_mono();
int64_t micros = timespec_tomicros(timespec_sub(ended, started));
if (WIFEXITED(wstatus)) {
if (WEXITSTATUS(wstatus)) {
@ -750,18 +750,18 @@ WaitAgain:
AppendResourceReport(&client->output, &rusage, "\n");
PrintProgramOutput(client);
}
ts1 = timespec_real();
ts1 = timespec_mono();
SendProgramOutput(client);
SendExitMessage(exitcode);
mbedtls_ssl_close_notify(&ezssl);
DEBUF("it took %'zu us to send result to client",
timespec_tomicros(timespec_sub(timespec_real(), ts1)));
timespec_tomicros(timespec_sub(timespec_mono(), ts1)));
if (etxtbsy_tries > 1) {
WARNF("encountered %d ETXTBSY race conditions spawning %s",
etxtbsy_tries - 1, origname);
}
DEBUF("it took %'zu us TO DO EVERYTHING",
timespec_tomicros(timespec_sub(timespec_real(), ts0)));
timespec_tomicros(timespec_sub(timespec_mono(), ts0)));
pthread_exit(0);
}

View file

@ -18,6 +18,7 @@
*/
#include "libc/assert.h"
#include "libc/calls/struct/timespec.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/kprintf.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
@ -26,36 +27,19 @@
#define MAXIMUM 1e9
#define ITERATIONS 10
void TestSleepRealRelative(void) {
void TestSleepRelative(int clock) {
printf("\n");
printf("testing: clock_nanosleep(CLOCK_REALTIME) with relative "
"timeout\n");
printf("testing: clock_nanosleep(%s) with relative timeout\n",
DescribeClockName(clock));
for (long nanos = 1; nanos < (long)MAXIMUM; nanos *= 2) {
struct timespec t1, t2, wf;
wf = timespec_fromnanos(nanos);
clock_gettime(CLOCK_REALTIME, &t1);
if (clock_gettime(clock, &t1))
return;
for (int i = 0; i < ITERATIONS; ++i) {
npassert(!clock_nanosleep(CLOCK_REALTIME, 0, &wf, 0));
npassert(!clock_nanosleep(clock, 0, &wf, 0));
}
clock_gettime(CLOCK_REALTIME, &t2);
long took = timespec_tonanos(timespec_sub(t2, t1)) / ITERATIONS;
printf("%,12ld ns sleep took %,12ld ns delta %,12ld ns\n", nanos, took,
took - nanos);
}
}
void TestSleepMonoRelative(void) {
printf("\n");
printf("testing: clock_nanosleep(CLOCK_MONOTONIC) with relative "
"timeout\n");
for (long nanos = 1; nanos < (long)MAXIMUM; nanos *= 2) {
struct timespec t1, t2, wf;
wf = timespec_fromnanos(nanos);
clock_gettime(CLOCK_REALTIME, &t1);
for (int i = 0; i < ITERATIONS; ++i) {
npassert(!clock_nanosleep(CLOCK_MONOTONIC, 0, &wf, 0));
}
clock_gettime(CLOCK_REALTIME, &t2);
clock_gettime(clock, &t2);
long took = timespec_tonanos(timespec_sub(t2, t1)) / ITERATIONS;
printf("%,12ld ns sleep took %,12ld ns delta %,12ld ns\n", nanos, took,
took - nanos);
@ -63,6 +47,8 @@ void TestSleepMonoRelative(void) {
}
int main(int argc, char *argv[]) {
TestSleepRealRelative();
TestSleepMonoRelative();
TestSleepRelative(CLOCK_REALTIME);
TestSleepRelative(CLOCK_MONOTONIC);
TestSleepRelative(CLOCK_REALTIME_COARSE);
TestSleepRelative(CLOCK_MONOTONIC_COARSE);
}