mirror of
https://github.com/jart/cosmopolitan.git
synced 2026-11-12 13:04:16 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4a7dd31567 | ||
|
|
d730fc668c | ||
|
|
e975245102 | ||
|
|
126a44dc49 | ||
|
|
476926790a | ||
|
|
dd8c4dbd7d | ||
|
|
0e59afb403 | ||
|
|
f68fc1f815 | ||
|
|
6107eb38f9 | ||
|
|
d50f4c02f6 | ||
|
|
0d74673213 | ||
|
|
8527462b95 | ||
|
|
8313dca982 | ||
|
|
87a6669900 | ||
|
|
ce2fbf9325 | ||
|
|
1bfb348403 | ||
|
|
aaed879ec7 | ||
|
|
8201ef2b3d | ||
|
|
b1c9801897 | ||
|
|
f7754ab608 | ||
|
|
96abe91c29 | ||
|
|
bb7942e557 | ||
|
|
b14dddcc18 | ||
|
|
65e425fbca | ||
|
|
774c67fcd3 | ||
|
|
3c58ecd00c | ||
|
|
5aa970bc4e |
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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__ */
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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_ */
|
||||
@@ -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[];
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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]);
|
||||
|
||||
@@ -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);
|
||||
@@ -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() */
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,INET6_ADDRSTRLEN,46,46,46,46,46,46,46,65
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ip,INET_ADDRSTRLEN,0x10,0x10,0x10,0x10,0x10,0x10,0x10,22
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292DSTOPTS,4,4,23,23,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292HOPLIMIT,8,8,20,20,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292HOPOPTS,3,3,22,22,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292PKTINFO,2,2,19,19,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292PKTOPTIONS,6,6,25,25,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_2292RTHDR,5,5,24,24,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_ADDRFORM,1,1,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_ADD_MEMBERSHIP,20,20,0,0,0,0,0,12
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_AUTHHDR,10,10,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_AUTOFLOWLABEL,0,0,0,0,59,59,59,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_DROP_MEMBERSHIP,21,21,0,0,0,0,0,13
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_DSTOPTS,59,59,0,0,50,50,50,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_HDRINCL,36,36,0,0,0,0,0,2
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_IPSEC_POLICY,34,34,28,28,28,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_JOIN_ANYCAST,27,27,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_LEAVE_ANYCAST,28,28,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_MINHOPCOUNT,0,0,0,0,0,65,65,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_MTU,24,24,0,0,0,0,0,72
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_MTU_DISCOVER,23,23,0,0,0,0,0,71
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_NEXTHOP,9,9,0,0,48,48,48,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_ORIGDSTADDR,0,0,0,0,72,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_PATHMTU,61,61,0,0,44,44,44,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_PMTUDISC_DO,2,2,0,0,0,0,0,0
|
||||
@@ -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
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_PMTUDISC_OMIT,5,5,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_PMTUDISC_PROBE,3,3,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_PMTUDISC_WANT,1,1,0,0,0,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVDSTOPTS,58,58,0,0,40,40,40,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVERR,25,25,0,0,0,0,0,75
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVHOPLIMIT,51,51,0,0,37,37,37,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVHOPOPTS,53,53,0,0,39,39,39,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVORIGDSTADDR,0,0,0,0,72,0,0,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVPATHMTU,60,60,0,0,43,43,43,0
|
||||
@@ -1,2 +0,0 @@
|
||||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon ipv6,IPV6_RECVPKTINFO,49,49,0,0,36,36,36,0
|
||||
@@ -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,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
Reference in new issue
Block a user