Compare commits

...
27 Commits
Author SHA1 Message Date
Justine Tunney 4a7dd31567 Release Cosmopolitan v3.9.2 2024-09-22 01:40:51 -07:00
Justine Tunney d730fc668c Make NESEMU1 demo more reliable
This program was originally ported to Cosmopolitan before we had threads
so it was designed to use a single thread. That caused issues for people
with slower computers, like an Intel Core i5, where Gyarados would go so
slow that the audio would skip. I would also get audio skipping when the
terminal was put in full screen mode. Now we use two threads and smarter
timing, so NESEMU1 should go reliably fast on everyone's computer today.
2024-09-22 01:21:10 -07:00
Justine Tunney e975245102 Upgrade to superconfigure z0.0.56 2024-09-22 01:21:10 -07:00
Justine Tunney 126a44dc49 Write more tests attempting to break windows
This time I haven't succeeded in breaking anything which is a good sign.
2024-09-22 01:21:10 -07:00
Gabriel Ravier 476926790a Make printf %La test-case work properly on AArch64 (#1298)
As the size of long double changes between x86 and AArch64, this results
in one of the printf a conversion specifier test-cases getting different
output between the two. Note that both outputs (and a few more) are 100%
standards-conforming, but the testcase currently only expects a specific
one - the one that had been seen on x86 when initially writing the test.

This patch fixes the testcase so it accepts either of those two outputs.
2024-09-22 01:21:03 -07:00
Justine Tunney dd8c4dbd7d Write more tests for signal handling
There's now a much stronger level of assurance that signaling on Windows
will be atomic, low-latency, low tail latency, and shall never deadlock.
2024-09-21 05:24:56 -07:00
Justine Tunney 0e59afb403 Fix conflicting RTTI related symbol 2024-09-19 20:34:43 -07:00
Justine Tunney f68fc1f815 Put more thought into new signaling code 2024-09-19 20:21:33 -07:00
Justine Tunney 6107eb38f9 Fix m=tinylinux build 2024-09-19 04:25:34 -07:00
Justine Tunney d50f4c02f6 Make revision to previous change 2024-09-19 03:29:39 -07:00
Justine Tunney 0d74673213 Introduce interprocess signaling on Windows
This change gets rsync working without any warning or errors. On Windows
we now create a bunch of C:\var\sig\x\y.pid shared memory files, so sigs
can be delivered between processes. WinMain() creates this file when the
process starts. If the program links signaling system calls then we make
a thread at startup too, which allows asynchronous delivery each quantum
and cancelation points can spot these signals potentially faster on wait

See #1240
2024-09-19 03:02:13 -07:00
Justine Tunney 8527462b95 Fix ECHILD with WNOHANG on Windows
This change along with a patch for rsync's safe_write() function that'll
that'll soon be added to superconfigure, gets rsync working. There's one
remaining issue (which isn't a blocker) which is how rsync logs an error
about abnormal process termination since there's currently no way for us
to send non-fatal signals between processes. rsync in cosmos is restored

Fixes #1240
2024-09-18 23:26:02 -07:00
Justine Tunney 8313dca982 Show file descriptors on crash on Windows 2024-09-18 21:53:09 -07:00
Justine Tunney 87a6669900 Make more Windows socket fixes and improvements
This change makes send() / sendto() always block on Windows. It's needed
because poll(POLLOUT) doesn't guarantee a socket is immediately writable
on Windows, and it caused rsync to fail because it made that assumption.
The only exception is when a SO_SNDTIMEO is specified which will EAGAIN.

Tests are added confirming MSG_WAITALL and MSG_NOSIGNAL work as expected
on all our supported OSes. Most of the platform-specific MSG_FOO magnums
have been deleted, with the exception of MSG_FASTOPEN. Your --strace log
will now show MSG_FOO flags as symbols rather than numbers.

I've also removed cv_wait_example_test because it's 0.3% flaky with Qemu
under system load since it depends on a process being readily scheduled.
2024-09-18 20:29:42 -07:00
Justine Tunney ce2fbf9325 Write network audio programs 2024-09-18 17:17:02 -07:00
Steven Dee (Jōshin) 1bfb348403 Add weak self make_shared variant (#1299)
This extends the CTL version of make_shared with functionality not found
in the STL, with inspiration taken from Rust's Rc class.
2024-09-17 15:46:23 -07:00
Justine Tunney aaed879ec7 Release Cosmopolitan v3.9.1 2024-09-17 02:55:07 -07:00
Justine Tunney 8201ef2b3d Fix regression in package.ape build tool 2024-09-17 02:54:17 -07:00
Justine Tunney b1c9801897 Support more TCP socket options on Windows 2024-09-17 02:46:05 -07:00
Justine Tunney f7754ab608 Fix strace result code for recv() 2024-09-17 02:16:56 -07:00
Justine Tunney 96abe91c29 Reveal another Qemu bug 2024-09-17 01:31:55 -07:00
Justine Tunney bb7942e557 Improve socket option story 2024-09-17 01:17:07 -07:00
Justine Tunney b14dddcc18 Emulate Linux socket timeout signaling on Windows 2024-09-17 00:24:08 -07:00
Justine Tunney 65e425fbca Slightly optimize iovec on Windows 2024-09-16 21:36:22 -07:00
Justine Tunney 774c67fcd3 Make send() block in non-blocking mode 2024-09-16 21:09:28 -07:00
Justine Tunney 3c58ecd00c Fix bug with send() on Windows in O_NONBLOCK mode
There is a bug in WIN32 where using CancelIoEx() on an overlapped i/o op
initiated by WSASend() will cause WSAGetOverlappedResult() to report the
operation failed when it actually succeeded. We now work around that, by
having send and sendto initially consult WSAPoll() on O_NONBLOCK sockets
2024-09-16 20:49:58 -07:00
Justine Tunney 5aa970bc4e Fix strace logging of ipv6 port 2024-09-16 02:19:17 -07:00
213 changed files with 3008 additions and 1117 deletions

No files matched your search

+1
View File
@@ -279,6 +279,7 @@ include dsp/scale/BUILD.mk # │
include dsp/mpeg/BUILD.mk # │
include dsp/tty/BUILD.mk # │
include dsp/audio/BUILD.mk # │
include dsp/prog/BUILD.mk # │
include dsp/BUILD.mk # │
include third_party/stb/BUILD.mk # │
include third_party/mbedtls/BUILD.mk # │
+68 -8
View File
@@ -5,6 +5,7 @@
#include "exception.h"
#include "is_base_of.h"
#include "is_constructible.h"
#include "is_convertible.h"
#include "remove_extent.h"
#include "unique_ptr.h"
@@ -437,6 +438,9 @@ class weak_ptr
template<typename U>
friend class shared_ptr;
template<typename U, typename... Args>
friend shared_ptr<U> make_shared(Args&&...);
element_type* p = nullptr;
__::shared_ref* rc = nullptr;
};
@@ -497,19 +501,75 @@ shared_ptr<T>::shared_ptr(U* const p, D d)
}
}
// Our make_shared supports passing a weak self reference as the first parameter
// to your constructor, e.g.:
//
// struct Tree : ctl::weak_self_base
// {
// ctl::shared_ptr<Tree> l, r;
// ctl::weak_ptr<Tree> parent;
// Tree(weak_ptr<Tree> const& self, auto&& l2, auto&& r2)
// : l(ctl::forward<decltype(l2)>(l2)),
// r(ctl::forward<decltype(r2)>(r2))
// {
// if (l) l->parent = self;
// if (r) r->parent = self;
// }
// };
//
// int main() {
// auto t = ctl::make_shared<Tree>(
// ctl::make_shared<Tree>(nullptr, nullptr), nullptr);
// return t->l->parent.lock().get() == t.get() ? 0 : 1;
// }
//
// As shown, passing the parameter at object construction time lets you complete
// object construction without needing a separate Init method. But because we go
// off spec as far as the STL is concerned, there is a potential ambiguity where
// you might have a constructor with a weak_ptr first parameter that is intended
// to be something other than a self-reference. So this feature is opt-in by way
// of inheriting from the following struct.
struct weak_self_base
{};
template<typename T, typename... Args>
shared_ptr<T>
make_shared(Args&&... args)
{
auto rc = __::shared_emplace<T>::make();
rc->construct(forward<Args>(args)...);
shared_ptr<T> r;
r.p = &rc->t;
r.rc = rc.release();
if constexpr (is_base_of_v<enable_shared_from_this<T>, T>) {
r->weak_this = r;
unique_ptr rc = __::shared_emplace<T>::make();
if constexpr (is_base_of_v<weak_self_base, T> &&
is_constructible_v<T, const weak_ptr<T>&, Args...>) {
// A __::shared_ref has a virtual weak reference that is owned by all of
// the shared references. We can avoid some unnecessary refcount changes
// by "borrowing" that reference and passing it to the constructor, then
// promoting it to a shared reference by swapping it with the shared_ptr
// that we return.
weak_ptr<T> w;
w.p = &rc->t;
w.rc = rc.get();
try {
rc->construct(const_cast<const weak_ptr<T>&>(w),
forward<Args>(args)...);
} catch (...) {
w.p = nullptr;
w.rc = nullptr;
throw;
}
rc.release();
shared_ptr<T> r;
swap(r.p, w.p);
swap(r.rc, w.rc);
return r;
} else {
rc->construct(forward<Args>(args)...);
shared_ptr<T> r;
r.p = &rc->t;
r.rc = rc.release();
if constexpr (is_base_of_v<enable_shared_from_this<T>, T>) {
r->weak_this = r;
}
return r;
}
return r;
}
} // namespace ctl
+1
View File
@@ -6,4 +6,5 @@ o/$(MODE)/dsp: o/$(MODE)/dsp/audio \
o/$(MODE)/dsp/core \
o/$(MODE)/dsp/mpeg \
o/$(MODE)/dsp/scale \
o/$(MODE)/dsp/prog \
o/$(MODE)/dsp/tty
+3 -3
View File
@@ -469,16 +469,16 @@ COSMOAUDIO_ABI int cosmoaudio_poll(struct CosmoAudio* ca,
if (in_out_writeFrames && 1u + *in_out_writeFrames > ca->outputBufferFrames)
return COSMOAUDIO_ENOBUF;
for (;;) {
int done = 0;
int done = 1;
ma_uint32 readable = 0;
ma_uint32 writable = 0;
if (in_out_readFrames) {
readable = ma_pcm_rb_available_read(&ca->input);
done |= readable >= (ma_uint32)*in_out_readFrames;
done &= readable >= (ma_uint32)*in_out_readFrames;
}
if (in_out_writeFrames) {
writable = ma_pcm_rb_available_write(&ca->output);
done |= writable >= (ma_uint32)*in_out_writeFrames;
done &= writable >= (ma_uint32)*in_out_writeFrames;
}
if (done) {
if (in_out_readFrames)
+43
View File
@@ -0,0 +1,43 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += DSP_PROG
DSP_PROG_FILES := $(wildcard dsp/prog/*)
DSP_PROG_HDRS = $(filter %.h,$(DSP_PROG_FILES))
DSP_PROG_SRCS = $(filter %.c,$(DSP_PROG_FILES))
DSP_PROG_OBJS = $(DSP_PROG_SRCS:%.c=o/$(MODE)/%.o)
DSP_PROG_COMS = $(DSP_PROG_SRCS:%.c=o/$(MODE)/%)
DSP_PROG_BINS = $(DSP_PROG_COMS) $(DSP_PROG_COMS:%=%.dbg)
DSP_PROG_DIRECTDEPS = \
DSP_AUDIO \
LIBC_CALLS \
LIBC_INTRIN \
LIBC_NEXGEN32E \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_SYSV \
LIBC_TINYMATH \
THIRD_PARTY_MUSL \
DSP_PROG_DEPS := \
$(call uniq,$(foreach x,$(DSP_PROG_DIRECTDEPS),$($(x))))
o/$(MODE)/dsp/prog/prog.pkg: \
$(DSP_PROG_OBJS) \
$(foreach x,$(DSP_PROG_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/dsp/prog/%.dbg: \
$(DSP_PROG_DEPS) \
o/$(MODE)/dsp/prog/prog.pkg \
o/$(MODE)/dsp/prog/%.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
$(DSP_PROG_OBJS): dsp/prog/BUILD.mk
.PHONY: o/$(MODE)/dsp/prog
o/$(MODE)/dsp/prog: $(DSP_PROG_BINS)
+41
View File
@@ -0,0 +1,41 @@
#ifndef COSMOPOLITAN_DSP_PROG_LOUDNESS_H_
#define COSMOPOLITAN_DSP_PROG_LOUDNESS_H_
#include <math.h>
#include <stdio.h>
#define MIN_DECIBEL -60
#define MAX_DECIBEL 0
// computes root of mean squares
static double rms(float *p, int n) {
double s = 0;
for (int i = 0; i < n; ++i)
s += p[i] * p[i];
return sqrt(s / n);
}
// converts rms to decibel
static double rms_to_db(double rms) {
double db = 20 * log10(rms);
db = fmin(db, MAX_DECIBEL);
db = fmax(db, MIN_DECIBEL);
return db;
}
// char meter[21];
// format_decibel_meter(meter, 20, rms_to_db(rms(samps, count)))
static char *format_decibel_meter(char *meter, int width, double db) {
double range = MAX_DECIBEL - MIN_DECIBEL;
int filled = (db - MIN_DECIBEL) / range * width;
for (int i = 0; i < width; ++i) {
if (i < filled) {
meter[i] = '=';
} else {
meter[i] = ' ';
}
}
meter[width] = 0;
return meter;
}
#endif /* COSMOPOLITAN_DSP_PROG_LOUDNESS_H_ */
+127
View File
@@ -0,0 +1,127 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include <arpa/inet.h>
#include <assert.h>
#include <cosmoaudio.h>
#include <errno.h>
#include <math.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include "loudness.h"
/**
* @fileoverview plays audio from remote computer on speaker
* @see dsp/prog/sendaudio.c
*/
#define SAMPLING_RATE 44100
#define FRAMES_PER_SECOND 60
#define DEBUG_LOG 0
#define PORT 9834
#define CHUNK_FRAMES (SAMPLING_RATE / FRAMES_PER_SECOND)
static_assert(CHUNK_FRAMES * sizeof(short) < 1472,
"audio chunks won't fit in udp ethernet packet");
sig_atomic_t g_done;
void onsig(int sig) {
g_done = 1;
}
short toshort(float x) {
return fmaxf(-1, fminf(1, x)) * 32767;
}
float tofloat(short x) {
return x / 32768.f;
}
int main(int argc, char* argv[]) {
// listen on udp port for audio
int server;
if ((server = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror("socket");
return 3;
}
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(PORT)};
if (bind(server, (struct sockaddr*)&addr, sizeof(addr))) {
perror("bind");
return 4;
}
// setup signals
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = onsig;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
// configure cosmo audio
struct CosmoAudioOpenOptions cao = {0};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
cao.deviceType = kCosmoAudioDeviceTypePlayback;
cao.sampleRate = SAMPLING_RATE;
cao.bufferFrames = CHUNK_FRAMES * 2;
cao.debugLog = DEBUG_LOG;
cao.channels = 1;
// connect to microphone and speaker
int status;
struct CosmoAudio* ca;
status = cosmoaudio_open(&ca, &cao);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to open audio: %d\n", status);
return 5;
}
while (!g_done) {
// read from network
ssize_t got;
short buf16[CHUNK_FRAMES];
if ((got = read(server, buf16, CHUNK_FRAMES * sizeof(short))) == -1) {
if (errno == EINTR)
continue;
perror("read");
return 7;
}
if (got != CHUNK_FRAMES * sizeof(short)) {
fprintf(stderr, "warning: got partial audio frame\n");
continue;
}
// write to speaker
float buf32[CHUNK_FRAMES];
for (int i = 0; i < CHUNK_FRAMES; ++i)
buf32[i] = tofloat(buf16[i]);
cosmoaudio_poll(ca, 0, (int[]){CHUNK_FRAMES});
cosmoaudio_write(ca, buf32, CHUNK_FRAMES);
// print loudness in ascii
char meter[21];
double db = rms_to_db(rms(buf32, CHUNK_FRAMES));
format_decibel_meter(meter, 20, db);
printf("\r%s| %+6.2f dB", meter, db);
fflush(stdout);
}
// clean up resources
cosmoaudio_flush(ca);
cosmoaudio_close(ca);
close(server);
}
+149
View File
@@ -0,0 +1,149 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
│ To the extent possible under law, Justine Tunney has waived │
│ all copyright and related or neighboring rights to this file, │
│ as it is written in the following disclaimers: │
│ • http://unlicense.org/ │
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
╚─────────────────────────────────────────────────────────────────*/
#endif
#include <arpa/inet.h>
#include <assert.h>
#include <cosmoaudio.h>
#include <errno.h>
#include <math.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include "loudness.h"
/**
* @fileoverview sends audio from microphone to remote computer
* @see dsp/prog/recvaudio.c
*/
#define SAMPLING_RATE 44100
#define FRAMES_PER_SECOND 60
#define DEBUG_LOG 0
#define PORT 9834
#define CHUNK_FRAMES (SAMPLING_RATE / FRAMES_PER_SECOND)
static_assert(CHUNK_FRAMES * sizeof(short) < 1472,
"audio chunks won't fit in udp ethernet packet");
sig_atomic_t g_done;
void onsig(int sig) {
g_done = 1;
}
short toshort(float x) {
return fmaxf(-1, fminf(1, x)) * 32767;
}
float tofloat(short x) {
return x / 32768.f;
}
uint32_t host2ip(const char* host) {
uint32_t ip;
if ((ip = inet_addr(host)) != -1u)
return ip;
int rc;
struct addrinfo* ai = NULL;
struct addrinfo hint = {AI_NUMERICSERV, AF_INET, SOCK_STREAM, IPPROTO_TCP};
if ((rc = getaddrinfo(host, "0", &hint, &ai))) {
fprintf(stderr, "%s: %s\n", host, gai_strerror(rc));
exit(50 + rc);
}
ip = ntohl(((struct sockaddr_in*)ai->ai_addr)->sin_addr.s_addr);
freeaddrinfo(ai);
return ip;
}
int main(int argc, char* argv[]) {
if (argc != 2) {
fprintf(stderr, "%s: missing host argument\n", argv[0]);
return 1;
}
// get host argument
const char* remote_host = argv[1];
uint32_t ip = host2ip(remote_host);
// connect to server
int client;
if ((client = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
perror(remote_host);
return 3;
}
struct sockaddr_in addr = {.sin_family = AF_INET,
.sin_port = htons(PORT),
.sin_addr.s_addr = htonl(ip)};
if (connect(client, (struct sockaddr*)&addr, sizeof(addr))) {
perror(remote_host);
return 4;
}
// setup signals
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = onsig;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
// configure cosmo audio
struct CosmoAudioOpenOptions cao = {0};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
cao.deviceType = kCosmoAudioDeviceTypeCapture;
cao.sampleRate = SAMPLING_RATE;
cao.bufferFrames = CHUNK_FRAMES * 2;
cao.debugLog = DEBUG_LOG;
cao.channels = 1;
// connect to microphone and speaker
int status;
struct CosmoAudio* ca;
status = cosmoaudio_open(&ca, &cao);
if (status != COSMOAUDIO_SUCCESS) {
fprintf(stderr, "failed to open audio: %d\n", status);
return 5;
}
while (!g_done) {
// read from microphone
float buf32[CHUNK_FRAMES];
cosmoaudio_poll(ca, (int[]){CHUNK_FRAMES}, 0);
cosmoaudio_read(ca, buf32, CHUNK_FRAMES);
short buf16[CHUNK_FRAMES];
for (int i = 0; i < CHUNK_FRAMES; ++i)
buf16[i] = toshort(buf32[i]);
// send to server
if (write(client, buf16, CHUNK_FRAMES * sizeof(short)) == -1) {
if (errno == EINTR && g_done)
break;
perror(remote_host);
return 7;
}
// print loudness in ascii
char meter[21];
double db = rms_to_db(rms(buf32, CHUNK_FRAMES));
format_decibel_meter(meter, 20, db);
printf("\r%s| %+6.2f dB", meter, db);
fflush(stdout);
}
// clean up resources
cosmoaudio_close(ca);
close(client);
}
+4
View File
@@ -150,6 +150,10 @@ o/$(MODE)/examples/picol.o: private \
CPPFLAGS += \
-DSTACK_FRAME_UNLIMITED
o/$(MODE)/examples/nesemu1.o: private \
CPPFLAGS += \
-O3
o/$(MODE)/examples/picol.dbg: \
$(EXAMPLES_DEPS) \
o/$(MODE)/examples/picol.o \
+121 -134
View File
@@ -13,7 +13,6 @@
#include "dsp/tty/tty.h"
#include "libc/assert.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/itimerval.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/termios.h"
@@ -36,20 +35,17 @@
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fileno.h"
#include "libc/sysv/consts/itimer.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/prio.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h"
#include "libc/thread/thread.h"
#include "libc/time.h"
#include "libc/x/xasprintf.h"
#include "libc/x/xsigaction.h"
#include "libc/zip.h"
#include "third_party/getopt/getopt.internal.h"
#include "third_party/libcxx/__atomic/atomic.h"
#include "third_party/libcxx/vector"
#include "tool/viz/lib/knobs.h"
@@ -124,15 +120,6 @@ typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
static const struct itimerval kNesFps = {
{0, 1. / FPS * 1e6},
{0, 1. / FPS * 1e6},
};
struct Frame {
char *p, *w, *mem;
};
struct Action {
int code;
int wait;
@@ -148,15 +135,13 @@ struct ZipGames {
char** p;
};
static int frame_;
static size_t vtsize_;
static const struct timespec kNesFps = {0, 1. / FPS * 1e9};
static bool artifacts_;
static long tyn_, txn_;
static struct Frame vf_[2];
static const char* inputfn_;
static struct Status status_;
static volatile bool exited_;
static volatile bool timeout_;
static volatile bool resized_;
static struct CosmoAudio* ca_;
static struct TtyRgb* ttyrgb_;
@@ -165,7 +150,7 @@ static struct ZipGames zipgames_;
static struct Action arrow_, button_;
static struct SamplingSolution* ssy_;
static struct SamplingSolution* ssx_;
static unsigned char pixels_[3][DYN][DXN];
static unsigned char (*pixels_)[3][DYN][DXN];
static unsigned char palette_[3][64][512][3];
static int joy_current_[2], joy_next_[2], joypos_[2];
@@ -173,6 +158,11 @@ static int keyframes_ = 10;
static enum TtyBlocksSelection blocks_ = kTtyBlocksUnicode;
static enum TtyQuantizationAlgorithm quant_ = kTtyQuantXterm256;
static struct timespec deadline_;
static std::atomic<void*> pixels_ready_;
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static int Clamp(int v) {
return MAX(0, MIN(255, v));
}
@@ -232,18 +222,8 @@ void InitPalette(void) {
}
}
static ssize_t Write(int fd, const void* p, size_t n) {
int rc;
sigset_t ss, oldss;
sigfillset(&ss);
sigprocmask(SIG_SETMASK, &ss, &oldss);
rc = write(fd, p, n);
sigprocmask(SIG_SETMASK, &oldss, 0);
return rc;
}
static void WriteString(const char* s) {
Write(STDOUT_FILENO, s, strlen(s));
write(STDOUT_FILENO, s, strlen(s));
}
void Exit(int rc) {
@@ -264,28 +244,10 @@ void OnCtrlC(void) {
exited_ = true;
}
void OnTimer(void) {
timeout_ = true;
}
void OnResize(void) {
resized_ = true;
}
void OnPiped(void) {
exited_ = true;
}
void OnSigChld(void) {
waitpid(-1, 0, WNOHANG);
cosmoaudio_close(ca_);
ca_ = 0;
}
void InitFrame(struct Frame* f) {
f->p = f->w = f->mem = (char*)realloc(f->mem, vtsize_);
}
long ChopAxis(long dn, long sn) {
while (HALF(sn) > dn) {
sn = HALF(sn);
@@ -308,11 +270,6 @@ void GetTermSize(void) {
G = (unsigned char*)realloc(G, tyn_ * txn_);
B = (unsigned char*)realloc(B, tyn_ * txn_);
ttyrgb_ = (struct TtyRgb*)realloc(ttyrgb_, tyn_ * txn_ * 4);
vtsize_ = ((tyn_ * txn_ * strlen("\e[48;2;255;48;2;255m▄")) +
(tyn_ * strlen("\e[0m\r\n")) + 128);
frame_ = 0;
InitFrame(&vf_[0]);
InitFrame(&vf_[1]);
WriteString("\e[0m\e[H\e[J");
resized_ = false;
}
@@ -320,11 +277,7 @@ void GetTermSize(void) {
void IoInit(void) {
GetTermSize();
xsigaction(SIGINT, (void*)OnCtrlC, 0, 0, NULL);
xsigaction(SIGPIPE, (void*)OnPiped, 0, 0, NULL);
xsigaction(SIGWINCH, (void*)OnResize, 0, 0, NULL);
xsigaction(SIGALRM, (void*)OnTimer, 0, 0, NULL);
xsigaction(SIGCHLD, (void*)OnSigChld, 0, 0, NULL);
setitimer(ITIMER_REAL, &kNesFps, NULL);
ttyhidecursor(STDOUT_FILENO);
ttyraw(kTtySigs);
ttyquantsetup(quant_, kTtyQuantRgb, blocks_);
@@ -461,57 +414,29 @@ ssize_t ReadKeyboard(void) {
return rc;
}
bool HasVideo(struct Frame* f) {
return f->w < f->p;
}
bool HasPendingVideo(void) {
return HasVideo(&vf_[0]) || HasVideo(&vf_[1]);
}
struct Frame* FlipFrameBuffer(void) {
frame_ = !frame_;
return &vf_[frame_];
}
void TransmitVideo(void) {
ssize_t rc;
struct Frame* f;
f = &vf_[frame_];
if (!HasVideo(f))
f = FlipFrameBuffer();
if ((rc = Write(STDOUT_FILENO, f->w, f->p - f->w)) != -1) {
f->w += rc;
} else if (errno == EAGAIN) {
// slow teletypewriter
} else if (errno == EPIPE) {
Exit(0);
}
}
void ScaleVideoFrameToTeletypewriter(void) {
void ScaleVideoFrameToTeletypewriter(unsigned char (*pixels)[3][DYN][DXN]) {
long y, x, yn, xn;
yn = DYN, xn = DXN;
while (HALF(yn) > tyn_ || HALF(xn) > txn_) {
if (HALF(xn) > txn_) {
Magikarp2xX(DYN, DXN, pixels_[0], yn, xn);
Magikarp2xX(DYN, DXN, pixels_[1], yn, xn);
Magikarp2xX(DYN, DXN, pixels_[2], yn, xn);
Magikarp2xX(DYN, DXN, (*pixels)[0], yn, xn);
Magikarp2xX(DYN, DXN, (*pixels)[1], yn, xn);
Magikarp2xX(DYN, DXN, (*pixels)[2], yn, xn);
xn = HALF(xn);
}
if (HALF(yn) > tyn_) {
Magikarp2xY(DYN, DXN, pixels_[0], yn, xn);
Magikarp2xY(DYN, DXN, pixels_[1], yn, xn);
Magikarp2xY(DYN, DXN, pixels_[2], yn, xn);
Magikarp2xY(DYN, DXN, (*pixels)[0], yn, xn);
Magikarp2xY(DYN, DXN, (*pixels)[1], yn, xn);
Magikarp2xY(DYN, DXN, (*pixels)[2], yn, xn);
yn = HALF(yn);
}
}
GyaradosUint8(tyn_, txn_, R, DYN, DXN, pixels_[0], tyn_, txn_, yn, xn, 0, 255,
ssy_, ssx_, true);
GyaradosUint8(tyn_, txn_, G, DYN, DXN, pixels_[1], tyn_, txn_, yn, xn, 0, 255,
ssy_, ssx_, true);
GyaradosUint8(tyn_, txn_, B, DYN, DXN, pixels_[2], tyn_, txn_, yn, xn, 0, 255,
ssy_, ssx_, true);
GyaradosUint8(tyn_, txn_, R, DYN, DXN, (*pixels)[0], tyn_, txn_, yn, xn, 0,
255, ssy_, ssx_, true);
GyaradosUint8(tyn_, txn_, G, DYN, DXN, (*pixels)[1], tyn_, txn_, yn, xn, 0,
255, ssy_, ssx_, true);
GyaradosUint8(tyn_, txn_, B, DYN, DXN, (*pixels)[2], tyn_, txn_, yn, xn, 0,
255, ssy_, ssx_, true);
for (y = 0; y < tyn_; ++y) {
for (x = 0; x < txn_; ++x) {
ttyrgb_[y * txn_ + x] =
@@ -528,55 +453,104 @@ void KeyCountdown(struct Action* a) {
}
}
void PollAndSynchronize(void) {
do {
if (ReadKeyboard() == -1) {
if (errno != EINTR)
Exit(1);
if (exited_)
Exit(0);
if (resized_)
GetTermSize();
}
} while (!timeout_);
TransmitVideo();
timeout_ = false;
KeyCountdown(&arrow_);
KeyCountdown(&button_);
joy_next_[0] = arrow_.code | button_.code;
joy_next_[1] = arrow_.code | button_.code;
}
void Raster(void) {
struct Frame* f;
void Raster(unsigned char (*pixels)[3][DYN][DXN]) {
struct TtyRgb bg = {0x12, 0x34, 0x56, 0};
struct TtyRgb fg = {0x12, 0x34, 0x56, 0};
ScaleVideoFrameToTeletypewriter();
f = &vf_[!frame_];
f->p = f->w = f->mem;
f->p = stpcpy(f->p, "\e[0m\e[H");
f->p = ttyraster(f->p, ttyrgb_, tyn_, txn_, bg, fg);
ScaleVideoFrameToTeletypewriter(pixels);
char* ansi = (char*)malloc((tyn_ * txn_ * strlen("\e[48;2;255;48;2;255m▄")) +
(tyn_ * strlen("\e[0m\r\n")) + 128);
char* p = ansi;
p = stpcpy(p, "\e[0m\e[H");
p = ttyraster(p, ttyrgb_, tyn_, txn_, bg, fg);
free(pixels);
if (status_.wait) {
status_.wait--;
f->p = stpcpy(f->p, "\e[0m\e[H");
f->p = stpcpy(f->p, status_.text);
p = stpcpy(p, "\e[0m\e[H");
p = stpcpy(p, status_.text);
}
size_t n = p - ansi;
ssize_t wrote;
for (size_t i = 0; i < n; i += wrote) {
if ((wrote = write(STDOUT_FILENO, ansi + i, n - i)) == -1) {
exited_ = true;
break;
}
}
free(ansi);
}
void* RasterThread(void* arg) {
sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGINT);
sigaddset(&ss, SIGHUP);
sigaddset(&ss, SIGQUIT);
sigaddset(&ss, SIGTERM);
sigaddset(&ss, SIGPIPE);
sigprocmask(SIG_SETMASK, &ss, 0);
for (;;) {
unsigned char(*pixels)[3][DYN][DXN];
pthread_mutex_lock(&lock);
while (!(pixels = (unsigned char(*)[3][DYN][DXN])pixels_ready_.load()))
pthread_cond_wait(&cond, &lock);
pixels_ready_.store(0);
pthread_mutex_unlock(&lock);
if (resized_)
GetTermSize();
Raster(pixels);
}
PollAndSynchronize();
}
void FlushScanline(unsigned py) {
if (py == DYN - 1) {
if (!timeout_)
Raster();
timeout_ = false;
if (py != DYN - 1)
return;
pthread_mutex_lock(&lock);
if (!pixels_ready_) {
pixels_ready_.store(pixels_);
pixels_ = 0;
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&lock);
if (!pixels_)
pixels_ = (unsigned char(*)[3][DYN][DXN])malloc(3 * DYN * DXN);
if (exited_)
Exit(0);
do {
struct timespec now = timespec_mono();
struct timespec remain = timespec_subz(deadline_, now);
int remain_ms = timespec_tomillis(remain);
struct pollfd fds[] = {{STDIN_FILENO, POLLIN}};
int got = poll(fds, 1, remain_ms);
if (got == -1) {
if (errno == EINTR)
continue;
Exit(1);
}
if (got == 1) {
do {
if (ReadKeyboard() == -1) {
if (errno == EINTR)
continue;
Exit(1);
}
} while (0);
}
KeyCountdown(&arrow_);
KeyCountdown(&button_);
joy_next_[0] = arrow_.code | button_.code;
joy_next_[1] = arrow_.code | button_.code;
now = timespec_mono();
do
deadline_ = timespec_add(deadline_, kNesFps);
while (timespec_cmp(deadline_, now) <= 0);
} while (0);
}
static void PutPixel(unsigned px, unsigned py, unsigned pixel, int offset) {
static unsigned prev;
pixels_[0][py][px] = palette_[offset][prev % 64][pixel][2];
pixels_[1][py][px] = palette_[offset][prev % 64][pixel][1];
pixels_[2][py][px] = palette_[offset][prev % 64][pixel][0];
(*pixels_)[0][py][px] = palette_[offset][prev % 64][pixel][2];
(*pixels_)[1][py][px] = palette_[offset][prev % 64][pixel][1];
(*pixels_)[2][py][px] = palette_[offset][prev % 64][pixel][0];
prev = pixel;
}
@@ -1732,8 +1706,18 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
return 3;
}
// initialize screen
pixels_ = (unsigned char(*)[3][DYN][DXN])malloc(3 * DYN * DXN);
InitPalette();
// start raster thread
errno_t err;
pthread_t th;
if ((err = pthread_create(&th, 0, RasterThread, 0))) {
fprintf(stderr, "pthread_create: %s\n", strerror(err));
exit(1);
}
// open speaker
struct CosmoAudioOpenOptions cao = {};
cao.sizeofThis = sizeof(struct CosmoAudioOpenOptions);
@@ -1742,6 +1726,9 @@ int PlayGame(const char* romfile, const char* opt_tasfile) {
cao.channels = 1;
cosmoaudio_open(&ca_, &cao);
// initialize time
deadline_ = timespec_add(timespec_mono(), kNesFps);
// Read the ROM file header
u8 rom16count = fgetc(fp);
u8 vrom8count = fgetc(fp);
+1 -1
View File
@@ -40,7 +40,7 @@ static textwindows int sys_clock_nanosleep_nt_impl(int clock,
return 0;
msdelay = timespec_tomillis(timespec_sub(abs, now));
msdelay = MIN(msdelay, -1u);
if (_park_norestart(msdelay, waitmask))
if (_park_norestart(msdelay, waitmask) == -1)
return -1;
}
}
+3 -19
View File
@@ -17,26 +17,10 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/atomic.h"
#include "libc/fmt/internal.h"
#include "libc/intrin/atomic.h"
#include "libc/runtime/internal.h"
static textwindows char16_t *itoa16(char16_t p[21], uint64_t x) {
char t;
size_t a, b, i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
// This function is called very early by WinMain().
textwindows char16_t *__create_pipe_name(char16_t *a) {
char16_t *p = a;
@@ -44,9 +28,9 @@ textwindows char16_t *__create_pipe_name(char16_t *a) {
static atomic_uint x;
while (*q)
*p++ = *q++;
p = itoa16(p, __pid);
p = __itoa16(p, __pid);
*p++ = '-';
p = itoa16(p, atomic_fetch_add(&x, 1));
p = __itoa16(p, atomic_fetch_add(&x, 1));
*p = 0;
return a;
}
+37 -7
View File
@@ -17,9 +17,17 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/enum/wait.h"
#include "libc/nt/events.h"
#include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
#ifdef __x86_64__
@@ -28,17 +36,39 @@
// raises ECANCELED if this POSIX thread was canceled in masked mode
textwindows static int _park_thread(uint32_t msdelay, sigset_t waitmask,
bool restartable) {
if (__sigcheck(waitmask, restartable) == -1)
return -1;
int expect = 0;
atomic_int futex = 0;
struct PosixThread *pt = _pthread_self();
// perform the wait operation
intptr_t sigev;
if (!(sigev = CreateEvent(0, 0, 0, 0)))
return __winerr();
pt->pt_event = sigev;
pt->pt_blkmask = waitmask;
atomic_store_explicit(&pt->pt_blocker, &futex, memory_order_release);
bool32 ok = WaitOnAddress(&futex, &expect, sizeof(int), msdelay);
atomic_store_explicit(&pt->pt_blocker, PT_BLOCKER_EVENT,
memory_order_release);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
int sig = 0;
uint32_t ws = 0;
if (!_is_canceled() &&
!(_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))))
ws = WaitForSingleObject(sigev, msdelay);
//!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!/!//
atomic_store_explicit(&pt->pt_blocker, 0, memory_order_release);
if (ok && __sigcheck(waitmask, restartable) == -1)
CloseHandle(sigev);
// recursion is now safe
if (ws == -1)
return __winerr();
int handler_was_called = 0;
if (sig)
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel())
return -1;
if (handler_was_called & SIG_HANDLED_NO_RESTART)
return eintr();
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (!restartable)
return eintr();
return 0;
}
+8
View File
@@ -17,13 +17,21 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#ifdef __x86_64__
textwindows int sys_pause_nt(void) {
int rc;
// we don't strictly need to block signals, but it reduces signal
// delivery latency, by preventing other threads from delivering a
// signal asynchronously. it takes about ~5us to deliver a signal
// using SetEvent() whereas it takes ~30us to use SuspendThread(),
// GetThreadContext(), SetThreadContext(), and ResumeThread().
BLOCK_SIGNALS;
while (!(rc = _park_norestart(-1u, 0)))
donothing;
ALLOW_SIGNALS;
return rc;
}
+1 -5
View File
@@ -16,7 +16,6 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/createfileflags.internal.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
@@ -170,14 +169,11 @@ sys_readwrite_nt(int fd, void *data, size_t size, ssize_t offset,
}
// the i/o operation was successfully canceled
if (got_eagain) {
unassert(!got_sig);
if (got_eagain)
return eagain();
}
// it's now reasonable to report semaphore creation error
if (other_error) {
unassert(!got_sig);
errno = __dos2errno(other_error);
return -1;
}
+86 -45
View File
@@ -25,6 +25,7 @@
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/dce.h"
#include "libc/errno.h"
@@ -32,12 +33,13 @@
#include "libc/intrin/bsf.h"
#include "libc/intrin/describebacktrace.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/strace.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/context.h"
#include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/processcreationflags.h"
#include "libc/nt/enum/signal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/events.h"
@@ -46,6 +48,7 @@
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/symbols.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
@@ -58,6 +61,8 @@
* @fileoverview Cosmopolitan Signals for Windows.
*/
#define STKSZ 65536
struct SignalFrame {
unsigned rva;
unsigned flags;
@@ -80,7 +85,7 @@ textwindows bool __sig_ignored(int sig) {
textwindows void __sig_delete(int sig) {
struct Dll *e;
atomic_fetch_and_explicit(&__sig.pending, ~(1ull << (sig - 1)),
atomic_fetch_and_explicit(__sig.process, ~(1ull << (sig - 1)),
memory_order_relaxed);
_pthread_lock();
for (e = dll_last(_pthread_list); e; e = dll_prev(_pthread_list, e))
@@ -108,7 +113,7 @@ static textwindows int __sig_getter(atomic_ulong *sigs, sigset_t masked) {
textwindows int __sig_get(sigset_t masked) {
int sig;
if (!(sig = __sig_getter(&__get_tls()->tib_sigpending, masked)))
sig = __sig_getter(&__sig.pending, masked);
sig = __sig_getter(__sig.process, masked);
return sig;
}
@@ -131,7 +136,24 @@ static textwindows wontreturn void __sig_terminate(int sig) {
TerminateThisProcess(sig);
}
static textwindows bool __sig_start(struct PosixThread *pt, int sig,
textwindows static void __sig_wake(struct PosixThread *pt, int sig) {
atomic_int *blocker;
blocker = atomic_load_explicit(&pt->pt_blocker, memory_order_acquire);
if (!blocker)
return;
// threads can create semaphores on an as-needed basis
if (blocker == PT_BLOCKER_EVENT) {
STRACE("%G set %d's event object", sig, _pthread_tid(pt));
SetEvent(pt->pt_event);
return;
}
// all other blocking ops that aren't overlap should use futexes
// we force restartable futexes to churn by waking w/o releasing
STRACE("%G waking %d's futex", sig, _pthread_tid(pt));
WakeByAddressSingle(blocker);
}
textwindows static bool __sig_start(struct PosixThread *pt, int sig,
unsigned *rva, unsigned *flags) {
*rva = __sighandrvas[sig];
*flags = __sighandflags[sig];
@@ -145,6 +167,7 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
STRACE("enqueing %G on %d", sig, _pthread_tid(pt));
atomic_fetch_or_explicit(&pt->tib->tib_sigpending, 1ull << (sig - 1),
memory_order_relaxed);
__sig_wake(pt, sig);
return false;
}
if (*rva == (intptr_t)SIG_DFL) {
@@ -154,7 +177,7 @@ static textwindows bool __sig_start(struct PosixThread *pt, int sig,
return true;
}
static textwindows sigaction_f __sig_handler(unsigned rva) {
textwindows static sigaction_f __sig_handler(unsigned rva) {
atomic_fetch_add_explicit(&__sig.count, 1, memory_order_relaxed);
return (sigaction_f)(__executable_start + rva);
}
@@ -179,6 +202,7 @@ textwindows int __sig_raise(volatile int sig, int sic) {
unsigned rva, flags;
struct PosixThread *pt = _pthread_self();
if (__sig_start(pt, sig, &rva, &flags)) {
if (flags & SA_RESETHAND) {
STRACE("resetting %G handler", sig);
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
@@ -223,34 +247,15 @@ textwindows int __sig_relay(int sig, int sic, sigset_t waitmask) {
return handler_was_called;
}
// cancels blocking operations being performed by signaled thread
textwindows void __sig_cancel(struct PosixThread *pt, int sig, unsigned flags) {
atomic_int *blocker;
blocker = atomic_load_explicit(&pt->pt_blocker, memory_order_acquire);
if (!blocker) {
STRACE("%G sent to %d asynchronously", sig, _pthread_tid(pt));
return;
}
// threads can create semaphores on an as-needed basis
if (blocker == PT_BLOCKER_EVENT) {
STRACE("%G set %d's event object", sig, _pthread_tid(pt));
SetEvent(pt->pt_event);
return;
}
// all other blocking ops that aren't overlap should use futexes
// we force restartable futexes to churn by waking w/o releasing
STRACE("%G waking %d's futex", sig, _pthread_tid(pt));
WakeByAddressSingle(blocker);
}
// the user's signal handler callback is wrapped with this trampoline
static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
int sig = sf->si.si_signo;
struct CosmoTib *tib = __get_tls();
struct PosixThread *pt = (struct PosixThread *)tib->tib_pthread;
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
for (;;) {
// update the signal mask in preparation for signal handller
// update the signal mask in preparation for signal handler
sigset_t blocksigs = __sighandmask[sig];
if (!(sf->flags & SA_NODEFER))
blocksigs |= 1ull << (sig - 1);
@@ -297,12 +302,16 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
return 0;
}
// we can't preempt threads that masked sig or are blocked
if (atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire) &
(1ull << (sig - 1))) {
// we can't preempt threads that masked sigs or are blocked. we also
// need to ensure we don't overflow the target thread's stack if many
// signals need to be delivered at once. we also need to make sure two
// threads can't deadlock by killing each other at the same time.
if ((atomic_load_explicit(&pt->tib->tib_sigmask, memory_order_acquire) &
(1ull << (sig - 1))) ||
atomic_exchange_explicit(&pt->pt_intoff, 1, memory_order_acquire)) {
atomic_fetch_or_explicit(&pt->tib->tib_sigpending, 1ull << (sig - 1),
memory_order_relaxed);
__sig_cancel(pt, sig, flags);
__sig_wake(pt, sig);
return 0;
}
@@ -316,17 +325,16 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
uintptr_t th = _pthread_syshand(pt);
if (atomic_load_explicit(&pt->tib->tib_sigpending, memory_order_acquire) &
(1ull << (sig - 1))) {
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
return 0;
}
// take control of thread
// suspending the thread happens asynchronously
// however getting the context blocks until it's frozen
static pthread_spinlock_t killer_lock;
pthread_spin_lock(&killer_lock);
if (SuspendThread(th) == -1u) {
STRACE("SuspendThread failed w/ %d", GetLastError());
pthread_spin_unlock(&killer_lock);
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
return ESRCH;
}
struct NtContext nc;
@@ -334,10 +342,9 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
if (!GetThreadContext(th, &nc)) {
STRACE("GetThreadContext failed w/ %d", GetLastError());
ResumeThread(th);
pthread_spin_unlock(&killer_lock);
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
return ESRCH;
}
pthread_spin_unlock(&killer_lock);
// we can't preempt threads that masked sig or are blocked
// we can't preempt threads that are running in win32 code
@@ -349,7 +356,8 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
atomic_fetch_or_explicit(&pt->tib->tib_sigpending, 1ull << (sig - 1),
memory_order_relaxed);
ResumeThread(th);
__sig_cancel(pt, sig, flags);
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
__sig_wake(pt, sig);
return 0;
}
@@ -382,10 +390,11 @@ static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
nc.Rsp = sp;
if (!SetThreadContext(th, &nc)) {
STRACE("SetThreadContext failed w/ %d", GetLastError());
atomic_store_explicit(&pt->pt_intoff, 0, memory_order_release);
return ESRCH;
}
ResumeThread(th);
__sig_cancel(pt, sig, flags);
__sig_wake(pt, sig);
return 0;
}
@@ -399,6 +408,7 @@ textwindows int __sig_kill(struct PosixThread *pt, int sig, int sic) {
}
// sends signal to any other thread
// this should only be called by non-posix threads
textwindows void __sig_generate(int sig, int sic) {
struct Dll *e;
struct PosixThread *pt, *mark = 0;
@@ -410,7 +420,7 @@ textwindows void __sig_generate(int sig, int sic) {
STRACE("terminating on %G due to no handler", sig);
__sig_terminate(sig);
}
if (atomic_load_explicit(&__sig.pending, memory_order_acquire) &
if (atomic_load_explicit(__sig.process, memory_order_acquire) &
(1ull << (sig - 1))) {
return;
}
@@ -445,10 +455,11 @@ textwindows void __sig_generate(int sig, int sic) {
}
_pthread_unlock();
if (mark) {
// no lock needed since current thread is nameless and formless
__sig_killer(mark, sig, sic);
_pthread_unref(mark);
} else {
atomic_fetch_or_explicit(&__sig.pending, 1ull << (sig - 1),
atomic_fetch_or_explicit(__sig.process, 1ull << (sig - 1),
memory_order_relaxed);
}
ALLOW_SIGNALS;
@@ -591,6 +602,9 @@ static textwindows int __sig_console_sig(uint32_t dwCtrlType) {
}
__msabi textwindows dontinstrument bool32 __sig_console(uint32_t dwCtrlType) {
// win32 launches a thread to deliver ctrl-c and ctrl-break when typed
// it only happens when kNtEnableProcessedInput is in play on console.
// otherwise we need to wait until read-nt.c discovers that keystroke.
struct CosmoTib tls;
__bootstrap_tls(&tls, __builtin_frame_address(0));
__sig_generate(__sig_console_sig(dwCtrlType), SI_KERNEL);
@@ -602,13 +616,39 @@ __msabi textwindows dontinstrument bool32 __sig_console(uint32_t dwCtrlType) {
// didn't have the SA_RESTART flag, and `2`, which means SA_RESTART
// handlers were called (or `3` if both were the case).
textwindows int __sig_check(void) {
int sig;
if ((sig = __sig_get(atomic_load_explicit(&__get_tls()->tib_sigmask,
memory_order_acquire)))) {
return __sig_raise(sig, SI_KERNEL);
} else {
return 0;
int sig, res = 0;
while ((sig = __sig_get(atomic_load_explicit(&__get_tls()->tib_sigmask,
memory_order_acquire))))
res |= __sig_raise(sig, SI_KERNEL);
return res;
}
// background thread for delivering inter-process signals asynchronously
// this checks for undelivered process-wide signals, once per scheduling
// quantum, which on windows should be every ~15ms or so, unless somehow
// the process was tuned to have more fine-grained event timing. we want
// signals to happen faster when possible; that happens when cancelation
// points, e.g. read need to wait on i/o; they too check for new signals
textwindows dontinstrument static uint32_t __sig_worker(void *arg) {
struct CosmoTib tls;
__bootstrap_tls(&tls, __builtin_frame_address(0));
char *sp = __builtin_frame_address(0);
__maps_track((char *)(((uintptr_t)sp + __pagesize - 1) & -__pagesize) - STKSZ,
STKSZ);
for (;;) {
// dequeue all pending signals and fire them off. if there's no
// thread that can handle them then __sig_generate will requeue
// those signals back to __sig.process; hence the need for xchg
unsigned long sigs =
atomic_exchange_explicit(__sig.process, 0, memory_order_acq_rel);
while (sigs) {
int sig = bsfl(sigs) + 1;
sigs &= ~(1ull << (sig - 1));
__sig_generate(sig, SI_KERNEL);
}
Sleep(POLL_INTERVAL_MS);
}
return 0;
}
__attribute__((__constructor__(10))) textstartup void __sig_init(void) {
@@ -616,6 +656,7 @@ __attribute__((__constructor__(10))) textstartup void __sig_init(void) {
return;
AddVectoredExceptionHandler(true, (void *)__sig_crash);
SetConsoleCtrlHandler((void *)__sig_console, true);
CreateThread(0, STKSZ, __sig_worker, 0, kNtStackSizeParamIsAReservation, 0);
}
#endif /* __x86_64__ */
+7 -2
View File
@@ -1,6 +1,8 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_
#include "libc/atomic.h"
#include "libc/calls/struct/sigset.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/thread/posixthread.internal.h"
#define SIG_HANDLED_NO_RESTART 1
@@ -9,8 +11,8 @@
COSMOPOLITAN_C_START_
struct Signals {
_Atomic(uint64_t) pending;
_Atomic(uint64_t) count;
atomic_ulong *process;
atomic_ulong count;
};
extern struct Signals __sig;
@@ -27,5 +29,8 @@ void __sig_delete(int);
void __sig_generate(int, int);
void __sig_init(void);
__msabi char16_t *__sig_process_path(char16_t *, uint32_t, int);
__msabi atomic_ulong *__sig_map_process(int, int);
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_CALLS_SIGNALS_INTERNAL_H_ */
+8 -8
View File
@@ -23,18 +23,18 @@
#include "libc/sysv/errfuns.h"
textwindows int __sigcheck(sigset_t waitmask, bool restartable) {
int sig, handler_was_called;
int sig, handler_was_called = 0;
if (_check_cancel() == -1)
return -1;
if (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
handler_was_called = _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
while (_weaken(__sig_get) && (sig = _weaken(__sig_get)(waitmask))) {
handler_was_called |= _weaken(__sig_relay)(sig, SI_KERNEL, waitmask);
if (_check_cancel() == -1)
return -1;
if (handler_was_called & SIG_HANDLED_NO_RESTART)
return eintr();
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (!restartable)
return eintr();
}
if (handler_was_called & SIG_HANDLED_NO_RESTART)
return eintr();
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (!restartable)
return eintr();
return 0;
}
+1 -1
View File
@@ -53,7 +53,7 @@ int sigpending(sigset_t *pending) {
}
rc = 0;
} else if (IsWindows()) {
*pending = atomic_load_explicit(&__sig.pending, memory_order_acquire) |
*pending = atomic_load_explicit(__sig.process, memory_order_acquire) |
atomic_load_explicit(&__get_tls()->tib_sigpending,
memory_order_acquire);
rc = 0;
+7
View File
@@ -53,8 +53,15 @@ int sigsuspend(const sigset_t *ignore) {
} else {
sigset_t waitmask = ignore ? *ignore : 0;
if (IsWindows() || IsMetal()) {
// we don't strictly need to block signals, but it reduces signal
// delivery latency, by preventing other threads from delivering a
// signal asynchronously. it takes about ~5us to deliver a signal
// using SetEvent() whereas it takes ~30us to use SuspendThread(),
// GetThreadContext(), SetThreadContext(), and ResumeThread().
BLOCK_SIGNALS;
while (!(rc = _park_norestart(-1u, waitmask)))
donothing;
ALLOW_SIGNALS;
} else {
rc = sys_sigsuspend((uint64_t[2]){waitmask}, 8);
}
+2
View File
@@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_FMT_STRTOL_H_
#include "libc/ctype.h"
#include "libc/errno.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/str/str.h"
#define CONSUME_SPACES(t, s, c) \
@@ -48,5 +49,6 @@
int __vcscanf(int (*)(void *), int (*)(int, void *), void *, const char *,
va_list);
int __fmt(void *, void *, const char *, va_list, int *);
__msabi char16_t *__itoa16(char16_t[21], uint64_t);
#endif /* COSMOPOLITAN_LIBC_FMT_STRTOL_H_ */
+1
View File
@@ -21,6 +21,7 @@ extern const struct MagnumStr kErrnoDocs[];
extern const struct MagnumStr kErrnoNames[];
extern const struct MagnumStr kFcntlCmds[];
extern const struct MagnumStr kIpOptnames[];
extern const struct MagnumStr kIpv6Optnames[];
extern const struct MagnumStr kOpenFlags[];
extern const struct MagnumStr kRlimitNames[];
extern const struct MagnumStr kSignalNames[];
+1 -1
View File
@@ -4,7 +4,7 @@
#define __COSMOPOLITAN_MAJOR__ 3
#define __COSMOPOLITAN_MINOR__ 9
#define __COSMOPOLITAN_PATCH__ 0
#define __COSMOPOLITAN_PATCH__ 2
#define __COSMOPOLITAN__ \
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
__COSMOPOLITAN_PATCH__)
+2
View File
@@ -125,6 +125,8 @@ o/$(MODE)/libc/intrin/kerrnodocs.o: libc/intrin/kerrnodocs.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/intrin/kipoptnames.o: libc/intrin/kipoptnames.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/intrin/kipv6optnames.o: libc/intrin/kipv6optnames.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/intrin/kerrnonames.o: libc/intrin/kerrnonames.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/intrin/kfcntlcmds.o: libc/intrin/kfcntlcmds.S
+4 -2
View File
@@ -8,8 +8,8 @@ struct thatispacked DescribeFlags {
const char *name;
};
const char *_DescribeFlags(char *, size_t, const struct DescribeFlags *,
size_t, const char *, unsigned) libcesque;
const char *_DescribeFlags(char *, size_t, const struct DescribeFlags *, size_t,
const char *, unsigned) libcesque;
const char *_DescribeArchPrctlCode(char[12], int) libcesque;
const char *_DescribeCancelState(char[12], int, int *) libcesque;
@@ -27,6 +27,7 @@ const char *_DescribeItimer(char[12], int) libcesque;
const char *_DescribeMapFlags(char[64], int) libcesque;
const char *_DescribeMapping(char[8], int, int) libcesque;
const char *_DescribeMremapFlags(char[30], int) libcesque;
const char *_DescribeMsg(char[16], int) libcesque;
const char *_DescribeMsyncFlags(char[48], int) libcesque;
const char *_DescribeNtConsoleInFlags(char[256], uint32_t) libcesque;
const char *_DescribeNtConsoleOutFlags(char[128], uint32_t) libcesque;
@@ -84,6 +85,7 @@ const char *_DescribeWhichPrio(char[12], int) libcesque;
#define DescribeMapFlags(x) _DescribeMapFlags(alloca(64), x)
#define DescribeMapping(x, y) _DescribeMapping(alloca(8), x, y)
#define DescribeMremapFlags(x) _DescribeMremapFlags(alloca(30), x)
#define DescribeMsg(x) _DescribeMsg(alloca(16), x)
#define DescribeMsyncFlags(x) _DescribeMsyncFlags(alloca(48), x)
#define DescribeNtConsoleInFlags(x) _DescribeNtConsoleInFlags(alloca(256), x)
#define DescribeNtConsoleOutFlags(x) _DescribeNtConsoleOutFlags(alloca(128), x)
+36
View File
@@ -0,0 +1,36 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2024 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/intrin/describeflags.h"
#include "libc/macros.h"
#include "libc/sysv/consts/msg.h"
const char *_DescribeMsg(char buf[16], int x) {
const struct DescribeFlags kMsgFlags[] = {
{MSG_FASTOPEN, "FASTOPEN"}, // order matters
{MSG_OOB, "OOB"}, //
{MSG_PEEK, "PEEK"}, //
{MSG_DONTROUTE, "DONTROUTE"}, //
{MSG_DONTWAIT, "DONTWAIT"}, //
{MSG_WAITALL, "WAITALL"}, //
{MSG_NOSIGNAL, "NOSIGNAL"}, //
{MSG_TRUNC, "TRUNC"}, //
{MSG_CTRUNC, "CTRUNC"}, //
};
return _DescribeFlags(buf, 16, kMsgFlags, ARRAYLEN(kMsgFlags), "MSG_", x);
}
+8
View File
@@ -49,6 +49,14 @@ const char *_DescribeSockOptname(char buf[32], int l, int x) {
*p++ = '_';
*p = 0;
ms = kIpOptnames;
} else if (l == SOL_IPV6) {
*p++ = 'I';
*p++ = 'P';
*p++ = 'V';
*p++ = '6';
*p++ = '_';
*p = 0;
ms = kIpv6Optnames;
} else {
ms = 0;
}
+21 -10
View File
@@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ Copyright 2024 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
@@ -16,11 +16,22 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/macros.h"
#include "libc/fmt/internal.h"
// __cxxabiv1::__function_type_info (?)
// Because Clang in MODE=dbg doesn't respect -fno-rtti
.balign 8
_ZTVN10__cxxabiv120__function_type_infoE:
.quad 0
.endobj _ZTVN10__cxxabiv120__function_type_infoE,globl
__msabi textwindows dontinstrument char16_t *__itoa16(char16_t p[21],
uint64_t x) {
char t;
size_t a, b, i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
+10 -1
View File
@@ -32,9 +32,18 @@
.underrun
kIpOptnames:
.e IP_TOS,"TOS" // int
.e IP_MTU,"MTU" // int
.e IP_TTL,"TTL" // int
.e IP_MTU,"MTU" // int
.e IP_HDRINCL,"HDRINCL" // bool32
.e IP_OPTIONS,"OPTIONS"
.e IP_RECVTTL,"RECVTTL"
.e IP_ADD_MEMBERSHIP,"ADD_MEMBERSHIP"
.e IP_DROP_MEMBERSHIP,"DROP_MEMBERSHIP"
.e IP_MULTICAST_IF,"MULTICAST_IF"
.e IP_MULTICAST_LOOP,"MULTICAST_LOOP"
.e IP_MULTICAST_TTL,"MULTICAST_TTL"
.e IP_PKTINFO,"PKTINFO"
.e IP_RECVTOS,"RECVTOS"
.long MAGNUM_TERMINATOR
.endobj kIpOptnames,globl,hidden
.overrun
+52
View File
@@ -0,0 +1,52 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
│ vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/macros.h"
.macro .e e s
.long \e - kIpv6Optnames
.long .L\@ - kIpv6Optnames
.rodata.str1.1
.L\@: .string "\s"
.previous
.endm
.section .rodata
.balign 4
.underrun
kIpv6Optnames:
.e IPV6_V6ONLY,"V6ONLY"
.e IPV6_CHECKSUM,"CHECKSUM"
.e IPV6_JOIN_GROUP,"JOIN_GROUP"
.e IPV6_LEAVE_GROUP,"LEAVE_GROUP"
.e IPV6_MULTICAST_HOPS,"MULTICAST_HOPS"
.e IPV6_MULTICAST_IF,"MULTICAST_IF"
.e IPV6_MULTICAST_LOOP,"MULTICAST_LOOP"
.e IPV6_UNICAST_HOPS,"UNICAST_HOPS"
.e IPV6_RECVTCLASS,"RECVTCLASS"
.e IPV6_TCLASS,"TCLASS"
.e IPV6_DONTFRAG,"DONTFRAG"
.e IPV6_HOPLIMIT,"HOPLIMIT"
.e IPV6_HOPOPTS,"HOPOPTS"
.e IPV6_PKTINFO,"PKTINFO"
.e IPV6_RECVRTHDR,"RECVRTHDR"
.e IPV6_RTHDR,"RTHDR"
.long MAGNUM_TERMINATOR
.endobj kIpv6Optnames,globl,hidden
.overrun
+1
View File
@@ -47,6 +47,7 @@ kSockOptnames:
.e SO_RCVLOWAT,"RCVLOWAT" // int
.e SO_SNDLOWAT,"SNDLOWAT" // int
.e SO_ERROR,"ERROR" // int
.e SO_OOBINLINE,"OOBINLINE" // int
.long MAGNUM_TERMINATOR
.endobj kSockOptnames,globl,hidden
.overrun
+1 -2
View File
@@ -44,9 +44,8 @@ void __sig_unblock(sigset_t m) {
if (IsWindows() || IsMetal()) {
if (__tls_enabled) {
atomic_store_explicit(&__get_tls()->tib_sigmask, m, memory_order_release);
if (_weaken(__sig_check)) {
if (_weaken(__sig_check))
_weaken(__sig_check)();
}
}
} else {
sys_sigprocmask(SIG_SETMASK, &m, 0);
+124
View File
@@ -0,0 +1,124 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│ vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi │
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2024 Justine Alexandra Roberts Tunney │
│ │
│ Permission to use, copy, modify, and/or distribute this software for │
│ any purpose with or without fee is hereby granted, provided that the │
│ above copyright notice and this permission notice appear in all copies. │
│ │
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/atomic.h"
#include "libc/calls/sig.internal.h"
#include "libc/fmt/internal.h"
#include "libc/nt/createfile.h"
#include "libc/nt/enum/accessmask.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/filemovemethod.h"
#include "libc/nt/enum/filesharemode.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#ifdef __x86_64__
// cut back on code size and avoid setting errno
// this code is a mandatory dependency of winmain
__msabi extern typeof(CloseHandle) *const __imp_CloseHandle;
__msabi extern typeof(CreateDirectory) *const __imp_CreateDirectoryW;
__msabi extern typeof(CreateFile) *const __imp_CreateFileW;
__msabi extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW;
__msabi extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx;
__msabi extern typeof(SetEndOfFile) *const __imp_SetEndOfFile;
__msabi extern typeof(SetFilePointer) *const __imp_SetFilePointer;
__msabi extern typeof(GetEnvironmentVariable)
*const __imp_GetEnvironmentVariableW;
// Generates C:\ProgramData\cosmo\sig\x\y.pid like path
__msabi textwindows dontinstrument char16_t *__sig_process_path(
char16_t *path, uint32_t pid, int create_directories) {
char16_t buf[3];
char16_t *p = path;
uint32_t vlen = __imp_GetEnvironmentVariableW(u"SYSTEMDRIVE", buf, 3);
*p++ = vlen == 2 ? buf[0] : 'C';
*p++ = ':';
*p++ = '\\';
*p++ = 'P';
*p++ = 'r';
*p++ = 'o';
*p++ = 'g';
*p++ = 'r';
*p++ = 'a';
*p++ = 'm';
*p++ = 'D';
*p++ = 'a';
*p++ = 't';
*p++ = 'a';
*p = 0;
if (create_directories)
__imp_CreateDirectoryW(path, 0);
*p++ = '\\';
*p++ = 'c';
*p++ = 'o';
*p++ = 's';
*p++ = 'm';
*p++ = 'o';
*p = 0;
if (create_directories)
__imp_CreateDirectoryW(path, 0);
*p++ = '\\';
*p++ = 's';
*p++ = 'i';
*p++ = 'g';
*p = 0;
if (create_directories)
__imp_CreateDirectoryW(path, 0);
*p++ = '\\';
p = __itoa16(p, (pid & 0x000ff800) >> 11);
*p = 0;
if (create_directories)
__imp_CreateDirectoryW(path, 0);
*p++ = '\\';
p = __itoa16(p, pid);
*p++ = '.';
*p++ = 'p';
*p++ = 'i';
*p++ = 'd';
*p = 0;
return path;
}
__msabi textwindows atomic_ulong *__sig_map_process(int pid, int disposition) {
char16_t path[128];
__sig_process_path(path, pid, disposition == kNtOpenAlways);
intptr_t hand = __imp_CreateFileW(path, kNtGenericRead | kNtGenericWrite,
kNtFileShareRead | kNtFileShareWrite, 0,
disposition, kNtFileAttributeNormal, 0);
if (hand == -1)
return 0;
__imp_SetFilePointer(hand, 8, 0, kNtFileBegin);
__imp_SetEndOfFile(hand);
intptr_t map = __imp_CreateFileMappingW(hand, 0, kNtPageReadwrite, 0, 8, 0);
if (!map) {
__imp_CloseHandle(hand);
return 0;
}
atomic_ulong *sigs = __imp_MapViewOfFileEx(map, kNtFileMapWrite, 0, 0, 8, 0);
__imp_CloseHandle(map);
__imp_CloseHandle(hand);
return sigs;
}
#endif /* __x86_64__ */
+5 -5
View File
@@ -17,6 +17,7 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
#include "libc/intrin/atomic.h"
@@ -34,7 +35,7 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
}
// get address of sigset to modify
_Atomic(uint64_t) *mask = &__get_tls()->tib_sigmask;
atomic_ulong *mask = &__get_tls()->tib_sigmask;
// handle read-only case
sigset_t oldmask;
@@ -46,6 +47,9 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
} else { // SIG_SETMASK
oldmask = atomic_exchange_explicit(mask, *neu, memory_order_acq_rel);
}
if (_weaken(__sig_check)) {
_weaken(__sig_check)();
}
} else {
oldmask = atomic_load_explicit(mask, memory_order_acquire);
}
@@ -55,10 +59,6 @@ textwindows int __sig_mask(int how, const sigset_t *neu, sigset_t *old) {
*old = oldmask;
}
if (_weaken(__sig_check)) {
_weaken(__sig_check)();
}
return 0;
}
+22
View File
@@ -16,17 +16,39 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/atomic.h"
#include "libc/calls/sig.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/internal.h"
#ifdef __x86_64__
__msabi extern typeof(DeleteFile) *const __imp_DeleteFileW;
__msabi extern typeof(TerminateProcess) *const __imp_TerminateProcess;
__msabi extern typeof(UnmapViewOfFile) *const __imp_UnmapViewOfFile;
/**
* Terminates the calling process and all of its threads.
*/
textwindows dontinstrument void TerminateThisProcess(uint32_t dwWaitStatus) {
// delete sig file
char16_t path[128];
atomic_ulong *real;
atomic_ulong fake = 0;
real = __sig.process;
__sig.process = &fake;
__imp_UnmapViewOfFile(real);
__imp_DeleteFileW(__sig_process_path(path, __pid, false));
// "When a process terminates itself, TerminateProcess stops execution
// of the calling thread and does not return." -Quoth MSDN
__imp_TerminateProcess(-1, dwWaitStatus);
__builtin_unreachable();
}
#endif /* __x86_64__ */
+5
View File
@@ -20,6 +20,7 @@
#include "libc/atomic.h"
#include "libc/calls/blockcancel.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
@@ -242,6 +243,10 @@ static relegated void ShowCrashReport(int err, int sig, siginfo_t *si,
}
kprintf("\n");
__print_maps(15);
if (g_fds.n)
kprintf("\n");
__printfds(g_fds.p, g_fds.n);
kprintf("\n");
if (__argv)
for (i = 0; i < __argc; ++i)
kprintf("%s ", __argv[i]);
+1 -2
View File
@@ -19,7 +19,6 @@
#include "ape/sections.internal.h"
#include "libc/assert.h"
#include "libc/fmt/conv.h"
#include "libc/intrin/weaken.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
@@ -53,7 +52,7 @@ bool __grow(void *pp, size_t *capacity, size_t itemsize, size_t extra) {
n1 = *capacity;
n2 = (*p ? n1 + (n1 >> 1) : MAX(4, INITIAL_CAPACITY / itemsize)) + extra;
if (!ckd_mul(&t1, n1, itemsize) && !ckd_mul(&t2, n2, itemsize)) {
if (_weaken(realloc) && (p2 = _weaken(realloc)(p1, ROUNDUP(t2, 32)))) {
if ((p2 = realloc(p1, ROUNDUP(t2, 32)))) {
if (!p1 && *p)
memcpy(p2, *p, t1);
bzero((char *)p2 + t1, t2 - t1);
+4
View File
@@ -225,6 +225,10 @@ bool32 GetVolumeInformationByHandle(int64_t hFile,
char16_t *opt_out_lpFileSystemNameBuffer,
uint32_t nFileSystemNameSize);
uint32_t SetFilePointer(intptr_t hFile, int32_t lDistanceToMove,
long *opt_inout_lpDistanceToMoveHigh,
uint32_t dwMoveMethod);
#if ShouldUseMsabiAttribute()
#include "libc/nt/thunk/files.inc"
#endif /* ShouldUseMsabiAttribute() */
+18
View File
@@ -0,0 +1,18 @@
#include "libc/nt/codegen.h"
.imp kernel32,__imp_SetFilePointer,SetFilePointer
.text.windows
.ftrace1
SetFilePointer:
.ftrace2
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
mov __imp_SetFilePointer(%rip),%rax
jmp __sysv2nt
#elif defined(__aarch64__)
mov x0,#0
ret
#endif
.endfn SetFilePointer,globl
.previous
+1
View File
@@ -259,6 +259,7 @@ imp 'SetEvent' SetEvent kernel32 1
imp 'SetFileAttributes' SetFileAttributesW kernel32 2
imp 'SetFileCompletionNotificationModes' SetFileCompletionNotificationModes kernel32 2
imp 'SetFileInformationByHandle' SetFileInformationByHandle kernel32 4
imp 'SetFilePointer' SetFilePointer kernel32 4
imp 'SetFileTime' SetFileTime kernel32 4
imp 'SetFileValidData' SetFileValidData kernel32 2
imp 'SetHandleCount' SetHandleCount kernel32 1
+10 -5
View File
@@ -196,9 +196,13 @@ textwindows void WinMainForked(void) {
int64_t reader;
int64_t savetsc;
uint32_t varlen;
atomic_ulong *sigproc;
char16_t fvar[21 + 1 + 21 + 1];
struct Fds *fds = __veil("r", &g_fds);
// save signal pointer
sigproc = __sig.process;
// check to see if the process was actually forked
// this variable should have the pipe handle numba
varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar));
@@ -295,12 +299,13 @@ textwindows void WinMainForked(void) {
fds->p[1].handle = GetStdHandle(kNtStdOutputHandle);
fds->p[2].handle = GetStdHandle(kNtStdErrorHandle);
// restore signal pointer
__sig.process = sigproc;
// restore the crash reporting stuff
#if SYSDEBUG
RemoveVectoredExceptionHandler(oncrash);
#endif
if (_weaken(__sig_init))
_weaken(__sig_init)();
// jump back into function below
longjmp(jb, 1);
@@ -460,15 +465,15 @@ textwindows int sys_fork_nt(uint32_t dwCreationFlags) {
__morph_tls();
__tls_enabled = true;
// the child's pending signals is initially empty
atomic_store_explicit(&__sig.pending, 0, memory_order_relaxed);
atomic_store_explicit(&tib->tib_sigpending, 0, memory_order_relaxed);
// re-apply code morphing for function tracing
if (ftrace_stackdigs) {
if (ftrace_stackdigs)
_weaken(__hook)(_weaken(ftrace_hook), _weaken(GetSymbolTable)());
}
// reset core runtime services
__proc_wipe();
WipeKeystrokes();
if (_weaken(__sig_init))
_weaken(__sig_init)();
if (_weaken(__itimer_wipe))
_weaken(__itimer_wipe)();
// notify pthread join
+44 -8
View File
@@ -16,16 +16,22 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall-nt.internal.h"
#include "libc/errno.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/ctrlevent.h"
#include "libc/nt/enum/processaccess.h"
#include "libc/nt/errors.h"
#include "libc/nt/memory.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
@@ -36,31 +42,39 @@
textwindows int sys_kill_nt(int pid, int sig) {
// validate api usage
if (!(0 <= sig && sig <= 64)) {
if (!(0 <= sig && sig <= 64))
return einval();
}
// XXX: NT doesn't really have process groups. For instance the
// CreateProcess() flag for starting a process group actually
// just does an "ignore ctrl-c" internally.
if (pid < -1) {
if (pid < -1)
pid = -pid;
}
// no support for kill all yet
if (pid == -1) {
if (pid == -1)
return einval();
}
// just call raise() if we're targeting self
if (pid <= 0 || pid == getpid()) {
if (sig) {
if (pid <= 0) {
// if pid is 0 or -1 then kill the processes beneath us too.
// this isn't entirely right but it's closer to being right.
// having this behavior is helpful for servers like redbean.
struct Dll *e;
BLOCK_SIGNALS;
__proc_lock();
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e))
TerminateProcess(PROC_CONTAINER(e)->handle, sig);
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e)) {
atomic_ulong *sigproc;
struct Proc *pr = PROC_CONTAINER(e);
if (sig != 9 && (sigproc = __sig_map_process(pid, kNtOpenExisting))) {
atomic_fetch_or_explicit(sigproc, 1ull << (sig - 1),
memory_order_release);
} else {
TerminateProcess(pr->handle, sig);
}
}
__proc_unlock();
ALLOW_SIGNALS;
}
@@ -71,6 +85,10 @@ textwindows int sys_kill_nt(int pid, int sig) {
}
// find existing handle we own for process
//
// this step should come first to verify process existence. this is
// because there's no guarantee that just because the shared memory
// file exists, the process actually exists.
int64_t handle, closeme = 0;
if (!(handle = __proc_handle(pid))) {
if ((handle = OpenProcess(kNtProcessTerminate, false, pid))) {
@@ -80,6 +98,24 @@ textwindows int sys_kill_nt(int pid, int sig) {
}
}
// attempt to signal via shared memory file
//
// now that we know the process exists, if it has a shared memory file
// then we can be reasonably certain it's a cosmo process which should
// be trusted to deliver its signal, unless it's a nine exterminations
if (pid > 0 && sig != 9) {
atomic_ulong *sigproc;
if ((sigproc = __sig_map_process(pid, kNtOpenExisting))) {
if (sig > 0)
atomic_fetch_or_explicit(sigproc, 1ull << (sig - 1),
memory_order_release);
UnmapViewOfFile(sigproc);
if (closeme)
CloseHandle(closeme);
return 0;
}
}
// perform actual kill
// process will report WIFSIGNALED with WTERMSIG(sig)
bool32 ok = TerminateProcess(handle, sig);
+11
View File
@@ -29,6 +29,17 @@
* The impact of this action can be terminating the process, or
* interrupting it to request something happen.
*
* On Windows, signals are delivered between processes using shared
* memory files stored in C:\ProgramData\cosmo\sig\x\y.pid which hold
* the process signal mask. Any process that can access these files can
* signal a cosmo process. The targeting process will then notice that a
* signal has been added and delivers to any thread as soon as possible.
*
* On Windows, the concept of a process group isn't fully implemented.
* Saying `kill(0, sig)` will deliver `sig` to all direct descendent
* processes. Saying `kill(-pid, sig)` will be the same as saying
* `kill(pid, sig)`.
*
* @param pid can be:
* >0 signals one process by id
* =0 signals all processes in current process group
+3 -1
View File
@@ -23,6 +23,7 @@
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/cosmo.h"
#include "libc/errno.h"
#include "libc/fmt/wintime.internal.h"
@@ -169,7 +170,7 @@ static textwindows dontinstrument uint32_t __proc_worker(void *arg) {
// wait for something to happen
if (n == 64) {
millis = 5;
millis = POLL_INTERVAL_MS;
} else {
millis = -1u;
handles[n++] = __proc.onbirth;
@@ -323,6 +324,7 @@ textwindows int64_t __proc_search(int pid) {
int64_t handle = 0;
BLOCK_SIGNALS;
__proc_lock();
// TODO(jart): we should increment a reference count when returning
for (e = dll_first(__proc.list); e; e = dll_next(__proc.list, e)) {
if (pid == PROC_CONTAINER(e)->pid) {
handle = PROC_CONTAINER(e)->handle;
+10 -8
View File
@@ -88,18 +88,20 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
__proc_lock();
CheckForZombies:
int rc = __proc_check(pid, wstatus, rusage);
// if there's no zombies left
// check if there's any living processes
if (!rc && dll_is_empty(__proc.list)) {
__proc_unlock();
return echild();
}
// otherwise return zombie or zero
if (rc || (options & WNOHANG)) {
__proc_unlock();
return rc;
}
// there's no zombies left
// check if there's any living processes
if (dll_is_empty(__proc.list)) {
__proc_unlock();
return echild();
}
// get appropriate wait object
// register ourself as waiting
struct Proc *pr = 0;
@@ -165,7 +167,7 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
}
__proc_unlock();
if (wi == 1) {
// __sig_cancel() woke our semaphore
// __sig_wake() woke our semaphore
continue;
} else {
// neither posix or win32 define i/o error conditions for
+8 -6
View File
@@ -17,11 +17,11 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/atomic.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/syscall_support-nt.internal.h"
#include "libc/intrin/dll.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/maps.h"
#include "libc/intrin/nomultics.h"
#include "libc/intrin/weaken.h"
@@ -31,6 +31,7 @@
#include "libc/nt/accounting.h"
#include "libc/nt/console.h"
#include "libc/nt/enum/consolemodeflags.h"
#include "libc/nt/enum/creationdisposition.h"
#include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h"
#include "libc/nt/files.h"
@@ -294,7 +295,6 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
ARRAYLEN(wa->envp) - 1);
__imp_FreeEnvironmentStringsW(env16);
__envp = &wa->envp[0];
// handover control to cosmopolitan runtime
__stack_call(count, wa->argv, wa->envp, wa->auxv, cosmo,
(uintptr_t)(stackaddr + (stacksize - sizeof(struct WinArgs))));
@@ -302,6 +302,7 @@ static abi wontreturn void WinInit(const char16_t *cmdline) {
abi int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
const char *lpCmdLine, int64_t nCmdShow) {
static atomic_ulong fake_process_signals;
const char16_t *cmdline;
extern char os asm("__hostos");
os = _HOSTWINDOWS; // madness https://news.ycombinator.com/item?id=21019722
@@ -317,19 +318,20 @@ abi int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
__gransize = si.dwAllocationGranularity;
__umask = 077;
__pid = __imp_GetCurrentProcessId();
if (!(__sig.process = __sig_map_process(__pid, kNtOpenAlways)))
__sig.process = &fake_process_signals;
atomic_store_explicit(__sig.process, 0, memory_order_release);
cmdline = __imp_GetCommandLineW();
#if SYSDEBUG
// sloppy flag-only check for early initialization
if (StrStr(cmdline, u"--strace"))
++__strace;
#endif
if (_weaken(WinSockInit)) {
if (_weaken(WinSockInit))
_weaken(WinSockInit)();
}
DeduplicateStdioHandles();
if (_weaken(WinMainForked)) {
if (_weaken(WinMainForked))
_weaken(WinMainForked)();
}
WinInit(cmdline);
}
+16 -23
View File
@@ -39,7 +39,6 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
uint64_t ms;
uint32_t in_optlen;
struct linger_nt linger;
npassert(fd->kind == kFdSocket);
if (out_opt_optval && inout_optlen) {
in_optlen = *inout_optlen;
@@ -48,40 +47,34 @@ textwindows int sys_getsockopt_nt(struct Fd *fd, int level, int optname,
}
if (level == SOL_SOCKET && optname == SO_ERROR) {
if (in_optlen >= sizeof(int)) {
int err;
uint32_t len = sizeof(err);
if (__imp_getsockopt(fd->handle, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
return __winsockerr();
*(int *)out_opt_optval = __dos2errno(err);
*inout_optlen = sizeof(int);
} else {
if (in_optlen < sizeof(int))
return einval();
}
int err;
uint32_t len = sizeof(err);
if (__imp_getsockopt(fd->handle, SOL_SOCKET, SO_ERROR, &err, &len) == -1)
return __winsockerr();
*(int *)out_opt_optval = __dos2errno(err);
*inout_optlen = sizeof(int);
}
if (level == SOL_SOCKET &&
(optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
if (in_optlen >= sizeof(struct timeval)) {
if (optname == SO_RCVTIMEO) {
ms = fd->rcvtimeo;
} else {
ms = fd->sndtimeo;
}
((struct timeval *)out_opt_optval)->tv_sec = ms / 1000;
((struct timeval *)out_opt_optval)->tv_usec = ms % 1000 * 1000;
*inout_optlen = sizeof(struct timeval);
return 0;
} else {
if (in_optlen < sizeof(struct timeval))
return einval();
if (optname == SO_RCVTIMEO) {
ms = fd->rcvtimeo;
} else {
ms = fd->sndtimeo;
}
*(struct timeval *)out_opt_optval = timeval_frommillis(ms);
*inout_optlen = sizeof(struct timeval);
return 0;
}
// TODO(jart): Use WSAIoctl?
if (__imp_getsockopt(fd->handle, level, optname, out_opt_optval,
inout_optlen) == -1) {
inout_optlen) == -1)
return __winsockerr();
}
if (level == SOL_SOCKET) {
if (optname == SO_LINGER && in_optlen == sizeof(struct linger)) {
+12 -6
View File
@@ -29,15 +29,21 @@
*/
textwindows size_t __iovec2nt(struct NtIovec iovnt[hasatleast 16],
const struct iovec *iov, size_t iovlen) {
size_t i, limit;
for (limit = 0x7ffff000, i = 0; i < MIN(16, iovlen); ++i) {
iovnt[i].buf = iov[i].iov_base;
size_t i, j, limit = 0x7ffff000;
for (j = i = 0; i < iovlen; ++i) {
if (!iov[i].iov_len)
continue;
if (j == 16)
break;
iovnt[j].buf = iov[i].iov_base;
if (iov[i].iov_len < limit) {
limit -= (iovnt[i].len = iov[i].iov_len);
limit -= (iovnt[j].len = iov[i].iov_len);
++j;
} else {
iovnt[i].len = limit;
iovnt[j].len = limit;
++j;
break;
}
}
return i;
return j;
}
+24 -9
View File
@@ -17,15 +17,17 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/fds.h"
#include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/fio.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
#ifdef __x86_64__
#define _MSG_OOB 1
@@ -33,6 +35,8 @@
#define _MSG_WAITALL 8
#define _MSG_DONTWAIT 64
__msabi extern typeof(__sys_ioctlsocket_nt) *const __imp_ioctlsocket;
struct RecvArgs {
const struct iovec *iov;
size_t iovlen;
@@ -54,13 +58,24 @@ textwindows ssize_t sys_recv_nt(int fd, const struct iovec *iov, size_t iovlen,
return einval();
ssize_t rc;
struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block();
bool nonblock = !(flags & _MSG_WAITALL) &&
((f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT));
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(f->handle, flags, nonblock, f->rcvtimeo, m,
sys_recv_nt_start, &(struct RecvArgs){iov, iovlen});
__sig_unblock(m);
sigset_t waitmask = __sig_block();
// "Be aware that if the underlying transport provider does not
// support MSG_WAITALL, or if the socket is in a non-blocking mode,
// then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL
// is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then
// this call will fail with WSAEOPNOTSUPP."
// —Quoth MSDN § WSARecv
if (flags & _MSG_WAITALL)
__imp_ioctlsocket(f->handle, FIONBIO, (uint32_t[]){0});
rc = __winsock_block(f->handle, flags & ~_MSG_DONTWAIT,
(f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT),
f->rcvtimeo, waitmask, sys_recv_nt_start,
&(struct RecvArgs){iov, iovlen});
__sig_unblock(waitmask);
return rc;
}
+29 -4
View File
@@ -20,31 +20,55 @@
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/msg.h"
#include "libc/sysv/errfuns.h"
/**
* Receives data from network socket.
*
* Calling `recv(fd, p, n, 0)` is equivalent to `read(fd, p, n)`.
*
* Unlike files where the OS tries very hard to fulfill the entire
* requested `size` before returning, read operations on sockets aim to
* return as quickly as possible. For example, if 10 bytes are requested
* and a packet comes in with only 5 bytes, then recv() will most likely
* return those 5 bytes before waiting longer. The `MSG_WAITALL` flag
* may be passed when waiting longer is desired. In that case, short
* reads should only be possible when the connection status changes or
* the receive operation is interrupted by a signal.
*
* @param fd is the file descriptor returned by socket()
* @param buf is where received network data gets copied
* @param size is the byte capacity of buf
* @param flags can have `MSG_OOB`, `MSG_PEEK`, `MSG_DONTWAIT`, `MSG_WAITALL`
* @return number of bytes received, 0 on remote close, or -1 w/ errno
* @raise EINTR if signal handler was called instead
* @raise EINVAL if unknown bits were passed in `flags`
* @raise EINVAL if flag isn't supported by host operating system
* @raise EINVAL if `MSG_WAITALL` and `MSG_PEEK` were both passed
* @raise EBADF if `fd` is an invalid file descriptor
* @raise EAGAIN if `MSG_DONTWAIT` was passed and no data was available
* @raise EAGAIN if `O_NONBLOCK` is in play and no data was available
* @error EINTR, EHOSTUNREACH, ECONNRESET (UDP ICMP Port Unreachable),
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
* @cancelationpoint
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
* @restartable (unless SO_RCVTIMEO on Linux or Windows)
*/
ssize_t recv(int fd, void *buf, size_t size, int flags) {
ssize_t rc;
BEGIN_CANCELATION_POINT;
if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
if ((flags & (MSG_WAITALL | MSG_PEEK)) == (MSG_WAITALL | MSG_PEEK)) {
// this is possible on some OSes like Linux but it breaks FreeBSD
// and Windows will raise EOPNOTSUPP when it gets passed together
return einval();
} else if (fd < g_fds.n && g_fds.p[fd].kind == kFdZip) {
rc = enotsock();
} else if (!IsWindows()) {
rc = sys_recvfrom(fd, buf, size, flags, 0, 0);
@@ -65,7 +89,8 @@ ssize_t recv(int fd, void *buf, size_t size, int flags) {
}
END_CANCELATION_POINT;
DATATRACE("recv(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags);
DATATRACE("recv(%d, [%#.*hhs%s], %'zu, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size,
DescribeMsg(flags), rc);
return rc;
}
+5 -6
View File
@@ -59,14 +59,13 @@ textwindows ssize_t sys_recvfrom_nt(int fd, const struct iovec *iov,
return einval();
ssize_t rc;
struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block();
bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT);
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(f->handle, flags, nonblock, f->rcvtimeo, m,
sys_recvfrom_nt_start,
sigset_t waitmask = __sig_block();
rc = __winsock_block(f->handle, flags & ~_MSG_DONTWAIT,
(f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT),
f->rcvtimeo, waitmask, sys_recvfrom_nt_start,
&(struct RecvFromArgs){iov, iovlen, opt_out_srcaddr,
opt_inout_srcaddrsize});
__sig_unblock(m);
__sig_unblock(waitmask);
return rc;
}
+8 -3
View File
@@ -21,6 +21,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
@@ -49,7 +50,7 @@
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
* @cancelationpoint
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
* @restartable (unless SO_RCVTIMEO on Linux or Windows)
*/
ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
struct sockaddr *opt_out_srcaddr,
@@ -95,7 +96,11 @@ ssize_t recvfrom(int fd, void *buf, size_t size, int flags,
}
END_CANCELATION_POINT;
DATATRACE("recvfrom(%d, [%#.*hhs%s], %'zu, %#x) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc);
DATATRACE(
"recvfrom(%d, [%#.*hhs%s], %'zu, %s, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, DescribeMsg(flags),
DescribeSockaddr(opt_out_srcaddr,
opt_inout_srcaddrsize ? *opt_inout_srcaddrsize : 0),
rc);
return rc;
}
+24 -11
View File
@@ -17,20 +17,25 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/intrin/fds.h"
#include "libc/errno.h"
#include "libc/nt/errors.h"
#include "libc/nt/struct/iovec.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#include "libc/vga/vga.internal.h"
#ifdef __x86_64__
#define _MSG_OOB 1
#define _MSG_DONTROUTE 4
#define _MSG_DONTWAIT 64
#define _MSG_NOSIGNAL 0x10000000
struct SendArgs {
const struct iovec *iov;
@@ -49,16 +54,24 @@ textwindows static int sys_send_nt_start(int64_t handle,
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
uint32_t flags) {
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE))
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE | _MSG_NOSIGNAL))
return einval();
ssize_t rc;
struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block();
bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT);
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(f->handle, flags, nonblock, f->sndtimeo, m,
sys_send_nt_start, &(struct SendArgs){iov, iovlen});
__sig_unblock(m);
sigset_t waitmask = __sig_block();
rc = __winsock_block(f->handle, flags & ~(_MSG_DONTWAIT | _MSG_NOSIGNAL),
false, f->sndtimeo, waitmask, sys_send_nt_start,
&(struct SendArgs){iov, iovlen});
__sig_unblock(waitmask);
if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN
errno = kNtErrorBrokenPipe; // EPIPE
if (!(flags & _MSG_NOSIGNAL))
__sig_raise(SIGPIPE, SI_KERNEL);
}
return rc;
}
+16 -3
View File
@@ -21,6 +21,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/macros.h"
#include "libc/sock/internal.h"
@@ -30,6 +31,18 @@
/**
* Sends data to network socket.
*
* Calling `send(fd, p, n, 0)` is equivalent to `write(fd, p, n)`.
*
* On Windows, calling send() or write() on a socket in `O_NONBLOCK`
* mode will block. This is done for many reasons. First, most UNIX OSes
* have a similar behavior, due to how little code checks the return
* status of write(). Secondly, WIN32 has bugs that prevent us from
* canceling an overlapped WSASend() operation safely. Programs that
* want to avoid send() blocking should call poll() beforehand with the
* POLLOUT flag to test when the socket can safely be written without
* blocking. It's also possible to pass `MSG_DONTWAIT` via `flags` in
* which case send() will do this for you automatically.
*
* @param fd is the file descriptor returned by socket()
* @param buf is the data to send, which we'll copy if necessary
* @param size is the byte-length of buf
@@ -39,7 +52,7 @@
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
* @cancelationpoint
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
* @restartable (unless SO_SNDTIMEO on Linux or Windows)
*/
ssize_t send(int fd, const void *buf, size_t size, int flags) {
ssize_t rc;
@@ -66,7 +79,7 @@ ssize_t send(int fd, const void *buf, size_t size, int flags) {
}
END_CANCELATION_POINT;
DATATRACE("send(%d, %#.*hhs%s, %'zu, %#x) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags, rc);
DATATRACE("send(%d, %#.*hhs%s, %'zu, %s) → %'ld% lm", fd, MAX(0, MIN(40, rc)),
buf, rc > 40 ? "..." : "", size, DescribeMsg(flags), rc);
return rc;
}
+22 -8
View File
@@ -17,20 +17,26 @@
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/sigset.internal.h"
#include "libc/errno.h"
#include "libc/intrin/fds.h"
#include "libc/nt/errors.h"
#include "libc/nt/struct/iovec.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h"
#ifdef __x86_64__
#define _MSG_OOB 1
#define _MSG_DONTROUTE 4
#define _MSG_DONTWAIT 64
#define _MSG_NOSIGNAL 0x10000000
struct SendToArgs {
const struct iovec *iov;
@@ -52,17 +58,25 @@ static textwindows int sys_sendto_nt_start(int64_t handle,
textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov,
size_t iovlen, uint32_t flags,
void *opt_in_addr, uint32_t in_addrsize) {
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE))
if (flags & ~(_MSG_DONTWAIT | _MSG_OOB | _MSG_DONTROUTE | _MSG_NOSIGNAL))
return einval();
ssize_t rc;
struct Fd *f = g_fds.p + fd;
sigset_t m = __sig_block();
bool nonblock = (f->flags & O_NONBLOCK) || (flags & _MSG_DONTWAIT);
flags &= ~_MSG_DONTWAIT;
rc = __winsock_block(
f->handle, flags, nonblock, f->sndtimeo, m, sys_sendto_nt_start,
&(struct SendToArgs){iov, iovlen, opt_in_addr, in_addrsize});
__sig_unblock(m);
sigset_t waitmask = __sig_block();
rc = __winsock_block(f->handle, flags & ~(_MSG_DONTWAIT | _MSG_NOSIGNAL),
false, f->sndtimeo, waitmask, sys_sendto_nt_start,
&(struct SendToArgs){iov, iovlen, //
opt_in_addr, in_addrsize});
__sig_unblock(waitmask);
if (rc == -1 && errno == WSAESHUTDOWN) { // ESHUTDOWN
errno = kNtErrorBrokenPipe; // EPIPE
if (!(flags & _MSG_NOSIGNAL))
__sig_raise(SIGPIPE, SI_KERNEL);
}
return rc;
}
+5 -4
View File
@@ -22,6 +22,7 @@
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/iovec.internal.h"
#include "libc/dce.h"
#include "libc/intrin/describeflags.h"
#include "libc/intrin/strace.h"
#include "libc/macros.h"
#include "libc/sock/internal.h"
@@ -51,7 +52,7 @@
* EPIPE (if MSG_NOSIGNAL), EMSGSIZE, ENOTSOCK, EFAULT, etc.
* @cancelationpoint
* @asyncsignalsafe
* @restartable (unless SO_RCVTIMEO)
* @restartable (unless SO_SNDTIMEO on Linux or Windows)
*/
ssize_t sendto(int fd, const void *buf, size_t size, int flags,
const struct sockaddr *opt_addr, uint32_t addrsize) {
@@ -88,8 +89,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, int flags,
}
END_CANCELATION_POINT;
DATATRACE("sendto(%d, %#.*hhs%s, %'zu, %#x, %p, %u) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size, flags,
opt_addr, addrsize, rc);
DATATRACE("sendto(%d, %#.*hhs%s, %'zu, %s, %s) → %'ld% lm", fd,
MAX(0, MIN(40, rc)), buf, rc > 40 ? "..." : "", size,
DescribeMsg(flags), DescribeSockaddr(opt_addr, addrsize), rc);
return rc;
}
+6 -3
View File
@@ -36,14 +36,17 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
const void *optval, uint32_t optlen) {
// socket read/write timeouts
// timeout of zero means wait forever (default)
if (level == SOL_SOCKET &&
(optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)) {
if (!(optval && optlen == sizeof(struct timeval)))
if (!optval)
return einval();
if (optlen < sizeof(struct timeval))
return einval();
const struct timeval *tv = optval;
int64_t ms = timeval_tomillis(*tv);
if (ms > -1u)
ms = 0; // wait forever (default) yes zero actually means this
ms = -1u;
if (optname == SO_RCVTIMEO)
fd->rcvtimeo = ms;
if (optname == SO_SNDTIMEO)
@@ -51,7 +54,7 @@ textwindows int sys_setsockopt_nt(struct Fd *fd, int level, int optname,
return 0; // we want to handle this on our own
}
// how to make close() a blocking i/o call
// how to make close() a blocking i/o call lool
union {
uint32_t millis;
struct linger_nt linger;
+1 -1
View File
@@ -56,7 +56,7 @@ const char *_DescribeSockaddr(char buf[128], const struct sockaddr *sa,
p = stpcpy(p, ip);
*p++ = ']';
*p++ = ':';
p = FormatUint32(p, in6->sin6_port);
p = FormatUint32(p, ntohs(in6->sin6_port));
}
} else if (sa->sa_family == AF_UNIX &&
sasize >= sizeof(struct sockaddr_un)) {
+10
View File
@@ -30,10 +30,12 @@
#include "libc/nt/events.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/overlapped.h"
#include "libc/nt/struct/pollfd.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/errfuns.h"
#include "libc/thread/posixthread.internal.h"
@@ -70,6 +72,9 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock,
bool32 ok = !StartSocketOp(handle, &overlap, &flags, arg);
if (!ok && WSAGetLastError() == kNtErrorIoPending) {
if (nonblock) {
// send() and sendto() shall not pass O_NONBLOCK along to here
// because winsock has a bug that causes CancelIoEx() to cause
// WSAGetOverlappedResult() to report errors when it succeeded
CancelIoEx(handle, &overlap);
got_eagain = true;
} else {
@@ -174,6 +179,11 @@ __winsock_block(int64_t handle, uint32_t flags, bool nonblock,
// check if signal handler without SA_RESTART was called
if (handler_was_called & SIG_HANDLED_NO_RESTART)
return eintr();
// emulates linux behavior of having timeouts @norestart
if (handler_was_called & SIG_HANDLED_SA_RESTART)
if (srwtimeout)
return eintr();
}
// otherwise try the i/o operation again
+90 -185
View File
@@ -651,14 +651,14 @@ syscon so SO_DEBUG 1 1 1 1 1 1 1 1 # debugging is enabled; co
syscon so SO_TYPE 3 3 0x1008 0x1008 0x1008 0x1008 0x1008 0x1008 # bsd consensus
syscon so SO_ERROR 4 4 0x1007 0x1007 0x1007 0x1007 0x1007 0x1007 # takes int pointer and stores/clears the pending error code; bsd consensus
syscon so SO_ACCEPTCONN 30 30 2 2 2 2 2 2 # takes int pointer and stores boolean indicating if listen() was called on fd; bsd consensus
syscon so SO_REUSEPORT 15 15 0x0200 0x0200 0x0200 0x0200 0x0200 0 # bsd consensus; no windows support
syscon so SO_REUSEPORT 15 15 512 512 512 512 512 0 # bsd consensus; no windows support
syscon so SO_REUSEADDR 2 2 4 4 4 4 4 -5 # SO_EXCLUSIVEADDRUSE on Windows (see third_party/python/Lib/test/support/__init__.py)
syscon so SO_KEEPALIVE 9 9 8 8 8 8 8 8 # bsd consensus
syscon so SO_DONTROUTE 5 5 0x10 0x10 0x10 0x10 0x10 0x10 # bsd consensus
syscon so SO_BROADCAST 6 6 0x20 0x20 0x20 0x20 0x20 0x20 # socket is configured for broadcast messages; bsd consensus
syscon so SO_USELOOPBACK 0 0 0x40 0x40 0x40 0x40 0x40 0x40 # bsd consensus
syscon so SO_LINGER 13 13 0x1080 0x1080 0x80 0x80 0x80 0x80 # takes struct linger; causes close() return value to actually mean something; SO_LINGER_SEC on XNU; bsd consensus
syscon so SO_OOBINLINE 10 10 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 # bsd consensus
syscon so SO_DONTROUTE 5 5 16 16 16 16 16 16 # bsd consensus
syscon so SO_BROADCAST 6 6 32 32 32 32 32 32 # socket is configured for broadcast messages; bsd consensus
syscon so SO_USELOOPBACK 0 0 64 64 64 64 64 64 # bsd consensus
syscon so SO_LINGER 13 13 4224 4224 128 128 128 128 # takes struct linger; causes close() return value to actually mean something; SO_LINGER_SEC on XNU; bsd consensus
syscon so SO_OOBINLINE 10 10 256 256 256 256 256 256 # bsd consensus
syscon so SO_SNDBUF 7 7 0x1001 0x1001 0x1001 0x1001 0x1001 0x1001 # bsd consensus
syscon so SO_RCVBUF 8 8 0x1002 0x1002 0x1002 0x1002 0x1002 0x1002 # bsd consensus
syscon so SO_RCVTIMEO 20 20 0x1006 0x1006 0x1006 0x1006 0x100c 0x1006 # recv timeout; takes struct timeval (overrides SA_RESTART restoring EINTR behavior on recv/send/connect/accept/etc.; bsd consensus)
@@ -678,18 +678,18 @@ syscon tcp TCP_CORK 3 3 4 4 4 16 4 0 # nagle's algorithm stri
syscon tcp TCP_MAXSEG 2 2 2 2 2 2 2 0 # reduces tcp segment size; see also tcp offloading
syscon tcp TCP_FASTOPEN 23 23 0x105 0x105 0x0401 0 0 15 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true
syscon tcp TCP_FASTOPEN_CONNECT 30 30 0 0 0 0 0 0 # reduces roundtrips; for listener; Linux 3.7+ (c. 2012) / or is windows it 0x22? /proc/sys/net/ipv4/tcp_fastopen TODO(jart): MSG_FASTOPEN; XNU sources say 261 but not sure if that's true
syscon tcp TCP_KEEPIDLE 4 4 0 0 0x100 0 3 0 # start keepalives after this period
syscon tcp TCP_KEEPINTVL 5 5 0x101 0x101 0x200 0 5 0 # interval between keepalives
syscon tcp TCP_KEEPCNT 6 6 0x102 0x102 0x400 0 6 0 # number of keepalives before death
syscon tcp TCP_KEEPIDLE 4 4 0 0 0x100 0 3 3 # start keepalives after this period
syscon tcp TCP_KEEPINTVL 5 5 0x101 0x101 0x200 0 5 17 # interval between keepalives
syscon tcp TCP_KEEPCNT 6 6 0x102 0x102 0x400 0 6 16 # number of keepalives before death
syscon tcp TCP_INFO 11 11 0x200 0x200 32 9 9 0 # get connection info
syscon tcp TCP_NOTSENT_LOWAT 25 25 513 513 0 0 0 0 # limit unset byte queue
syscon tcp TCP_MD5SIG 14 14 0 0 16 4 16 0 # what is it (rfc2385)
syscon tcp TCP_CONGESTION 13 13 0 0 64 0 0 0 # set traffic control
syscon tcp TCP_SYNCNT 7 7 0 0 0 0 0 0 # how hard to syn packet the enemy
syscon tcp TCP_ULP 31 31 0 0 0 0 0 0 # setsockopt(sock, IPPROTO_TCP, TCP_ULP, "tls", 4)
syscon tcp TCP_COOKIE_TRANSACTIONS 15 15 0 0 0 0 0 0 # defense against the syn packets
syscon tcp TCP_LINGER2 8 8 0 0 0 0 0 0 # orphaned fin-wait-2 lifetime cf. net.ipv4.tcp_fin_timeout see cloudflare blog
syscon tcp TCP_NOTSENT_LOWAT 25 25 513 513 0 0 0 0 # limit unset byte queue
syscon tcp TCP_INFO 11 11 0 0 0x20 0 9 0 # get connection info
syscon tcp TCP_CC_INFO 26 26 0 0 0 0 0 0 # get congestion control info
syscon tcp TCP_CONGESTION 13 13 0 0 0x40 0 0 0 # set traffic control
syscon tcp TCP_MD5SIG 14 14 0 0 0x10 4 16 0 # what is it (rfc2385)
syscon tcp TCP_MD5SIG_MAXKEYLEN 80 80 0 0 0 0 0 0 # what is it
syscon tcp TCP_TIMESTAMP 24 24 0 0 0 0 0 0 # what is it
syscon tcp TCP_USER_TIMEOUT 18 18 0 0 0 0 0 0 # what is it
@@ -705,6 +705,79 @@ syscon tcp TCP_REPAIR_OPTIONS 22 22 0 0 0 0 0 0 # what is it
syscon tcp TCP_REPAIR_QUEUE 20 20 0 0 0 0 0 0 # what is it
syscon tcp TCP_THIN_LINEAR_TIMEOUTS 16 16 0 0 0 0 0 0 # what is it
# IPPROTO_IP (or SOL_IP) socket options
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon ip IP_TOS 1 1 3 3 3 3 3 3 # bsd consensus
syscon ip IP_TTL 2 2 4 4 4 4 4 4 # bsd consensus
syscon ip IP_MTU 14 14 0 0 0 0 0 73 # bsd consensus
syscon ip IP_HDRINCL 3 3 2 2 2 2 2 2 # bsd consensus
syscon ip IP_OPTIONS 4 4 1 1 1 1 1 1 # bsd consensus
syscon ip IP_RECVTTL 12 12 24 24 65 31 23 21
syscon ip IP_ADD_MEMBERSHIP 35 35 12 12 12 12 12 12 # bsd consensus
syscon ip IP_DROP_MEMBERSHIP 36 36 13 13 13 13 13 13 # bsd consensus
syscon ip IP_MULTICAST_IF 32 32 9 9 9 9 9 9 # bsd consensus
syscon ip IP_MULTICAST_LOOP 34 34 11 11 11 11 11 11 # bsd consensus
syscon ip IP_MULTICAST_TTL 33 33 10 10 10 10 10 10 # bsd consensus
syscon ip IP_PKTINFO 8 8 26 26 0 0 25 19
syscon ip IP_RECVTOS 13 13 0 0 68 0 0 40
# IPPROTO_IPV6 (or SOL_IPV6) socket options
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon ipv6 IPV6_V6ONLY 26 26 27 27 27 27 27 27 # bsd consensus
syscon ipv6 IPV6_CHECKSUM 7 7 26 26 26 26 26 26 # bsd consensus
syscon ipv6 IPV6_JOIN_GROUP 20 20 12 12 12 12 12 12 # bsd consensus
syscon ipv6 IPV6_LEAVE_GROUP 21 21 13 13 13 13 13 13 # bsd consensus
syscon ipv6 IPV6_MULTICAST_HOPS 18 18 10 10 10 10 10 10 # bsd consensus
syscon ipv6 IPV6_MULTICAST_IF 17 17 9 9 9 9 9 9 # bsd consensus
syscon ipv6 IPV6_MULTICAST_LOOP 19 19 11 11 11 11 11 11 # bsd consensus
syscon ipv6 IPV6_UNICAST_HOPS 16 16 4 4 4 4 4 4 # bsd consensus
syscon ipv6 IPV6_RECVTCLASS 66 66 35 35 57 57 57 40
syscon ipv6 IPV6_TCLASS 67 67 36 36 61 61 61 39
syscon ipv6 IPV6_DONTFRAG 62 62 0 0 62 62 62 14
syscon ipv6 IPV6_HOPLIMIT 52 52 0 0 47 47 47 21
syscon ipv6 IPV6_HOPOPTS 54 54 0 0 49 49 49 1
syscon ipv6 IPV6_PKTINFO 50 50 0 0 46 46 46 19
syscon ipv6 IPV6_RECVRTHDR 56 56 0 0 38 38 38 38
syscon ipv6 IPV6_RTHDR 57 57 0 0 51 51 51 32
# IPPROTO_ICMPV6 (or SOL_ICMPV6) socket options
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon icmp6 ICMP6_DST_UNREACH_NOROUTE 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_PARAMPROB_HEADER 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_TIME_EXCEED_TRANSIT 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_DST_UNREACH_ADMIN 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_PARAMPROB_NEXTHEADER 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_TIME_EXCEED_REASSEMBLY 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_DST_UNREACH 1 1 1 1 1 1 1 0 # unix consensus
syscon icmp6 ICMP6_FILTER 1 1 18 18 18 18 18 0 # bsd consensus
syscon icmp6 ICMP6_DST_UNREACH_BEYONDSCOPE 2 2 2 2 2 2 2 2 # consensus
syscon icmp6 ICMP6_PARAMPROB_OPTION 2 2 2 2 2 2 2 2 # consensus
syscon icmp6 ICMP6_PACKET_TOO_BIG 2 2 2 2 2 2 2 0 # unix consensus
syscon icmp6 ICMP6_DST_UNREACH_ADDR 3 3 3 3 3 3 3 3 # consensus
syscon icmp6 ICMP6_TIME_EXCEEDED 3 3 3 3 3 3 3 0 # unix consensus
syscon icmp6 ICMP6_DST_UNREACH_NOPORT 4 4 4 4 4 4 4 4 # consensus
syscon icmp6 ICMP6_PARAM_PROB 4 4 4 4 4 4 4 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_PREVDONE 8 8 8 8 8 8 8 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_SPECSITE 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10 0x10 0x40 0x40 0x40 0x40 0x40 0 # bsd consensus
syscon icmp6 ICMP6_RR_FLAGS_FORCEAPPLY 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20 0x20 0x80 0x80 0x80 0x80 0x80 0 # bsd consensus
syscon icmp6 ICMP6_RR_FLAGS_REQRESULT 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0 # unix consensus
syscon icmp6 ICMP6_INFOMSG_MASK 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 # consensus
syscon icmp6 ICMP6_ECHO_REQUEST 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_TEST 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_ECHO_REPLY 129 129 129 129 129 129 129 0 # unix consensus
syscon icmp6 ICMP6_ROUTER_RENUMBERING 138 138 138 138 138 138 138 0 # unix consensus
syscon icmp6 ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0 # unix consensus
syscon icmp6 ICMP6_RR_RESULT_FLAGS_OOB 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0 # unix consensus
syscon ipport IPPORT_USERRESERVED 5000 5000 5000 5000 5000 49151 5000 5000
# https://blog.cloudflare.com/know-your-scm_rights/
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
@@ -715,60 +788,6 @@ syscon scm SCM_TIMESTAMPING 37 37 0 0 0 0 0 0
syscon scm SCM_TIMESTAMPNS 35 35 0 0 0 0 0 0
syscon scm SCM_WIFI_STATUS 41 41 0 0 0 0 0 0
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon ip IP_TOS 1 1 3 3 3 3 3 3 # bsd consensus
syscon ip IP_TTL 2 2 4 4 4 4 4 4 # bsd consensus
syscon ip IP_HDRINCL 3 3 2 2 2 2 2 2 # bsd consensus
syscon ip IP_DEFAULT_MULTICAST_LOOP 1 1 1 1 1 1 1 1 # consensus
syscon ip IP_DEFAULT_MULTICAST_TTL 1 1 1 1 1 1 1 1 # consensus
syscon ip IP_PMTUDISC_DONT 0 0 0 0 0 0 0 0 # consensus
syscon ip IP_MAX_MEMBERSHIPS 20 20 0x0fff 0x0fff 0x0fff 0x0fff 0x0fff 20 # bsd consensus
syscon ip IP_OPTIONS 4 4 1 1 1 1 1 1 # bsd consensus
syscon ip IP_RECVTTL 12 12 24 24 65 31 23 21
syscon ip IP_ADD_MEMBERSHIP 35 35 12 12 12 12 12 12 # bsd consensus
syscon ip IP_DROP_MEMBERSHIP 36 36 13 13 13 13 13 13 # bsd consensus
syscon ip IP_MULTICAST_IF 0x20 0x20 9 9 9 9 9 9 # bsd consensus
syscon ip IP_MULTICAST_LOOP 34 34 11 11 11 11 11 11 # bsd consensus
syscon ip IP_MULTICAST_TTL 33 33 10 10 10 10 10 10 # bsd consensus
syscon ip IP_RECVOPTS 6 6 5 5 5 5 5 0 # bsd consensus
syscon ip IP_RECVRETOPTS 7 7 6 6 6 6 6 0 # bsd consensus
syscon ip IP_RECVDSTADDR 0 0 7 7 7 7 7 0 # bsd consensus
syscon ip IP_RETOPTS 7 7 8 8 8 8 8 0 # bsd consensus
syscon ip IP_ADD_SOURCE_MEMBERSHIP 39 39 70 70 70 0 0 15
syscon ip IP_BLOCK_SOURCE 38 38 72 72 72 0 0 17
syscon ip IP_DROP_SOURCE_MEMBERSHIP 40 40 71 71 71 0 0 16
syscon ip IP_UNBLOCK_SOURCE 37 37 73 73 73 0 0 18
syscon ip IP_IPSEC_POLICY 0x10 0x10 21 21 21 0 0 0
syscon ip IP_MINTTL 21 21 0 0 66 32 24 0 # minimum ttl for packet or drop
syscon ip IP_MSFILTER 41 41 74 74 74 0 0 0
syscon ip IP_PKTINFO 8 8 26 26 0 0 25 19
syscon ip IP_RECVTOS 13 13 0 0 68 0 0 40
syscon ip IP_MTU 14 14 0 0 0 0 0 73 # bsd consensus
syscon ip IP_MTU_DISCOVER 10 10 0 0 0 0 0 71 # bsd consensus
syscon ip IP_RECVERR 11 11 0 0 0 0 0 75 # bsd consensus
syscon ip IP_UNICAST_IF 50 50 0 0 0 0 0 31 # bsd consensus
syscon ip IP_ORIGDSTADDR 20 20 0 0 27 0 0 0
syscon ip IP_RECVORIGDSTADDR 20 20 0 0 27 0 0 0
syscon ip IP_BIND_ADDRESS_NO_PORT 24 24 0 0 0 0 0 0
syscon ip IP_CHECKSUM 23 23 0 0 0 0 0 0
syscon ip IP_FREEBIND 15 15 0 0 0 0 0 0
syscon ip IP_MULTICAST_ALL 49 49 0 0 0 0 0 0
syscon ip IP_NODEFRAG 22 22 0 0 0 0 0 0
syscon ip IP_PASSSEC 18 18 0 0 0 0 0 0
syscon ip IP_PKTOPTIONS 9 9 0 0 0 0 0 0
syscon ip IP_PMTUDISC 10 10 0 0 0 0 0 0
syscon ip IP_PMTUDISC_DO 2 2 0 0 0 0 0 0
syscon ip IP_PMTUDISC_INTERFACE 4 4 0 0 0 0 0 0
syscon ip IP_PMTUDISC_OMIT 5 5 0 0 0 0 0 0
syscon ip IP_PMTUDISC_PROBE 3 3 0 0 0 0 0 0
syscon ip IP_PMTUDISC_WANT 1 1 0 0 0 0 0 0
syscon ip IP_ROUTER_ALERT 5 5 0 0 0 0 0 0
syscon ip IP_TRANSPARENT 19 19 0 0 0 0 0 0
syscon ip IP_XFRM_POLICY 17 17 0 0 0 0 0 0
syscon ip INET_ADDRSTRLEN 0x10 0x10 0x10 0x10 0x10 0x10 0x10 22 # unix consensus
syscon ipport IPPORT_USERRESERVED 5000 5000 5000 5000 5000 49151 5000 5000
# ptrace() codes
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
@@ -1119,32 +1138,12 @@ syscon reboot RB_NOSYNC 0x20000000 0x20000000 4 4 4 4 4 0x2000000
syscon msg MSG_OOB 1 1 1 1 1 1 1 1 # consensus
syscon msg MSG_PEEK 2 2 2 2 2 2 2 2 # consensus
syscon msg MSG_DONTROUTE 4 4 4 4 4 4 4 4 # consensus
syscon msg MSG_FASTOPEN 0x20000000 0x20000000 0 0 0 0 0 0 # TODO
syscon msg MSG_WAITALL 0x0100 0x0100 0x40 0x40 0x40 0x40 0x40 8 # bsd consensus
syscon msg MSG_MORE 0x8000 0x8000 0 0 0 0 0 0 # send/sendto: manual TCP_CORK hbasically
syscon msg MSG_NOSIGNAL 0x4000 0x4000 0x80000 0x80000 0x020000 0x0400 0x0400 0 # send/sendto: don't SIGPIPE on EOF
syscon msg MSG_DONTWAIT 0x40 0x40 0x80 0x80 0x80 0x80 0x80 0x40 # send/sendto: manual non-blocking
syscon msg MSG_WAITALL 0x0100 0x0100 0x40 0x40 0x40 0x40 0x40 8 # bsd consensus
syscon msg MSG_NOSIGNAL 0x4000 0x4000 0x80000 0x80000 0x020000 0x0400 0x0400 0x10000000 # send/sendto: don't raise sigpipe on local shutdown
syscon msg MSG_TRUNC 0x20 0x20 0x10 0x10 0x10 0x10 0x10 0x0100 # bsd consensus
syscon msg MSG_CTRUNC 8 8 0x20 0x20 0x20 0x20 0x20 0x0200 # bsd consensus
syscon msg MSG_ERRQUEUE 0x2000 0x2000 0 0 0 0 0 0x1000 # bsd consensus
syscon msg MSG_NOERROR 0x1000 0x1000 0x1000 0x1000 0x1000 0x1000 0x1000 0 # unix consensus
syscon msg MSG_EOR 0x80 0x80 8 8 8 8 8 0 # bsd consensus
syscon msg MSG_CMSG_CLOEXEC 0x40000000 0x40000000 0 0 0x040000 0x0800 0x0800 0
syscon msg MSG_WAITFORONE 0x010000 0x010000 0 0 0x080000 0 0x2000 0
syscon msg MSG_BATCH 0x040000 0x040000 0 0 0 0 0 0
syscon msg MSG_CONFIRM 0x0800 0x0800 0 0 0 0 0 0
syscon msg MSG_EXCEPT 0x2000 0x2000 0 0 0 0 0 0
syscon msg MSG_FIN 0x0200 0x0200 0x0100 0x0100 0x0100 0 0 0
syscon msg MSG_EOF 0x0200 0x0200 0x0100 0x0100 0x0100 0 0 0
syscon msg MSG_INFO 12 12 0 0 0 0 0 0
syscon msg MSG_PARITY_ERROR 9 9 0 0 0 0 0 0
syscon msg MSG_PROXY 0x10 0x10 0 0 0 0 0 0
syscon msg MSG_RST 0x1000 0x1000 0 0 0 0 0 0
syscon msg MSG_STAT 11 11 0 0 0 0 0 0
syscon msg MSG_SYN 0x0400 0x0400 0 0 0 0 0 0
syscon msg MSG_BCAST 0 0 0 0 0 0x100 0x100 0
syscon msg MSG_MCAST 0 0 0 0 0 0x200 0x200 0
syscon msg MSG_NOTIFICATION 0x8000 0x8000 0 0 0x2000 0 0x4000 0
syscon msg MSG_FASTOPEN 0x20000000 0x20000000 -1 -1 -1 -1 -1 -1 #
# getpriority() / setpriority() magnums (a.k.a. nice)
#
@@ -1944,107 +1943,13 @@ syscon junkerr EKEYREJECTED 129 129 -1 -1 -1 -1 -1 -1
syscon junkerr ERFKILL 132 132 -1 -1 -1 -1 -1 -1
syscon junkerr EHWPOISON 133 133 -1 -1 -1 -1 -1 -1
# arpanet fork combating human-induced exhaustion of our ipv4 address space
#
# group name GNU/Systemd GNU/Systemd (Aarch64) XNU's Not UNIX! MacOS (Arm64) FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon ipv6 IPV6_PMTUDISC_DONT 0 0 0 0 0 0 0 0 # consensus
syscon ipv6 IPV6_RTHDR_LOOSE 0 0 0 0 0 0 0 0 # consensus
syscon ipv6 IPV6_RTHDR_TYPE_0 0 0 0 0 0 0 0 0 # consensus
syscon ipv6 IPV6_CHECKSUM 7 7 26 26 26 26 26 26 # bsd consensus
syscon ipv6 IPV6_JOIN_GROUP 20 20 12 12 12 12 12 12 # bsd consensus
syscon ipv6 IPV6_LEAVE_GROUP 21 21 13 13 13 13 13 13 # bsd consensus
syscon ipv6 IPV6_MULTICAST_HOPS 18 18 10 10 10 10 10 10 # bsd consensus
syscon ipv6 IPV6_MULTICAST_IF 17 17 9 9 9 9 9 9 # bsd consensus
syscon ipv6 IPV6_MULTICAST_LOOP 19 19 11 11 11 11 11 11 # bsd consensus
syscon ipv6 IPV6_UNICAST_HOPS 0x10 0x10 4 4 4 4 4 4 # bsd consensus
syscon ipv6 IPV6_V6ONLY 26 26 27 27 27 27 27 27 # bsd consensus
syscon ipv6 IPV6_RECVTCLASS 66 66 35 35 57 57 57 40
syscon ipv6 IPV6_TCLASS 67 67 36 36 61 61 61 39
syscon ipv6 IPV6_DONTFRAG 62 62 0 0 62 62 62 14
syscon ipv6 IPV6_HOPLIMIT 52 52 0 0 47 47 47 21
syscon ipv6 IPV6_HOPOPTS 54 54 0 0 49 49 49 1
syscon ipv6 IPV6_PKTINFO 50 50 0 0 46 46 46 19
syscon ipv6 IPV6_RECVRTHDR 56 56 0 0 38 38 38 38
syscon ipv6 IPV6_RTHDR 57 57 0 0 51 51 51 0x20
syscon ipv6 IPV6_DSTOPTS 59 59 0 0 50 50 50 0
syscon ipv6 IPV6_IPSEC_POLICY 34 34 28 28 28 0 0 0
syscon ipv6 IPV6_NEXTHOP 9 9 0 0 48 48 48 0
syscon ipv6 IPV6_PATHMTU 61 61 0 0 44 44 44 0
syscon ipv6 IPV6_RECVDSTOPTS 58 58 0 0 40 40 40 0
syscon ipv6 IPV6_RECVHOPLIMIT 51 51 0 0 37 37 37 0
syscon ipv6 IPV6_RECVHOPOPTS 53 53 0 0 39 39 39 0
syscon ipv6 IPV6_RECVPATHMTU 60 60 0 0 43 43 43 0
syscon ipv6 IPV6_RECVPKTINFO 49 49 0 0 36 36 36 0
syscon ipv6 IPV6_RTHDRDSTOPTS 55 55 0 0 35 35 35 0
syscon ipv6 IPV6_RTHDR_STRICT 1 1 1 1 1 0 0 0
syscon ipv6 IPV6_ADD_MEMBERSHIP 20 20 0 0 0 0 0 12 # bsd consensus
syscon ipv6 IPV6_DROP_MEMBERSHIP 21 21 0 0 0 0 0 13 # bsd consensus
syscon ipv6 IPV6_HDRINCL 36 36 0 0 0 0 0 2 # bsd consensus
syscon ipv6 IPV6_MTU 24 24 0 0 0 0 0 72 # bsd consensus
syscon ipv6 IPV6_MTU_DISCOVER 23 23 0 0 0 0 0 71 # bsd consensus
syscon ipv6 IPV6_RECVERR 25 25 0 0 0 0 0 75 # bsd consensus
syscon ipv6 IPV6_2292DSTOPTS 4 4 23 23 0 0 0 0
syscon ipv6 IPV6_2292HOPLIMIT 8 8 20 20 0 0 0 0
syscon ipv6 IPV6_2292HOPOPTS 3 3 22 22 0 0 0 0
syscon ipv6 IPV6_2292PKTINFO 2 2 19 19 0 0 0 0
syscon ipv6 IPV6_2292PKTOPTIONS 6 6 25 25 0 0 0 0
syscon ipv6 IPV6_2292RTHDR 5 5 24 24 0 0 0 0
syscon ipv6 IPV6_AUTOFLOWLABEL 0 0 0 0 59 59 59 0
syscon ipv6 IPV6_ADDRFORM 1 1 0 0 0 0 0 0
syscon ipv6 IPV6_AUTHHDR 10 10 0 0 0 0 0 0
syscon ipv6 IPV6_JOIN_ANYCAST 27 27 0 0 0 0 0 0
syscon ipv6 IPV6_LEAVE_ANYCAST 28 28 0 0 0 0 0 0
syscon ipv6 IPV6_PMTUDISC_DO 2 2 0 0 0 0 0 0
syscon ipv6 IPV6_PMTUDISC_INTERFACE 4 4 0 0 0 0 0 0
syscon ipv6 IPV6_PMTUDISC_OMIT 5 5 0 0 0 0 0 0
syscon ipv6 IPV6_PMTUDISC_PROBE 3 3 0 0 0 0 0 0
syscon ipv6 IPV6_PMTUDISC_WANT 1 1 0 0 0 0 0 0
syscon ipv6 IPV6_ROUTER_ALERT 22 22 0 0 0 0 0 0
syscon ipv6 IPV6_RXDSTOPTS 59 59 0 0 0 0 0 0
syscon ipv6 IPV6_RXHOPOPTS 54 54 0 0 0 0 0 0
syscon ipv6 IPV6_XFRM_POLICY 35 35 0 0 0 0 0 0
syscon ipv6 IPV6_MINHOPCOUNT 0 0 0 0 0 65 65 0
syscon ipv6 IPV6_ORIGDSTADDR 0 0 0 0 72 0 0 0
syscon ipv6 IPV6_RECVORIGDSTADDR 0 0 0 0 72 0 0 0
syscon ipv6 INET6_ADDRSTRLEN 46 46 46 46 46 46 46 65 # unix consensus
syscon icmp6 ICMP6_DST_UNREACH_NOROUTE 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_PARAMPROB_HEADER 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_TIME_EXCEED_TRANSIT 0 0 0 0 0 0 0 0 # consensus
syscon icmp6 ICMP6_DST_UNREACH_ADMIN 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_PARAMPROB_NEXTHEADER 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_TIME_EXCEED_REASSEMBLY 1 1 1 1 1 1 1 1 # consensus
syscon icmp6 ICMP6_DST_UNREACH 1 1 1 1 1 1 1 0 # unix consensus
syscon icmp6 ICMP6_FILTER 1 1 18 18 18 18 18 0 # bsd consensus
syscon icmp6 ICMP6_DST_UNREACH_BEYONDSCOPE 2 2 2 2 2 2 2 2 # consensus
syscon icmp6 ICMP6_PARAMPROB_OPTION 2 2 2 2 2 2 2 2 # consensus
syscon icmp6 ICMP6_PACKET_TOO_BIG 2 2 2 2 2 2 2 0 # unix consensus
syscon icmp6 ICMP6_DST_UNREACH_ADDR 3 3 3 3 3 3 3 3 # consensus
syscon icmp6 ICMP6_TIME_EXCEEDED 3 3 3 3 3 3 3 0 # unix consensus
syscon icmp6 ICMP6_DST_UNREACH_NOPORT 4 4 4 4 4 4 4 4 # consensus
syscon icmp6 ICMP6_PARAM_PROB 4 4 4 4 4 4 4 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_PREVDONE 8 8 8 8 8 8 8 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_SPECSITE 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x10 0x10 0x40 0x40 0x40 0x40 0x40 0 # bsd consensus
syscon icmp6 ICMP6_RR_FLAGS_FORCEAPPLY 0x20 0x20 0x20 0x20 0x20 0x20 0x20 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x20 0x20 0x80 0x80 0x80 0x80 0x80 0 # bsd consensus
syscon icmp6 ICMP6_RR_FLAGS_REQRESULT 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_FLAGS_DECRPLTIME 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0 # unix consensus
syscon icmp6 ICMP6_INFOMSG_MASK 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 # consensus
syscon icmp6 ICMP6_ECHO_REQUEST 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_RR_FLAGS_TEST 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_RR_PCOUSE_FLAGS_DECRVLTIME 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0 # unix consensus
syscon icmp6 ICMP6_ECHO_REPLY 129 129 129 129 129 129 129 0 # unix consensus
syscon icmp6 ICMP6_ROUTER_RENUMBERING 138 138 138 138 138 138 138 0 # unix consensus
syscon icmp6 ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0x0100 0 # unix consensus
syscon icmp6 ICMP6_RR_RESULT_FLAGS_OOB 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0x0200 0 # unix consensus
syscon misc FIFOTYPE 54 54 54 54 54 54 54 0 # unix consensus
syscon misc GRPQUOTA 1 1 1 1 1 1 1 0 # unix consensus
syscon misc IF_NAMESIZE 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0 # unix consensus
syscon misc INTERMEDIATE_C_GOOD 10 10 0 0 0 0 0 0
syscon misc INTERMEDIATE_GOOD 8 8 0 0 0 0 0 0
syscon misc IOV_MAX 0x0400 0x0400 0x0400 0x0400 0x0400 0x0400 0x0400 16 # unix consensus & MSG_MAXIOVLEN
syscon misc IOV_MAX 1024 1024 1024 1024 1024 1024 1024 16 # unix consensus & MSG_MAXIOVLEN
syscon misc LINE_MAX 0x0800 0x0800 0x0800 0x0800 0x0800 0x0800 0x0800 0 # unix consensus
syscon misc LINKED_CMD_COMPLETE 10 10 0 0 0 0 0 0
syscon misc LINKED_FLG_CMD_COMPLETE 11 11 0 0 0 0 0 0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,INET6_ADDRSTRLEN,46,46,46,46,46,46,46,65
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ip,INET_ADDRSTRLEN,0x10,0x10,0x10,0x10,0x10,0x10,0x10,22
+1 -1
View File
@@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon misc,IOV_MAX,0x0400,0x0400,0x0400,0x0400,0x0400,0x0400,0x0400,16
.syscon misc,IOV_MAX,1024,1024,1024,1024,1024,1024,1024,16
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292DSTOPTS,4,4,23,23,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292HOPLIMIT,8,8,20,20,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292HOPOPTS,3,3,22,22,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292PKTINFO,2,2,19,19,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292PKTOPTIONS,6,6,25,25,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_2292RTHDR,5,5,24,24,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_ADDRFORM,1,1,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_ADD_MEMBERSHIP,20,20,0,0,0,0,0,12
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_AUTHHDR,10,10,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_AUTOFLOWLABEL,0,0,0,0,59,59,59,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_DROP_MEMBERSHIP,21,21,0,0,0,0,0,13
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_DSTOPTS,59,59,0,0,50,50,50,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_HDRINCL,36,36,0,0,0,0,0,2
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_IPSEC_POLICY,34,34,28,28,28,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_JOIN_ANYCAST,27,27,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_LEAVE_ANYCAST,28,28,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_MINHOPCOUNT,0,0,0,0,0,65,65,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_MTU,24,24,0,0,0,0,0,72
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_MTU_DISCOVER,23,23,0,0,0,0,0,71
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_NEXTHOP,9,9,0,0,48,48,48,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_ORIGDSTADDR,0,0,0,0,72,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PATHMTU,61,61,0,0,44,44,44,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_DO,2,2,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_DONT,0,0,0,0,0,0,0,0
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_INTERFACE,4,4,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_OMIT,5,5,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_PROBE,3,3,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_PMTUDISC_WANT,1,1,0,0,0,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVDSTOPTS,58,58,0,0,40,40,40,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVERR,25,25,0,0,0,0,0,75
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVHOPLIMIT,51,51,0,0,37,37,37,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVHOPOPTS,53,53,0,0,39,39,39,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVORIGDSTADDR,0,0,0,0,72,0,0,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVPATHMTU,60,60,0,0,43,43,43,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RECVPKTINFO,49,49,0,0,36,36,36,0
-2
View File
@@ -1,2 +0,0 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_ROUTER_ALERT,22,22,0,0,0,0,0,0
+1 -1
View File
@@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon ipv6,IPV6_RTHDR,57,57,0,0,51,51,51,0x20
.syscon ipv6,IPV6_RTHDR,57,57,0,0,51,51,51,32
Loaded 100 of 213 files, more files were not shown because too many files have changed in this diff. Show more