Make improvements

- Add GetCpuCount() API to redbean
- Add unix.gmtime() API to redbean
- Add unix.readlink() API to redbean
- Add unix.localtime() API to redbean
- Perfect the new redbean UNIX module APIs
- Integrate with Linux clock_gettime() vDSO
- Run Lua garbage collector when malloc() fails
- Fix another regression quirk with linenoise repl
- Fix GetProgramExecutableName() for systemwide installs
- Fix a build flake with test/libc/mem/test.mk SRCS list
This commit is contained in:
Justine Tunney 2022-04-25 21:16:05 -07:00
parent 860ea18a87
commit d57b81aac7
51 changed files with 3096 additions and 1395 deletions

View file

@ -65,6 +65,7 @@ $(LIBC_CALLS_A).pkg: \
$(LIBC_CALLS_A_OBJS) \ $(LIBC_CALLS_A_OBJS) \
$(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg) $(foreach x,$(LIBC_CALLS_A_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/libc/calls/vdsofunc.greg.o \
o/$(MODE)/libc/calls/directmap.o \ o/$(MODE)/libc/calls/directmap.o \
o/$(MODE)/libc/calls/directmap-nt.o \ o/$(MODE)/libc/calls/directmap-nt.o \
o/$(MODE)/libc/calls/raise.o: \ o/$(MODE)/libc/calls/raise.o: \

View file

@ -26,6 +26,8 @@
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime;
/** /**
* Returns nanosecond time. * Returns nanosecond time.
* *
@ -52,7 +54,7 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
rc = einval(); rc = einval();
} else if (!IsWindows()) { } else if (!IsWindows()) {
e = errno; e = errno;
if ((rc = sys_clock_gettime(clockid, ts))) { if ((rc = __clock_gettime(clockid, ts))) {
errno = e; errno = e;
ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL);
assert(ad.ax != -1); assert(ad.ax != -1);
@ -72,3 +74,23 @@ noinstrument int clock_gettime(int clockid, struct timespec *ts) {
} }
return rc; return rc;
} }
/**
* Returns fast system clock_gettime() if it exists.
*/
void *__get_clock_gettime(void) {
void *vdso;
static bool once;
static void *result;
if (!once) {
if ((vdso = __vdsofunc("__vdso_clock_gettime"))) {
__clock_gettime = result = vdso;
}
once = true;
}
return result;
}
const void *const __clock_gettime_ctor[] initarray = {
__get_clock_gettime,
};

View file

@ -33,7 +33,7 @@
* file is a relative path, then file is opened relative to dirfd * file is a relative path, then file is opened relative to dirfd
* @param path is a filename or directory * @param path is a filename or directory
* @param mode can be R_OK, W_OK, X_OK, F_OK * @param mode can be R_OK, W_OK, X_OK, F_OK
* @param flags should be 0 * @param flags can have AT_EACCESS, AT_SYMLINK_NOFOLLOW
* @return 0 if ok, or -1 and sets errno * @return 0 if ok, or -1 and sets errno
* @asyncsignalsafe * @asyncsignalsafe
*/ */

View file

@ -106,7 +106,7 @@ textwindows int sys_fstat_nt(int64_t handle, struct stat *st) {
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow; st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
st->st_blksize = PAGESIZE; st->st_blksize = PAGESIZE;
st->st_dev = wst.dwVolumeSerialNumber; st->st_dev = wst.dwVolumeSerialNumber;
st->st_rdev = wst.dwVolumeSerialNumber; st->st_rdev = 0;
st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow; st->st_ino = (uint64_t)wst.nFileIndexHigh << 32 | wst.nFileIndexLow;
st->st_nlink = wst.nNumberOfLinks; st->st_nlink = wst.nNumberOfLinks;
if (S_ISLNK(st->st_mode)) { if (S_ISLNK(st->st_mode)) {

View file

@ -0,0 +1,121 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 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/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/macros.internal.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/ok.h"
#define SIZE 1024
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
char program_executable_name[PATH_MAX + 1];
static inline void GetProgramExecutableNameImpl(char *p, char *e) {
char *q;
ssize_t rc;
size_t i, n;
union {
int cmd[4];
char16_t path16[PATH_MAX + 1];
} u;
if (IsWindows()) {
n = GetModuleFileName(0, u.path16, ARRAYLEN(u.path16));
for (i = 0; i < n; ++i) {
if (u.path16[i] == '\\') {
u.path16[i] = '/';
}
}
if (isalpha(u.path16[0]) && u.path16[1] == ':' && u.path16[2] == '/') {
p[0] = '/';
p[1] = '/';
p[2] = '?';
p[3] = '/';
p += 4;
}
tprecode16to8(p, e - p, u.path16);
return;
}
if (__argc && (q = __argv[0]) && !sys_faccessat(AT_FDCWD, q, F_OK, 0)) {
if (*q != '/') {
if (q[0] == '.' && q[1] == '/') {
q += 2;
}
if (getcwd(p, e - p)) {
while (*p) ++p;
*p++ = '/';
}
}
for (i = 0; *q && p + 1 < e; ++p, ++q) {
*p = *q;
}
*p = 0;
return;
}
if ((rc = sys_readlinkat(AT_FDCWD, "/proc/self/exe", p, e - p - 1)) > 0 ||
(rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, e - p - 1)) > 0) {
p[rc] = 0;
return;
}
if (IsFreebsd() || IsNetbsd()) {
u.cmd[0] = CTL_KERN;
u.cmd[1] = KERN_PROC;
if (IsFreebsd()) {
u.cmd[2] = KERN_PROC_PATHNAME_FREEBSD;
} else {
u.cmd[2] = KERN_PROC_PATHNAME_NETBSD;
}
u.cmd[3] = -1; // current process
n = e - p;
if (sysctl(u.cmd, ARRAYLEN(u.cmd), p, &n, 0, 0) != -1) {
return;
}
}
}
/**
* Returns absolute path of executable.
*/
char *GetProgramExecutableName(void) {
int e;
static bool once;
if (!once) {
e = errno;
GetProgramExecutableNameImpl(
program_executable_name,
program_executable_name + sizeof(program_executable_name));
errno = e;
}
return program_executable_name;
}
const void *const GetProgramExecutableNameCtor[] initarray = {
GetProgramExecutableName,
};

View file

@ -25,6 +25,8 @@
#include "libc/time/struct/timezone.h" #include "libc/time/struct/timezone.h"
#include "libc/time/time.h" #include "libc/time/time.h"
static typeof(sys_gettimeofday) *__gettimeofday = sys_gettimeofday;
/** /**
* Returns system wall time in microseconds. * Returns system wall time in microseconds.
* *
@ -40,7 +42,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
return efault(); return efault();
} }
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {
ad = sys_gettimeofday(tv, tz, NULL); ad = __gettimeofday(tv, tz, NULL);
assert(ad.ax != -1); assert(ad.ax != -1);
if (SupportsXnu() && ad.ax && tv) { if (SupportsXnu() && ad.ax && tv) {
tv->tv_sec = ad.ax; tv->tv_sec = ad.ax;
@ -53,3 +55,14 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) {
return sys_gettimeofday_nt(tv, tz); return sys_gettimeofday_nt(tv, tz);
} }
} }
static textstartup void __gettimeofday_init(void) {
void *vdso;
if ((vdso = __vdsofunc("__vdso_gettimeofday"))) {
__gettimeofday = vdso;
}
}
const void *const __gettimeofday_ctor[] initarray = {
__gettimeofday_init,
};

View file

@ -245,6 +245,8 @@ void sys_exit(int) hidden;
*/ */
void __onfork(void) hidden; void __onfork(void) hidden;
void *__vdsofunc(const char *) hidden;
void *__get_clock_gettime(void) hidden;
i32 __fixupnewfd(i32, i32) hidden; i32 __fixupnewfd(i32, i32) hidden;
void __restore_rt() hidden; void __restore_rt() hidden;
int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden; int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;

View file

@ -31,9 +31,9 @@
#include "libc/time/time.h" #include "libc/time/time.h"
static struct Now { static struct Now {
bool once;
uint64_t k0; uint64_t k0;
long double r0, cpn; long double r0, cpn;
typeof(sys_clock_gettime) *clock_gettime;
} g_now; } g_now;
static long double GetTimeSample(void) { static long double GetTimeSample(void) {
@ -73,22 +73,39 @@ void RefreshTime(void) {
now.cpn = MeasureNanosPerCycle(); now.cpn = MeasureNanosPerCycle();
now.r0 = dtime(CLOCK_REALTIME); now.r0 = dtime(CLOCK_REALTIME);
now.k0 = rdtsc(); now.k0 = rdtsc();
now.once = true;
memcpy(&g_now, &now, sizeof(now)); memcpy(&g_now, &now, sizeof(now));
} }
long double ConvertTicksToNanos(uint64_t ticks) { static long double nowl_sys(void) {
if (!g_now.once) RefreshTime();
return ticks * g_now.cpn; /* pico scale */
}
long double nowl_sys(void) {
return dtime(CLOCK_REALTIME); return dtime(CLOCK_REALTIME);
} }
long double nowl_art(void) { static long double nowl_art(void) {
uint64_t ticks; uint64_t ticks = rdtsc() - g_now.k0;
if (!g_now.once) RefreshTime();
ticks = unsignedsubtract(rdtsc(), g_now.k0);
return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn)); return g_now.r0 + (1 / 1e9L * (ticks * g_now.cpn));
} }
static long double nowl_vdso(void) {
long double secs;
struct timespec tv;
g_now.clock_gettime(CLOCK_REALTIME, &tv);
secs = tv.tv_nsec;
secs *= 1 / 1e9L;
secs += tv.tv_sec;
return secs;
}
long double nowl_setup(void) {
uint64_t ticks;
if ((g_now.clock_gettime = __get_clock_gettime())) {
nowl = nowl_vdso;
} else if (X86_HAVE(INVTSC)) {
RefreshTime();
nowl = nowl_art;
} else {
nowl = nowl_sys;
}
return nowl();
}
long double (*nowl)(void) = nowl_setup;

83
libc/calls/oldbench.c Normal file
View file

@ -0,0 +1,83 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/bits/bits.h"
#include "libc/bits/initializer.internal.h"
#include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/rdtsc.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/clock.h"
#include "libc/time/time.h"
static struct Now {
bool once;
uint64_t k0;
long double r0, cpn;
} g_now;
static long double GetTimeSample(void) {
uint64_t tick1, tick2;
long double time1, time2;
sched_yield();
time1 = dtime(CLOCK_REALTIME);
tick1 = rdtsc();
nanosleep(&(struct timespec){0, 1000000}, NULL);
time2 = dtime(CLOCK_REALTIME);
tick2 = rdtsc();
return (time2 - time1) * 1e9 / MAX(1, tick2 - tick1);
}
static long double MeasureNanosPerCycle(void) {
bool tc;
int i, n;
long double avg, samp;
tc = __time_critical;
__time_critical = true;
if (IsWindows()) {
n = 30;
} else {
n = 20;
}
for (avg = 1.0L, i = 1; i < n; ++i) {
samp = GetTimeSample();
avg += (samp - avg) / i;
}
__time_critical = tc;
STRACE("MeasureNanosPerCycle cpn*1000=%d", (long)(avg * 1000));
return avg;
}
static void Refresh(void) {
struct Now now;
now.cpn = MeasureNanosPerCycle();
now.r0 = dtime(CLOCK_REALTIME);
now.k0 = rdtsc();
now.once = true;
memcpy(&g_now, &now, sizeof(now));
}
long double ConvertTicksToNanos(uint64_t ticks) {
if (!g_now.once) Refresh();
return ticks * g_now.cpn; /* pico scale */
}

View file

@ -23,6 +23,7 @@
#include "libc/nt/enum/fileflagandattributes.h" #include "libc/nt/enum/fileflagandattributes.h"
#include "libc/nt/ipc.h" #include "libc/nt/ipc.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -42,9 +43,9 @@ textwindows int sys_pipe_nt(int pipefd[2], unsigned flags) {
} else { } else {
mode = kNtPipeTypeMessage | kNtPipeReadmodeMessage; mode = kNtPipeTypeMessage | kNtPipeReadmodeMessage;
} }
if ((hin = CreateNamedPipe(pipename, if ((hin = CreateNamedPipe(
kNtPipeAccessInbound | kNtFileFlagOverlapped, mode, pipename, kNtPipeAccessInbound | kNtFileFlagOverlapped, mode, 1,
1, 512, 512, 0, &kNtIsInheritable)) != -1) { PIPE_BUF, PIPE_BUF, 0, &kNtIsInheritable)) != -1) {
if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable, if ((hout = CreateFile(pipename, kNtGenericWrite, 0, &kNtIsInheritable,
kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) { kNtOpenExisting, kNtFileFlagOverlapped, 0)) != -1) {
g_fds.p[reader].kind = kFdFile; g_fds.p[reader].kind = kFdFile;

View file

@ -1,148 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 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/assert.h"
#include "libc/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/spinlock.h"
#include "libc/log/libfatal.internal.h"
#include "libc/macros.internal.h"
#include "libc/mem/alloca.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/str/path.h"
#include "libc/str/str.h"
#include "libc/str/tpenc.h"
#include "libc/str/utf16.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/prot.h"
#define SIZE 1024
#define CTL_KERN 1
#define KERN_PROC 14
#define KERN_PROC_PATHNAME_FREEBSD 12
#define KERN_PROC_PATHNAME_NETBSD 5
char program_executable_name[SIZE];
static textwindows bool GetNtExePath(char exe[SIZE]) {
bool32 rc;
uint64_t w;
wint_t x, y;
uint32_t i, j;
char16_t p[PATH_MAX + 1];
p[0] = 0;
rc = GetModuleFileName(0, p, ARRAYLEN(p));
NTTRACE("GetModuleFileName(0, [%#hs]) → %hhhd", p, rc);
if (!rc) return false;
j = 0;
if (p[0] != '\\' || p[1] != '\\' || p[2] != '?' || p[3] != '\\') {
exe[j++] = '/';
exe[j++] = '/';
exe[j++] = '?';
exe[j++] = '/';
}
for (i = 0; (x = p[i++] & 0xffff);) {
if (!IsUcs2(x)) {
y = p[i++] & 0xffff;
x = MergeUtf16(x, y);
}
if (x == '\\') x = '/';
w = tpenc(x);
do {
exe[j] = w;
if (++j == SIZE) {
return false;
}
} while ((w >>= 8));
}
exe[j] = 0;
return true;
}
static void ReadProgramExecutableName(char exe[SIZE], char *argv0,
uintptr_t *auxv) {
int e;
size_t m;
ssize_t n;
int cmd[4];
char *p, *t;
e = errno;
if (!IsWindows() || !GetNtExePath(exe)) {
for (p = 0; *auxv; auxv += 2) {
if (*auxv == AT_EXECFN) {
p = (char *)auxv[1];
break;
}
}
n = 0;
if (!p) p = argv0;
if (p) {
if (!_isabspath(p)) {
if (getcwd(exe, SIZE - 1)) {
n = strlen(exe);
exe[n++] = '/';
}
}
for (; *p; ++p) {
if (n + 1 < SIZE) {
exe[n++] = *p;
}
}
}
exe[n] = 0;
}
errno = e;
}
/**
* Returns absolute path of executable.
*
* This variable is initialized automatically at startup. The path is
* basically `argv[0]` except some extra vetting is done to provide
* stronger assurance that the path can be counted upon to exist.
*
* For example, if your program is executed as a relative path and then
* your program calls `chdir()`, then `argv[0]` will be incorrect; but
* `program_executable_name` will work, because it prefixed `getcwd()`
* early in the initialization phase.
*
* @see GetInterpreterExecutableName()
* @see program_invocation_short_name
* @see program_invocation_name
*/
char *GetProgramExecutableName(void) {
static bool once;
if (!once) {
ReadProgramExecutableName(program_executable_name, __argv[0], __auxv);
once = true;
}
return program_executable_name;
}
// try our best to memoize it before a chdir() happens
const void *const program_executable_name_init_ctor[] initarray = {
GetProgramExecutableName,
};

View file

@ -22,13 +22,14 @@
/** /**
* Adds signal to set. * Adds signal to set.
* *
* @return true, false, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raises EINVAL if `1 sig NSIG` isn't the case
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int sigaddset(sigset_t *set, int sig) { int sigaddset(sigset_t *set, int sig) {
unsigned i = sig - 1; _Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
if (i < sizeof(set->__bits) * 8) { if (1 <= sig && sig <= NSIG) {
set->__bits[i >> 6] |= 1ull << (i & 63); set->__bits[(sig - 1) >> 6] |= 1ull << ((sig - 1) & 63);
return 0; return 0;
} else { } else {
return einval(); return einval();

View file

@ -23,12 +23,13 @@
* Removes signal from set. * Removes signal from set.
* *
* @return 0 on success, or -1 w/ errno * @return 0 on success, or -1 w/ errno
* @raises EINVAL if `1 sig NSIG` isn't the case
* @asyncsignalsafe * @asyncsignalsafe
*/ */
int sigdelset(sigset_t *set, int sig) { int sigdelset(sigset_t *set, int sig) {
unsigned i = sig - 1; _Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
if (i < sizeof(set->__bits) * 8) { if (1 <= sig && sig <= NSIG) {
set->__bits[i >> 6] &= ~(1ull << (i & 63)); set->__bits[(sig - 1) >> 6] &= ~(1ull << ((sig - 1) & 63));
return 0; return 0;
} else { } else {
return einval(); return einval();

View file

@ -22,14 +22,15 @@
/** /**
* Returns true if signal is member of set. * Returns true if signal is member of set.
* *
* @return true, false, or -1 w/ errno * @return 1 if set, 0 if not set, or -1 w/ errno
* @raises EINVAL if `1 sig NSIG` isn't the case
* @asyncsignalsafe * @asyncsignalsafe
* @vforksafe * @vforksafe
*/ */
int sigismember(const sigset_t *set, int sig) { int sigismember(const sigset_t *set, int sig) {
unsigned i = sig - 1; _Static_assert(sizeof(set->__bits[0]) * CHAR_BIT == 64, "");
if (i < sizeof(set->__bits) * 8) { if (1 <= sig && sig <= NSIG) {
return (set->__bits[i >> 6] >> (i & 63)) & 1; return !!(set->__bits[(sig - 1) >> 6] & (1ull << ((sig - 1) & 63)));
} else { } else {
return einval(); return einval();
} }

View file

@ -10,7 +10,7 @@ struct stat { /* cosmo abi */
uint32_t st_mode; /* 24: octal file mask thing */ uint32_t st_mode; /* 24: octal file mask thing */
uint32_t st_uid; /* 28: user id of owner */ uint32_t st_uid; /* 28: user id of owner */
uint32_t st_gid; /* group id of owning group */ uint32_t st_gid; /* group id of owning group */
uint32_t st_flags; /* flags (bsd-only) */ uint32_t st_flags; /* nt/xnu/bsd-only */
uint64_t st_rdev; /* id of device if a special file */ uint64_t st_rdev; /* id of device if a special file */
int64_t st_size; /* bytes in file */ int64_t st_size; /* bytes in file */
int64_t st_blksize; /* preferred chunking for underlying filesystem */ int64_t st_blksize; /* preferred chunking for underlying filesystem */
@ -19,7 +19,7 @@ struct stat { /* cosmo abi */
struct timespec st_mtim; /* modified time */ struct timespec st_mtim; /* modified time */
struct timespec st_ctim; /* complicated time */ struct timespec st_ctim; /* complicated time */
struct timespec st_birthtim; struct timespec st_birthtim;
uint64_t st_gen; uint64_t st_gen; /* xnu/bsd only */
}; };
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -0,0 +1,94 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 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/bits/bits.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
#include "libc/log/libfatal.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
#define LAZY_RHEL7_RELOCATION 0xfffff
#define GetStr(tab, rva) ((char *)(tab) + (rva))
#define GetSection(e, s) ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset))
#define GetShstrtab(e) GetSection(e, GetShdr(e, (e)->e_shstrndx))
#define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name)
#define GetPhdr(e, i) \
((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \
(size_t)(e)->e_phentsize * (i)))
#define GetShdr(e, i) \
((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \
(size_t)(e)->e_shentsize * (i)))
static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = 0; i < e->e_shnum; ++i) {
shdr = GetShdr(e, i);
name = GetSectionName(e, GetShdr(e, i));
if (shdr->sh_type == SHT_STRTAB) {
name = GetSectionName(e, GetShdr(e, i));
if (name && READ64LE(name) == READ64LE(".dynstr")) {
if (n) *n = shdr->sh_size;
return GetSection(e, shdr);
}
}
}
return 0;
}
static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) {
Elf64_Half i;
Elf64_Shdr *shdr;
for (i = e->e_shnum; i > 0; --i) {
shdr = GetShdr(e, i - 1);
if (shdr->sh_type == SHT_DYNSYM) {
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
if (n) *n = shdr->sh_size / shdr->sh_entsize;
return GetSection(e, shdr);
}
}
return 0;
}
/**
* Returns Linux Kernel Virtual Dynamic Shared Object function address.
*/
void *__vdsofunc(const char *name) {
size_t m;
char *names;
Elf64_Ehdr *ehdr;
Elf64_Xword i, n;
Elf64_Sym *symtab, *sym;
if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) &&
(names = GetDynamicStringTable(ehdr, &m)) &&
(symtab = GetDynamicSymbolTable(ehdr, &n))) {
for (i = 0; i < n; ++i) {
if (!__strcmp(names + symtab[i].st_name, name)) {
return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION);
}
}
}
return 0;
}

View file

@ -26,6 +26,8 @@ void GetElfVirtualAddressRange(const Elf64_Ehdr *, size_t, intptr_t *,
intptr_t *); intptr_t *);
char *GetElfString(const Elf64_Ehdr *, size_t, const char *, Elf64_Word); char *GetElfString(const Elf64_Ehdr *, size_t, const char *, Elf64_Word);
const char *GetElfSectionName(const Elf64_Ehdr *, size_t, Elf64_Shdr *); const char *GetElfSectionName(const Elf64_Ehdr *, size_t, Elf64_Shdr *);
Elf64_Sym *GetElfDynSymbolTable(const Elf64_Ehdr *, size_t, Elf64_Xword *);
char *GetElfDynStringTable(const Elf64_Ehdr *, size_t);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -0,0 +1,40 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/str/str.h"
char *GetElfDynStringTable(const Elf64_Ehdr *elf, size_t mapsize) {
char *name;
Elf64_Half i;
Elf64_Shdr *shdr;
if (elf->e_shentsize) {
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i);
if (shdr->sh_type == SHT_STRTAB) {
name = GetElfSectionName(elf, mapsize,
GetElfSectionHeaderAddress(elf, mapsize, i));
if (name && !strcmp(name, ".dynstr")) {
return GetElfSectionAddress(elf, mapsize, shdr);
}
}
}
}
return NULL;
}

View file

@ -0,0 +1,37 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 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/elf/def.h"
#include "libc/elf/elf.h"
Elf64_Sym *GetElfDynSymbolTable(const Elf64_Ehdr *elf, size_t mapsize,
Elf64_Xword *out_count) {
Elf64_Half i;
Elf64_Shdr *shdr;
if (elf->e_shentsize) {
for (i = elf->e_shnum; i > 0; --i) {
shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1);
if (shdr->sh_type == SHT_DYNSYM) {
if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue;
if (out_count) *out_count = shdr->sh_size / shdr->sh_entsize;
return GetElfSectionAddress(elf, mapsize, shdr);
}
}
}
return NULL;
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#define ShouldUseMsabiAttribute() 1
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
@ -44,18 +43,18 @@ int strerror_wr(int err, uint32_t winerr, char *buf, size_t size) {
for (; (c = *sym++); --size) for (; (c = *sym++); --size)
if (size > 1) *buf++ = c; if (size > 1) *buf++ = c;
if (size) *buf = 0; if (size) *buf = 0;
} else if (!IsWindows()) { } else if (!IsWindows() || err == winerr || !winerr) {
ksnprintf(buf, size, "%s[%d][%s]", sym, err, msg); ksnprintf(buf, size, "%s:%d:%s", sym, err, msg);
} else { } else {
if ((n = __imp_FormatMessageW( if ((n = FormatMessage(
kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0, kNtFormatMessageFromSystem | kNtFormatMessageIgnoreInserts, 0,
winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg, winerr, MAKELANGID(kNtLangNeutral, kNtSublangDefault), winmsg,
ARRAYLEN(winmsg), 0))) { ARRAYLEN(winmsg), 0))) {
while ((n && winmsg[n - 1] <= ' ') || winmsg[n - 1] == '.') --n; while ((n && winmsg[n - 1] <= ' ') || winmsg[n - 1] == '.') --n;
ksnprintf(buf, size, "%s[%d][%s][%.*hs][%d]", sym, err, msg, n, winmsg, ksnprintf(buf, size, "%s:%d:%s:%d:%.*hs", sym, err, msg, winerr, n,
winerr); winmsg);
} else { } else {
ksnprintf(buf, size, "%s[%d][%s][%d]", sym, err, msg, winerr); ksnprintf(buf, size, "%s:%d:%s:%d", sym, err, msg, winerr);
} }
} }
return 0; return 0;

View file

@ -71,7 +71,7 @@
#define CACHELINE 0x40 /* nexgen32e */ #define CACHELINE 0x40 /* nexgen32e */
#define CHAR_BIT 8 /* b/c von neumann */ #define CHAR_BIT 8 /* b/c von neumann */
#define ARG_MAX 0x8000 /* b/c windows */ #define ARG_MAX 0x8000 /* b/c windows */
#define PATH_MAX 512 /* b/c bloat */ #define PATH_MAX 511 /* b/c bloat */
#define NAME_MAX 63 /* b/c dns */ #define NAME_MAX 63 /* b/c dns */
#define CHILD_MAX 25 /* only if malloc isn't linked */ #define CHILD_MAX 25 /* only if malloc isn't linked */
#define OPEN_MAX 16 /* only if malloc isn't linked */ #define OPEN_MAX 16 /* only if malloc isn't linked */

View file

@ -62,17 +62,17 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
} else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, n - 1)) > } else if ((rc = sys_readlinkat(AT_FDCWD, "/proc/curproc/file", p, n - 1)) >
0) { 0) {
errno = e; errno = e;
p[n] = 0; p[rc] = 0;
return p; return p;
} else if (IsFreebsd() || IsNetbsd()) { } else if (IsFreebsd() || IsNetbsd()) {
cmd[0] = 1 /* CTL_KERN */; cmd[0] = 1; // CTL_KERN
cmd[1] = 14 /* KERN_PROC */; cmd[1] = 14; // KERN_PROC
if (IsFreebsd()) { if (IsFreebsd()) { //
cmd[2] = 12 /* KERN_PROC_PATHNAME */; cmd[2] = 12; // KERN_PROC_PATHNAME
} else { } else { //
cmd[2] = 5 /* KERN_PROC_PATHNAME */; cmd[2] = 5; // KERN_PROC_PATHNAME
} } //
cmd[3] = -1; /* current process */ cmd[3] = -1; // current process
if (sysctl(cmd, ARRAYLEN(cmd), p, &n, 0, 0) != -1) { if (sysctl(cmd, ARRAYLEN(cmd), p, &n, 0, 0) != -1) {
errno = e; errno = e;
return p; return p;

View file

@ -324,8 +324,8 @@ textstartup void __printargs(const char *prologue) {
PRINT(" ☼ %s = %#s", "kTmpPath", kTmpPath); PRINT(" ☼ %s = %#s", "kTmpPath", kTmpPath);
PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory); PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory); PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
PRINT(" ☼ %s = %#s", "program_executable_name", GetProgramExecutableName()); PRINT(" ☼ %s = %#s", "GetProgramExecutableName", GetProgramExecutableName());
PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName()", PRINT(" ☼ %s = %#s", "GetInterpreterExecutableName",
GetInterpreterExecutableName(path, sizeof(path))); GetInterpreterExecutableName(path, sizeof(path)));
PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0)); PRINT(" ☼ %s = %p", "RSP", __builtin_frame_address(0));
PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr(0)); PRINT(" ☼ %s = %p", "GetStackAddr()", GetStackAddr(0));

View file

@ -14,7 +14,6 @@ extern char **__argv; /* CRT */
extern char **__envp; /* CRT */ extern char **__envp; /* CRT */
extern unsigned long *__auxv; /* CRT */ extern unsigned long *__auxv; /* CRT */
extern intptr_t __oldstack; /* CRT */ extern intptr_t __oldstack; /* CRT */
extern char program_executable_name[]; /* RII */
extern char *program_invocation_name; /* RII */ extern char *program_invocation_name; /* RII */
extern char *program_invocation_short_name; /* RII */ extern char *program_invocation_short_name; /* RII */
extern int g_ftrace; /* CRT */ extern int g_ftrace; /* CRT */

View file

@ -219,9 +219,6 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
} }
} }
env16 = GetEnvironmentStrings(); env16 = GetEnvironmentStrings();
for (char16_t *e = env16; *e; e += StrLen16(e) + 1) {
NTTRACE("GetEnvironmentStrings() → %!#hs", e);
}
NTTRACE("WinMainNew() loading environment"); NTTRACE("WinMainNew() loading environment");
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp, GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
ARRAYLEN(wa->envp) - 1); ARRAYLEN(wa->envp) - 1);

View file

@ -436,10 +436,10 @@ syscon ioctl TIOCINQ 0x541b 0x4004667f 0x4004667f 0x4004667f 0x4004667f
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary # group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon at AT_FDCWD -100 -2 -100 -100 -100 -100 # faked nt syscon at AT_FDCWD -100 -2 -100 -100 -100 -100 # faked nt
syscon at AT_SYMLINK_NOFOLLOW 0x0100 0x20 0x0200 2 0x200 0x0100 # faked nt syscon at AT_SYMLINK_NOFOLLOW 0x0100 0x20 0x0200 2 0x200 0x0100 # faked nt
syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 # see linkat(2)
syscon at AT_REMOVEDIR 0x0200 0x80 0x0800 8 0x800 0x0200 # faked nt syscon at AT_REMOVEDIR 0x0200 0x80 0x0800 8 0x800 0x0200 # faked nt
syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0 syscon at AT_EACCESS 0x0200 0x10 0x0100 1 0x100 0
syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc. syscon at AT_EMPTY_PATH 0x1000 0 0 0 0 0 # linux 2.6.39+; see unlink, O_TMPFILE, etc.
syscon at AT_SYMLINK_FOLLOW 0x0400 0x40 0x0400 4 0x400 0 # uhhh wut
# memfd_create() flags # memfd_create() flags
# #
@ -1229,6 +1229,11 @@ syscon mount MNT_NOCLUSTERR 0 0 0x40000000 0 0 0 # disable cluster
syscon mount MNT_NOCLUSTERW 0 0 0x80000000 0 0 0 # disable cluster write syscon mount MNT_NOCLUSTERW 0 0 0x80000000 0 0 0 # disable cluster write
syscon mount MNT_SNAPSHOT 0 0x40000000 0x01000000 0 0 0 # confusing syscon mount MNT_SNAPSHOT 0 0x40000000 0x01000000 0 0 0 # confusing
# limits
#
# group name GNU/Systemd XNU's Not UNIX! FreeBSD OpenBSD NetBSD The New Technology Commentary
syscon misc PIPE_BUF 4096 512 512 512 512 4096 # bsd consensus
# unmount() flags # unmount() flags
# a.k.a. umount2() on linux # a.k.a. umount2() on linux
# #
@ -3055,7 +3060,6 @@ syscon misc NGREG 23 0 0 0 0 0
syscon misc NOGROUP -1 0xffff 0xffff 0xffff 0xffff 0 # bsd consensus syscon misc NOGROUP -1 0xffff 0xffff 0xffff 0xffff 0 # bsd consensus
syscon misc ORDERED_QUEUE_TAG 34 0 0 0 0 0 syscon misc ORDERED_QUEUE_TAG 34 0 0 0 0 0
syscon misc ORIG_RAX 15 0 0 0 0 0 syscon misc ORIG_RAX 15 0 0 0 0 0
syscon misc PIPE_BUF 0x1000 0x0200 0x0200 0x0200 0x0200 0 # bsd consensus
syscon misc PRE_FETCH 52 0 0 0 0 0 syscon misc PRE_FETCH 52 0 0 0 0 0
syscon misc QUEUE_FULL 20 0 0 0 0 0 syscon misc QUEUE_FULL 20 0 0 0 0 0
syscon misc REASSIGN_BLOCKS 7 0 0 0 0 0 syscon misc REASSIGN_BLOCKS 7 0 0 0 0 0

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #include "libc/sysv/consts/syscon.internal.h"
.syscon misc,PIPE_BUF,0x1000,0x0200,0x0200,0x0200,0x0200,0 .syscon misc,PIPE_BUF,4096,512,512,512,512,4096

View file

@ -72,5 +72,5 @@ TEST(access, testRequestWriteOnReadOnly_returnsEaccess) {
} }
TEST(access, runThisExecutable) { TEST(access, runThisExecutable) {
ASSERT_SYS(0, 0, access(program_executable_name, R_OK | X_OK)); ASSERT_SYS(0, 0, access(GetProgramExecutableName(), R_OK | X_OK));
} }

View file

@ -1,7 +1,7 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│ /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,22 +16,14 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/nexgen32e/x86feature.h" #include "libc/calls/calls.h"
#include "libc/macros.internal.h" #include "libc/calls/struct/timespec.h"
#include "libc/sysv/consts/clock.h"
#include "libc/testlib/ezbench.h"
#include "libc/testlib/testlib.h"
// Returns timestamp without needing system calls. BENCH(clock_gettime, bench) {
// struct timespec ts;
// @return seconds since unix epoch in %st0 EZBENCH2("nowl", donothing, nowl());
// @note uses microsecond scale fallback on k8 or vm EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_REALTIME, &ts));
.initbss 202,_init_nowl }
nowl: .quad 0
.endobj nowl,globl
.previous
.init.start 202,_init_nowl
ezlea nowl_sys,ax
ezlea nowl_art,cx
testb X86_HAVE(INVTSC)+kCpuids(%rip)
cmovnz %rcx,%rax
stosq
.init.end 202,_init_nowl

View file

@ -51,8 +51,8 @@ TEST(dup, clearsCloexecFlag) {
ASSERT_NE(-1, (ws = xspawn(0))); ASSERT_NE(-1, (ws = xspawn(0)));
if (ws == -2) { if (ws == -2) {
dup2(3, 0); dup2(3, 0);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "boop", 0}); (char *const[]){GetProgramExecutableName(), "boop", 0});
_exit(127); _exit(127);
} }
ASSERT_EQ(72, WEXITSTATUS(ws)); ASSERT_EQ(72, WEXITSTATUS(ws));

View file

@ -177,8 +177,8 @@ TEST(ShowCrashReports, testMemoryLeakCrash) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "6", 0}); (char *const[]){GetProgramExecutableName(), "6", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -255,8 +255,8 @@ TEST(ShowCrashReports, testStackOverrunCrash) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "5", 0}); (char *const[]){GetProgramExecutableName(), "5", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -364,8 +364,8 @@ TEST(ShowCrashReports, testDivideByZero) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "1", 0}); (char *const[]){GetProgramExecutableName(), "1", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -486,8 +486,8 @@ TEST(ShowCrashReports, testBssOverrunCrash) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "2", 0}); (char *const[]){GetProgramExecutableName(), "2", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -565,8 +565,8 @@ TEST(ShowCrashReports, testNpeCrash) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "7", 0}); (char *const[]){GetProgramExecutableName(), "7", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -625,8 +625,8 @@ TEST(ShowCrashReports, testDataOverrunCrash) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "4", 0}); (char *const[]){GetProgramExecutableName(), "4", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);
@ -680,8 +680,8 @@ TEST(ShowCrashReports, testNpeCrashAfterFinalize) {
if (!pid) { if (!pid) {
dup2(fds[1], 1); dup2(fds[1], 1);
dup2(fds[1], 2); dup2(fds[1], 2);
execv(program_executable_name, execv(GetProgramExecutableName(),
(char *const[]){program_executable_name, "8", 0}); (char *const[]){GetProgramExecutableName(), "8", 0});
_exit(127); _exit(127);
} }
close(fds[1]); close(fds[1]);

View file

@ -4,6 +4,7 @@
PKGS += TEST_LIBC_MEM PKGS += TEST_LIBC_MEM
TEST_LIBC_MEM_FILES := $(wildcard test/libc/mem/*) TEST_LIBC_MEM_FILES := $(wildcard test/libc/mem/*)
TEST_LIBC_MEM_SRCS = $(TEST_LIBC_MEM_SRCS_C) $(TEST_LIBC_MEM_SRCS_CC)
TEST_LIBC_MEM_SRCS_C = $(filter %_test.c,$(TEST_LIBC_MEM_FILES)) TEST_LIBC_MEM_SRCS_C = $(filter %_test.c,$(TEST_LIBC_MEM_FILES))
TEST_LIBC_MEM_SRCS_CC = $(filter %_test.cc,$(TEST_LIBC_MEM_FILES)) TEST_LIBC_MEM_SRCS_CC = $(filter %_test.cc,$(TEST_LIBC_MEM_FILES))
@ -12,7 +13,7 @@ TEST_LIBC_MEM_OBJS = \
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.o) $(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.o)
TEST_LIBC_MEM_COMS = \ TEST_LIBC_MEM_COMS = \
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com) \ $(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com) \
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com) $(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com)
TEST_LIBC_MEM_BINS = \ TEST_LIBC_MEM_BINS = \
@ -20,7 +21,7 @@ TEST_LIBC_MEM_BINS = \
$(TEST_LIBC_MEM_COMS:%=%.dbg) $(TEST_LIBC_MEM_COMS:%=%.dbg)
TEST_LIBC_MEM_TESTS = \ TEST_LIBC_MEM_TESTS = \
$(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com.ok) \ $(TEST_LIBC_MEM_SRCS_C:%.c=o/$(MODE)/%.com.ok) \
$(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com.ok) $(TEST_LIBC_MEM_SRCS_CC:%.cc=o/$(MODE)/%.com.ok)
TEST_LIBC_MEM_CHECKS = \ TEST_LIBC_MEM_CHECKS = \

View file

@ -1810,6 +1810,7 @@ struct linenoiseState *linenoiseBegin(const char *prompt, int ifd, int ofd) {
} }
void linenoiseReset(struct linenoiseState *l) { void linenoiseReset(struct linenoiseState *l) {
l->buf[0] = 0;
l->dirty = true; l->dirty = true;
l->final = 0; l->final = 0;
l->hindex = 0; l->hindex = 0;

View file

@ -1,6 +1,7 @@
#ifndef llimits_h #ifndef llimits_h
#define llimits_h #define llimits_h
#include "libc/limits.h"
#include "libc/math.h" #include "libc/math.h"
#include "third_party/lua/lua.h" #include "third_party/lua/lua.h"

View file

@ -1011,7 +1011,7 @@ int execute_tests(int argc, const char **argv, const char *default_filename) {
file = fopen(test_filename, "r"); file = fopen(test_filename, "r");
if (file == NULL) { if (file == NULL) {
WRITE("%s (%s) failed to open test file: %s %m\n", WRITE("%s (%s) failed to open test file: %s %m\n",
program_invocation_short_name, program_executable_name, program_invocation_short_name, GetProgramExecutableName(),
test_filename); test_filename);
if (outcome_file != NULL) fclose(outcome_file); if (outcome_file != NULL) fclose(outcome_file);
return 1; return 1;

View file

@ -663,7 +663,7 @@ Py_GetProgramFullPath(void)
{ {
static bool once; static bool once;
if (_cmpxchg(&once, false, true)) { if (_cmpxchg(&once, false, true)) {
progpath = utf8toutf32(program_executable_name, -1, 0); progpath = utf8toutf32(GetProgramExecutableName(), -1, 0);
__cxa_atexit(free, progpath, 0); __cxa_atexit(free, progpath, 0);
} }
return progpath; return progpath;

32
tool/decode/dumpvdso.c Normal file
View file

@ -0,0 +1,32 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 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/calls/calls.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h"
noasan int main(int argc, char *argv[]) {
int i = 0;
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR);
if (isatty(1)) exit(1);
for (;;) {
write(1, ((char *)ehdr) + i++, 1);
}
return 0;
}

View file

@ -27,8 +27,10 @@
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
@ -231,6 +233,21 @@ static void printelfsymboltable(void) {
} }
} }
static void printelfdynsymboltable(void) {
size_t i, symcount = 0;
Elf64_Sym *symtab = GetElfDynSymbolTable(elf, st->st_size, &symcount);
char *strtab = GetElfDynStringTable(elf, st->st_size);
char *shstrtab = GetElfSectionNameStringTable(elf, st->st_size);
if (symtab && strtab) {
printf("\n\n");
printf("\t.org\t%#x\n", (intptr_t)symtab - (intptr_t)elf);
for (i = 0; i < symcount; ++i) {
printf(".Lsym%d:\n", i);
printelfsymbol(&symtab[i], strtab, shstrtab);
}
}
}
static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize, static char *getelfsymbolname(const Elf64_Ehdr *elf, size_t mapsize,
const char *strtab, const char *shstrtab, const char *strtab, const char *shstrtab,
const Elf64_Sym *sym) { const Elf64_Sym *sym) {
@ -324,12 +341,14 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "error: not an elf executable: %'s\n", path); fprintf(stderr, "error: not an elf executable: %'s\n", path);
exit(1); exit(1);
} }
elf = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR);
startfile(); startfile();
printelfehdr(); printelfehdr();
printelfsegmentheaders(); printelfsegmentheaders();
printelfsectionheaders(); printelfsectionheaders();
printelfrelocations(); printelfrelocations();
printelfsymboltable(); printelfsymboltable();
printelfdynsymboltable();
munmap(elf, st->st_size); munmap(elf, st->st_size);
close(fd); close(fd);
return 0; return 0;

2
tool/net/demo/script.lua Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/redbean -i
print('hello world')

View file

@ -0,0 +1,93 @@
Write('<!doctype html>\r\n')
Write('<title>redbean</title>\r\n')
Write('<style>\r\n')
Write('td,th { padding: 2px 5px; }\r\n')
Write('td { white-space: nowrap; }\r\n')
Write('.l { text-align: left; }\r\n')
Write('.r { text-align: right; }\r\n')
Write('</style>\r\n')
Write('<h3>UNIX Directory Stream Demo</h3>\r\n')
Write('<table>\r\n')
Write('<thead>\r\n')
Write('<tr>\r\n')
Write('<th class=l>name\r\n')
Write('<th>type\r\n')
Write('<th class=r>ino\r\n')
Write('<th class=r>off\r\n')
Write('<th class=r>size\r\n')
Write('<th class=r>blocks\r\n')
Write('<th class=r>mode\r\n')
Write('<th class=r>uid\r\n')
Write('<th class=r>gid\r\n')
Write('<th class=r>dev\r\n')
Write('<th class=r>rdev\r\n')
Write('<th class=r>nlink\r\n')
Write('<th class=r>blksize\r\n')
Write('<th class=r>gen\r\n')
Write('<th class=r>flags\r\n')
Write('<th class=r>birthtim\r\n')
Write('<th class=r>mtim\r\n')
Write('<th class=r>atim\r\n')
Write('<th class=r>ctim\r\n')
Write('<tbody>\r\n')
dir = '.'
for name, kind, ino, off in assert(unix.opendir(dir)) do
Write('<tr>\r\n')
Write('<td>')
Write(EscapeHtml(name))
if kind == unix.DT_DIR then
Write('/')
end
Write('\r\n')
Write('<td>')
if kind == unix.DT_REG then Write('DT_REG')
elseif kind == unix.DT_DIR then Write('DT_DIR')
elseif kind == unix.DT_FIFO then Write('DT_FIFO')
elseif kind == unix.DT_CHR then Write('DT_CHR')
elseif kind == unix.DT_BLK then Write('DT_BLK')
elseif kind == unix.DT_LNK then Write('DT_LNK')
elseif kind == unix.DT_SOCK then Write('DT_SOCK')
else Write('DT_UNKNOWN')
end
Write('\r\n')
Write('<td class=r>%d\r\n' % {ino})
Write('<td class=r>%d\r\n' % {off})
st,err = unix.stat(dir..'/'..name, unix.AT_SYMLINK_NOFOLLOW)
if st then
Write('<td class=r>%d\r\n' % {st:size()})
Write('<td class=r>%d\r\n' % {st:blocks()})
Write('<td class=r>%.7o\r\n' % {st:mode()})
Write('<td class=r>%d\r\n' % {st:uid()})
Write('<td class=r>%d\r\n' % {st:gid()})
Write('<td class=r>%d\r\n' % {st:dev()})
Write('<td class=r>%d,%d\r\n' % {unix.major(st:rdev()), unix.minor(st:rdev())})
Write('<td class=r>%d\r\n' % {st:nlink()})
Write('<td class=r>%d\r\n' % {st:blksize()})
Write('<td class=r>%d\r\n' % {st:gen()})
Write('<td class=r>%#x\r\n' % {st:flags()})
function WriteTime(unixsec,nanos)
year,mon,mday,hour,min,sec,gmtoffsec = unix.localtime(unixsec)
Write('<td class=r>%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.9d%+.2d%.2d\r\n' % {
year, mon, mday, hour, min, sec, nanos,
gmtoffsec / (60 * 60), math.abs(gmtoffsec) % 60})
end
WriteTime(st:birthtim())
WriteTime(st:mtim())
WriteTime(st:atim())
WriteTime(st:ctim())
else
Write('<td class=l colspan=15>%s\r\n' % {err})
end
end
Write('</table>\r\n')

View file

@ -26,7 +26,7 @@ sid, errno = unix.getsid(0)
if sid then if sid then
Write('<dd>%d\r\n' % {sid}) Write('<dd>%d\r\n' % {sid})
else else
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {tostring(errno)})
end end
Write('<dt>unix.gethostname()\r\n') Write('<dt>unix.gethostname()\r\n')
@ -54,7 +54,7 @@ function PrintResourceLimit(name, id)
end end
Write('\r\n') Write('\r\n')
else else
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
end end
end end
PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS) PrintResourceLimit('RLIMIT_AS', unix.RLIMIT_AS)
@ -77,13 +77,13 @@ if ifs then
Write('%s %s/%d<br>\r\n' % {EscapeHtml(ifs[i].name), FormatIp(ifs[i].ip), cidr}) Write('%s %s/%d<br>\r\n' % {EscapeHtml(ifs[i].name), FormatIp(ifs[i].ip), cidr})
end end
else else
Write('%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('%s\r\n' % {EscapeHtml(tostring(errno))})
end end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DEBUG)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -91,7 +91,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_ACCEPTCONN)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -99,7 +99,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEADDR)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -107,7 +107,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_REUSEPORT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -115,7 +115,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_KEEPALIVE)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -123,7 +123,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NODELAY)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -131,7 +131,7 @@ end
secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO) secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVTIMEO)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d sec %d µs\r\n' % {secs, micros}) Write('<dd>%d sec %d µs\r\n' % {secs, micros})
end end
@ -139,7 +139,7 @@ end
secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO) secs, errno, micros = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDTIMEO)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d sec %d µs\r\n' % {secs, micros}) Write('<dd>%d sec %d µs\r\n' % {secs, micros})
end end
@ -147,7 +147,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_DONTROUTE)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -155,7 +155,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDBUF)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -163,7 +163,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVBUF)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -171,7 +171,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -179,7 +179,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_BROADCAST)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -187,7 +187,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_CORK)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -195,7 +195,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_QUICKACK)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -203,7 +203,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_DEFER_ACCEPT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -211,7 +211,7 @@ end
enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT) enabled, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_FASTOPEN_CONNECT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%s\r\n' % {enabled}) Write('<dd>%s\r\n' % {enabled})
end end
@ -219,7 +219,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_SNDLOWAT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -227,7 +227,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_SOCKET, unix.SO_RCVLOWAT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -235,7 +235,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPCNT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -243,7 +243,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_MAXSEG)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -251,7 +251,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_SYNCNT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -259,7 +259,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_NOTSENT_LOWAT)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -267,7 +267,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_WINDOW_CLAMP)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -275,7 +275,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPIDLE)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end
@ -283,7 +283,7 @@ end
bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL) bytes, errno = unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)
Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)\r\n') Write('<dt>unix.getsockopt(GetClientFd(), unix.SOL_TCP, unix.TCP_KEEPINTVL)\r\n')
if errno then if errno then
Write('<dd>%s\r\n' % {EscapeHtml(unix.strerrno(errno))}) Write('<dd>%s\r\n' % {EscapeHtml(tostring(errno))})
else else
Write('<dd>%d\r\n' % {bytes}) Write('<dd>%d\r\n' % {bytes})
end end

11
tool/net/demo/unix-raise.lua Executable file
View file

@ -0,0 +1,11 @@
#!/home/jart/bin/redbean -i
assert(unix.sigaction(unix.SIGUSR1, function(sig)
gotsigusr1 = true
end))
gotsigusr1 = false
assert(unix.raise(unix.SIGUSR1))
if gotsigusr1 then
print('hooray the signal was delivered')
else
print('oh no some other signal was handled')
end

View file

@ -1,4 +1,4 @@
local unix = require "unix" local unix = require 'unix'
local function main() local function main()
if GetMethod() ~= 'GET' and GetMethod() ~= 'HEAD' then if GetMethod() ~= 'GET' and GetMethod() ~= 'HEAD' then
@ -45,7 +45,7 @@ local function main()
Write(EncodeBase64(LoadAsset('/redbean.png'))) Write(EncodeBase64(LoadAsset('/redbean.png')))
Write('">\r\n') Write('">\r\n')
Write('redbean unix demo\r\n') Write('redbean unix demo\r\n')
Write('<span style="color:red">&nbsp;%s</span>\r\n' % {unix.strerrno(errno)}) Write('<span style="color:red">&nbsp;%s</span>\r\n' % {EscapeHtml(tostring(errno))})
Write('</h1>\r\n') Write('</h1>\r\n')
Write([[ Write([[
<p> <p>
@ -63,7 +63,6 @@ local function main()
unix.close(fd) unix.close(fd)
return return
end end
-- if pid is zero then we're the child -- if pid is zero then we're the child
-- turn into a daemon -- turn into a daemon
unix.umask(0) unix.umask(0)
@ -106,34 +105,6 @@ local function main()
unix.write(fd, 'became an autonomous daemon reparented on your init!\r\n') unix.write(fd, 'became an autonomous daemon reparented on your init!\r\n')
unix.write(fd, '</p>\r\n') unix.write(fd, '</p>\r\n')
unix.write(fd, '<h2>listing of current directory</h2>\r\n')
dir, err = unix.opendir('.')
if dir then
unix.write(fd, '<ul>\r\n')
while true do
name, errno, kind, ino, off = dir:read()
if not name then
break
end
unix.write(fd, '<li>')
unix.write(fd, EscapeHtml(VisualizeControlCodes(name)))
if kind == unix.DT_DIR then
unix.write(fd, '/')
else
st, err = unix.stat(name)
if st then
unix.write(fd, ' (%d bytes)' % {st:size()})
end
end
unix.write(fd, '\r\n')
end
unix.write(fd, '</ul>\r\n')
else
unix.write(fd, '<p>\r\n')
unix.write(fd, 'failed: %s\r\n' % {EscapeHtml(VisualizeControlCodes(unix:strerror(err)))})
unix.write(fd, '</p>\r\n')
end
-- terminate -- terminate
unix.close(fd) unix.close(fd)
unix.exit(0) unix.exit(0)

View file

@ -9,55 +9,48 @@ function main()
end end
syscall = 'commandv' syscall = 'commandv'
ls = assert(unix.commandv(cmd)) ls = assert(unix.commandv(cmd))
if ls then syscall = 'pipe'
syscall = 'pipe' reader, writer = assert(unix.pipe(unix.O_CLOEXEC))
reader, writer, errno = unix.pipe() oldint = assert(unix.sigaction(unix.SIGINT, unix.SIG_IGN))
if reader then oldquit = assert(unix.sigaction(unix.SIGQUIT, unix.SIG_IGN))
-- oldint = assert(unix.sigaction(unix.SIGINT, unix.SIG_IGN)) oldmask = assert(unix.sigprocmask(unix.SIG_BLOCK, unix.Sigset(unix.SIGCHLD)))
-- oldquit = assert(unix.sigaction(unix.SIGQUIT, unix.SIG_IGN)) syscall = 'fork'
-- oldmask = assert(unix.sigprocmask(unix.SIG_BLOCK, (1 << (unix.SIGCHLD - 1)))) child = assert(unix.fork())
syscall = 'fork' if child == 0 then
child, errno = unix.fork() unix.close(0)
if child then unix.open("/dev/null", unix.O_RDONLY)
if child == 0 then unix.close(1)
unix.close(1) unix.dup(writer)
unix.dup(writer) unix.close(2)
unix.close(writer) unix.open("/dev/null", unix.O_RDONLY)
unix.close(reader) unix.sigaction(unix.SIGINT, oldint)
-- unix.sigaction(unix.SIGINT, oldint) unix.sigaction(unix.SIGQUIT, oldquit)
-- unix.sigaction(unix.SIGQUIT, oldquit) unix.sigprocmask(unix.SIG_SETMASK, oldmask)
-- unix.sigprocmask(unix.SIG_SETMASK, oldmask) unix.execve(ls, {ls, '-Shal'})
unix.execve(ls, {ls, '-Shal'}) unix.exit(127)
unix.exit(127) else
unix.close(writer)
SetStatus(200)
SetHeader('Content-Type', 'text/plain')
while true do
data, err = unix.read(reader)
if data then
if data ~= '' then
Write(data)
else else
unix.close(writer) break
SetStatus(200)
SetHeader('Content-Type', 'text/plain')
while true do
data, errno = unix.read(reader)
if data then
if data ~= '' then
Write(data)
else
break
end
elseif errno ~= unix.EINTR then
Log(kLogWarn, 'read() failed: %s' % {unix.strerror(errno)})
break
end
end
unix.close(reader)
unix.wait(-1)
-- unix.sigaction(unix.SIGINT, oldint)
-- unix.sigaction(unix.SIGQUIT, oldquit)
-- unix.sigprocmask(unix.SIG_SETMASK, oldmask)
return
end end
elseif err:errno() ~= unix.EINTR then
Log(kLogWarn, 'read() failed: %s' % {tostring(err)})
break
end end
end end
unix.close(reader)
unix.wait(-1)
unix.sigaction(unix.SIGINT, oldint)
unix.sigaction(unix.SIGQUIT, oldquit)
unix.sigprocmask(unix.SIG_SETMASK, oldmask)
return
end end
SetStatus(200)
SetHeader('Content-Type', 'text/plain')
Write('error %s calling %s()' % {unix.strerrno(errno), syscall})
end end
main() main()

View file

@ -45,7 +45,7 @@ function main()
server = unix.socket() server = unix.socket()
unix.bind(server, ifs[i].ip) unix.bind(server, ifs[i].ip)
unix.listen(server) unix.listen(server)
ip, errno, port = unix.getsockname(server) ip, port = assert(unix.getsockname(server))
addr = '%s:%d' % {FormatIp(ip), port} addr = '%s:%d' % {FormatIp(ip), port}
url = 'http://%s' % {addr} url = 'http://%s' % {addr}
Log(kLogInfo, 'listening on %s' % {addr}) Log(kLogInfo, 'listening on %s' % {addr})
@ -65,7 +65,7 @@ function main()
if fd == mainfd then if fd == mainfd then
data, errno = unix.read(mainfd) data, errno = unix.read(mainfd)
if not data then if not data then
Log(kLogInfo, 'got %s from parent client' % {unix.strerrno(errno)}) Log(kLogInfo, 'got %s from parent client' % {tostring(errno)})
-- prevent redbean core from writing a response -- prevent redbean core from writing a response
unix.exit(1) unix.exit(1)
end end
@ -79,8 +79,7 @@ function main()
unix.write(mainfd, data) unix.write(mainfd, data)
elseif servers[fd] then elseif servers[fd] then
unix.write(mainfd, 'preparing to accept from %d<br>\r\n' % {fd}) unix.write(mainfd, 'preparing to accept from %d<br>\r\n' % {fd})
client, errno, clientip, clientport = unix.accept(fd) client, clientip, clientport = assert(unix.accept(fd))
unix.write(mainfd, 'preparing to accept from %d<br>\r\n' % {fd})
addr = '%s:%d' % {FormatIp(clientip), clientport} addr = '%s:%d' % {FormatIp(clientip), clientport}
addrs[client] = addr addrs[client] = addr
unix.write(mainfd, 'got client %s<br>\r\n' % {addr}) unix.write(mainfd, 'got client %s<br>\r\n' % {addr})

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,7 @@
#include "libc/nexgen32e/rdtscp.h" #include "libc/nexgen32e/rdtscp.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/sysconf.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/rusage.h" #include "libc/sysv/consts/rusage.h"
@ -82,6 +83,11 @@ int LuaGetCpuCore(lua_State *L) {
return 1; return 1;
} }
int LuaGetCpuCount(lua_State *L) {
lua_pushinteger(L, GetCpuCount());
return 1;
}
int LuaGetLogLevel(lua_State *L) { int LuaGetLogLevel(lua_State *L) {
lua_pushinteger(L, __log_level); lua_pushinteger(L, __log_level);
return 1; return 1;

View file

@ -35,6 +35,7 @@ int LuaEscapeUser(lua_State *);
int LuaFormatHttpDateTime(lua_State *); int LuaFormatHttpDateTime(lua_State *);
int LuaFormatIp(lua_State *); int LuaFormatIp(lua_State *);
int LuaGetCpuCore(lua_State *); int LuaGetCpuCore(lua_State *);
int LuaGetCpuCount(lua_State *);
int LuaGetCpuNode(lua_State *); int LuaGetCpuNode(lua_State *);
int LuaGetCryptoHash(lua_State *); int LuaGetCryptoHash(lua_State *);
int LuaGetHostOs(lua_State *); int LuaGetHostOs(lua_State *);

File diff suppressed because it is too large Load diff

View file

@ -175,6 +175,7 @@ o/$(MODE)/tool/net/demo/sql.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \ o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/hello.lua.zip.o \ o/$(MODE)/tool/net/demo/hello.lua.zip.o \
@ -221,6 +222,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-dir.lua.zip.o \
o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \ o/$(MODE)/tool/net/demo/unix-info.lua.zip.o \
o/$(MODE)/tool/net/demo/fetch.lua.zip.o \ o/$(MODE)/tool/net/demo/fetch.lua.zip.o \
o/$(MODE)/tool/net/demo/hello.lua.zip.o \ o/$(MODE)/tool/net/demo/hello.lua.zip.o \

View file

@ -63,6 +63,7 @@
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/gc.h" #include "libc/runtime/gc.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/stack.h" #include "libc/runtime/stack.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
@ -196,6 +197,8 @@ STATIC_YOINK("zip_uri_support");
// puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~ // puncts not used: !"#$%&'()*+,-./;<=>@[\]^_`{|}~
#define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:" #define GETOPTS "BSVZabdfghijkmsuvzA:C:D:F:G:H:K:L:M:P:R:T:U:c:e:l:p:r:t:"
extern unsigned long long __kbirth;
static const uint8_t kGzipHeader[] = { static const uint8_t kGzipHeader[] = {
0x1F, // MAGNUM 0x1F, // MAGNUM
0x8B, // MAGNUM 0x8B, // MAGNUM
@ -4956,6 +4959,7 @@ static const luaL_Reg kLuaFuncs[] = {
{"GetComment", LuaGetAssetComment}, // {"GetComment", LuaGetAssetComment}, //
{"GetCookie", LuaGetCookie}, // {"GetCookie", LuaGetCookie}, //
{"GetCpuCore", LuaGetCpuCore}, // {"GetCpuCore", LuaGetCpuCore}, //
{"GetCpuCount", LuaGetCpuCount}, //
{"GetCpuNode", LuaGetCpuNode}, // {"GetCpuNode", LuaGetCpuNode}, //
{"GetCryptoHash", LuaGetCryptoHash}, // {"GetCryptoHash", LuaGetCryptoHash}, //
{"GetDate", LuaGetDate}, // {"GetDate", LuaGetDate}, //
@ -5192,6 +5196,7 @@ static void LuaPrint(lua_State *L) {
static void LuaInterpreter(lua_State *L) { static void LuaInterpreter(lua_State *L) {
int i, n, sig, status; int i, n, sig, status;
const char *script; const char *script;
if (funtrace) ftrace_install();
if (optind < __argc) { if (optind < __argc) {
script = __argv[optind]; script = __argv[optind];
if (!strcmp(script, "-")) script = 0; if (!strcmp(script, "-")) script = 0;
@ -5201,7 +5206,11 @@ static void LuaInterpreter(lua_State *L) {
luaL_checkstack(L, n + 3, "too many script args"); luaL_checkstack(L, n + 3, "too many script args");
for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i); for (i = 1; i <= n; i++) lua_rawgeti(L, -i, i);
lua_remove(L, -i); // remove arg table from stack lua_remove(L, -i); // remove arg table from stack
if (funtrace) ++g_ftrace;
if (systrace) ++__strace;
status = lua_runchunk(L, n, LUA_MULTRET); status = lua_runchunk(L, n, LUA_MULTRET);
if (systrace) --__strace;
if (funtrace) --g_ftrace;
} }
lua_report(L, status); lua_report(L, status);
} else { } else {
@ -5225,7 +5234,9 @@ static void LuaInterpreter(lua_State *L) {
exit(1); exit(1);
} }
if (status == LUA_OK) { if (status == LUA_OK) {
if (funtrace) ++g_ftrace;
status = lua_runchunk(GL, 0, LUA_MULTRET); status = lua_runchunk(GL, 0, LUA_MULTRET);
if (funtrace) --g_ftrace;
} }
if (status == LUA_OK) { if (status == LUA_OK) {
LuaPrint(GL); LuaPrint(GL);
@ -6358,7 +6369,6 @@ static int HandleConnection(size_t i) {
connectionclose = false; connectionclose = false;
if (!IsTiny()) { if (!IsTiny()) {
if (systrace) { if (systrace) {
extern unsigned long long __kbirth;
__strace = 1; __strace = 1;
__kbirth = rdtsc(); __kbirth = rdtsc();
} }
@ -6474,18 +6484,20 @@ static void RestoreApe(void) {
if (endswith(zpath, ".com.dbg")) return; if (endswith(zpath, ".com.dbg")) return;
if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) { if ((a = GetAssetZip("/.ape", 5)) && (p = LoadAsset(a, &n))) {
close(zfd); close(zfd);
if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1) if ((zfd = OpenExecutable()) == -1 || WRITE(zfd, p, n) == -1) {
WARNF("(srvr) can't restore .ape"); WARNF("(srvr) can't restore .ape");
}
free(p); free(p);
} else { } else {
INFOF("(srvr) /.ape not found"); DEBUGF("(srvr) /.ape not found");
} }
} }
static int HandleReadline(void) { static int HandleReadline(void) {
int status; int status;
lua_State *L = GL;
for (;;) { for (;;) {
status = lua_loadline(GL); status = lua_loadline(L);
if (status < 0) { if (status < 0) {
if (status == -1) { if (status == -1) {
OnTerm(SIGHUP); // eof OnTerm(SIGHUP); // eof
@ -6508,12 +6520,12 @@ static int HandleReadline(void) {
linenoiseDisableRawMode(); linenoiseDisableRawMode();
LUA_REPL_LOCK; LUA_REPL_LOCK;
if (status == LUA_OK) { if (status == LUA_OK) {
status = lua_runchunk(GL, 0, LUA_MULTRET); status = lua_runchunk(L, 0, LUA_MULTRET);
} }
if (status == LUA_OK) { if (status == LUA_OK) {
LuaPrint(GL); LuaPrint(L);
} else { } else {
lua_report(GL, status); lua_report(L, status);
} }
LUA_REPL_UNLOCK; LUA_REPL_UNLOCK;
if (lua_repl_isterminal) { if (lua_repl_isterminal) {
@ -6683,26 +6695,28 @@ static int EventLoop(int ms) {
} }
static void ReplEventLoop(void) { static void ReplEventLoop(void) {
lua_State *L = GL;
DEBUGF("ReplEventLoop()"); DEBUGF("ReplEventLoop()");
polls[0].fd = 0; polls[0].fd = 0;
lua_repl_completions_callback = HandleCompletions; lua_repl_completions_callback = HandleCompletions;
lua_initrepl(GL, "redbean"); lua_initrepl(L, "redbean");
if (lua_repl_isterminal) { if (lua_repl_isterminal) {
linenoiseEnableRawMode(0); linenoiseEnableRawMode(0);
} }
EventLoop(100); EventLoop(100);
linenoiseDisableRawMode(); linenoiseDisableRawMode();
lua_freerepl(); lua_freerepl();
lua_settop(GL, 0); // clear stack lua_settop(L, 0); // clear stack
polls[0].fd = -1; polls[0].fd = -1;
} }
static uint32_t WindowsReplThread(void *arg) { static uint32_t WindowsReplThread(void *arg) {
int sig; int sig;
lua_State *L = GL;
DEBUGF("WindowsReplThread()"); DEBUGF("WindowsReplThread()");
lua_repl_blocking = true; lua_repl_blocking = true;
lua_repl_completions_callback = HandleCompletions; lua_repl_completions_callback = HandleCompletions;
lua_initrepl(GL, "redbean"); lua_initrepl(L, "redbean");
if (lua_repl_isterminal) { if (lua_repl_isterminal) {
linenoiseEnableRawMode(0); linenoiseEnableRawMode(0);
} }
@ -6714,7 +6728,7 @@ static uint32_t WindowsReplThread(void *arg) {
linenoiseDisableRawMode(); linenoiseDisableRawMode();
lua_freerepl(); lua_freerepl();
LUA_REPL_LOCK; LUA_REPL_LOCK;
lua_settop(GL, 0); // clear stack lua_settop(L, 0); // clear stack
LUA_REPL_UNLOCK; LUA_REPL_UNLOCK;
if ((sig = linenoiseGetInterrupt())) { if ((sig = linenoiseGetInterrupt())) {
raise(sig); raise(sig);
@ -6896,7 +6910,7 @@ void RedBean(int argc, char *argv[]) {
(shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE), (shared = mmap(NULL, ROUNDUP(sizeof(struct Shared), FRAMESIZE),
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS,
-1, 0))); -1, 0)));
zpath = program_executable_name; zpath = GetProgramExecutableName();
CHECK_NE(-1, (zfd = open(zpath, O_RDONLY))); CHECK_NE(-1, (zfd = open(zpath, O_RDONLY)));
CHECK_NE(-1, fstat(zfd, &zst)); CHECK_NE(-1, fstat(zfd, &zst));
OpenZip(true); OpenZip(true);