mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-08 20:28:30 +00:00
Add missing ICANON features
This commit is contained in:
parent
dd8544c3bd
commit
03875beadb
22 changed files with 526 additions and 251 deletions
|
@ -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)", //
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue