Add raw memory visualization tool to redbean

This change introduces a `-W /dev/pts/1` flag to redbean. What it does
is use the mincore() system call to create a dual-screen terminal
display that lets you troubleshoot the virtual address space. This is
useful since page faults are an important thing to consider when using a
forking web server. Now we have a colorful visualization of which pages
are going to fault and which ones are resident in memory.

The memory monitor, if enabled, spawns as a thread that just outputs
ANSI codes to the second terminal in a loop. In order to make this
happen using the new clone() polyfill, stdio is now thread safe.

This change also introduces some new demo pages to redbean. It also
polishes the demos we already have, to look a bit nicer and more
presentable for the upcoming release, with better explanations too.
This commit is contained in:
Justine Tunney 2022-05-14 04:33:58 -07:00
parent 578cb21591
commit 80b211e314
106 changed files with 1483 additions and 592 deletions

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
clearerr_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call clearerr
pop %rbp
ret
.endfn clearerr_unlocked,globl
// Clears error state on stream.
//
// @param rdi has stream pointer
// @see clearerr_unlocked()
clearerr:
mov %rdi,%r11
ezlea clearerr_unlocked,ax
jmp stdio_unlock
.endfn clearerr,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
feof_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call feof
pop %rbp
ret
.endfn feof_unlocked,globl
// Returns true if stream is in end-of-file state.
//
// @param rdi has file stream object pointer
// @note EOF doesn't count
// @see feof_unlocked()
feof: mov %rdi,%r11
ezlea feof_unlocked,ax
jmp stdio_unlock
.endfn feof,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
ferror_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call ferror
pop %rbp
ret
.endfn ferror_unlocked,globl
// Returns nonzero if stream is in error state.
//
// @param rdi has file stream object pointer
// @note EOF doesn't count
// @see ferror_unlocked()
ferror: mov %rdi,%r11
ezlea ferror_unlocked,ax
jmp stdio_unlock
.endfn ferror,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
fflush_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fflush
pop %rbp
ret
.endfn fflush_unlocked,globl
// Blocks until data from stream buffer is written out.
//
// @param rdi is the stream handle
// @return 0 on success or -1 w/ errno
// @see fflush_unlocked()
fflush: mov %rdi,%r11
ezlea fflush_unlocked,ax
jmp stdio_unlock
.endfn fflush,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
fgetc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fgetc
pop %rbp
ret
.endfn fgetc_unlocked,globl
// Reads byte from stream.
//
// @param rdi has stream object pointer
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
fgetc: mov %rdi,%r11
ezlea fgetc_unlocked,ax
jmp stdio_unlock
.endfn fgetc,globl

View file

@ -18,11 +18,19 @@
*/
#include "libc/macros.internal.h"
fgets_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fgets
pop %rbp
ret
.endfn fgets_unlocked,globl
// Reads line from stream.
//
// This function is similar to getline() except it'll truncate
// lines exceeding size. The line ending marker is included
// and may be removed using _chomp().
//
// @param rdi is output buffer
// @param rsi is size of rdi buffer
// @param rdx is file stream object pointer
// @return rax has rdi on success, NULL on error or
// NULL if EOF happens with zero chars read
// @see fgets_unlocked()
fgets: mov %rdx,%r11
ezlea fgets_unlocked,ax
jmp stdio_unlock
.endfn fgets,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
fgetwc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fgetwc
pop %rbp
ret
.endfn fgetwc_unlocked,globl
// Reads UTF-8 wide character from stream.
//
// @param rdi has stream object pointer
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
fgetwc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn fgetwc,globl

View file

@ -18,11 +18,17 @@
*/
#include "libc/macros.internal.h"
fgetws_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fgetws
pop %rbp
ret
.endfn fgetws_unlocked,globl
// Reads UTF-8 content from stream into UTF-32 buffer.
//
// This function is similar to getline() except it'll truncate lines
// exceeding size. The line ending marker is included and may be removed
// using _chomp().
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is size of rdi buffer
// @param rsi is file stream object pointer
// @see fgetws_unlocked()
fgetws: mov %rdx,%r11
ezlea fgetws_unlocked,ax
jmp stdio_unlock
.endfn fgetws,globl

View file

@ -18,11 +18,11 @@
*/
#include "libc/macros.internal.h"
fileno_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fileno
pop %rbp
ret
.endfn fileno_unlocked,globl
// Returns file descriptor associated with stream.
//
// @param rdi has file stream object pointer
// @see fileno_unlocked()
fileno: mov %rdi,%r11
ezlea fileno_unlocked,ax
jmp stdio_unlock
.endfn fileno,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
fputc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fputc
pop %rbp
ret
.endfn fputc_unlocked,globl
// Writes character to stream.
//
// @param rdi c is byte to buffer or write, which is masked
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
fputc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn fputc,globl

View file

@ -18,11 +18,17 @@
*/
#include "libc/macros.internal.h"
fputs_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fputs
pop %rbp
ret
.endfn fputs_unlocked,globl
// Writes string to stream.
//
// Writing stops at the NUL-terminator, which isn't included in output.
// This function blocks until the full string is written, unless an
// unrecoverable error happens.
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputs_unlocked()
fputs: mov %rsi,%r11
ezlea fputs_unlocked,ax
jmp stdio_unlock
.endfn fputs,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
fputwc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fputwc
pop %rbp
ret
.endfn fputwc_unlocked,globl
// Writes wide character to stream.
//
// @param rdi has wide character
// @param rsi has file object stream pointer
// @return rax is wide character if written or -1 w/ errno
// @see fputwc_unlocked()
fputwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn fputwc,globl

View file

@ -18,11 +18,17 @@
*/
#include "libc/macros.internal.h"
fputws_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fputws
pop %rbp
ret
.endfn fputws_unlocked,globl
// Writes wide character string to stream.
//
// Writing stops at the NUL-terminator, which isn't included in output.
// This function blocks until the full string is written, unless an
// unrecoverable error happens.
//
// @param rdi is nul-terminated string that's non-null
// @param rsi is file object stream pointer
// @return strlen(rdi) on success or -1 w/ errno
// @see fputws_unlocked()
fputws: mov %rsi,%r11
ezlea fputws_unlocked,ax
jmp stdio_unlock
.endfn fputws,globl

View file

@ -18,11 +18,15 @@
*/
#include "libc/macros.internal.h"
fread_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fread
pop %rbp
ret
.endfn fread_unlocked,globl
// Reads data from stream.
//
// @param rdi has pointer to data to read
// @param rsi stride specifies the size of individual items
// @param rdx count is the number of strides to read
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fread_unlocked()
fread: mov %rcx,%r11
ezlea fread_unlocked,ax
jmp stdio_unlock
.endfn fread,globl

View file

@ -18,11 +18,15 @@
*/
#include "libc/macros.internal.h"
fwrite_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fwrite
pop %rbp
ret
.endfn fwrite_unlocked,globl
// Writes data to stream.
//
// @param rdi has pointer to data to write
// @param rsi stride specifies the size of individual items
// @param rdx count is the number of strides to write
// @param rcx has file object stream pointer
// @return count on success, [0,count) on EOF, 0 on error or count==0
// @see fwrite_unlocked()
fwrite: mov %rcx,%r11
ezlea fwrite_unlocked,ax
jmp stdio_unlock
.endfn fwrite,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
getc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call getc
pop %rbp
ret
.endfn getc_unlocked,globl
// Reads character from stream.
//
// @param rdi has file stream object pointer
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
getc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getc,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
getchar_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call getchar
pop %rbp
ret
.endfn getchar_unlocked,globl
// Reads character from stdin.
//
// @return byte in range 0..255, or -1 w/ errno
// @see fgetc_unlocked()
getchar:
lea stdin(%rip),%rdi
mov %rdi,%r11
ezlea fgetc_unlocked,ax
jmp stdio_unlock
.endfn getchar,globl

View file

@ -18,11 +18,12 @@
*/
#include "libc/macros.internal.h"
getwc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fgetwc_unlocked
pop %rbp
ret
.endfn getwc_unlocked,globl
// Reads UTF-8 character from stream.
//
// @param rdi has file stream object pointer
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
getwc: mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getwc,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
getwchar_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call getwchar
pop %rbp
ret
.endfn getwchar_unlocked,globl
// Reads UTF-8 character from stdin.
//
// @return wide character or -1 on EOF or error
// @see fgetwc_unlocked()
getwchar:
lea stdin(%rip),%rdi
mov %rdi,%r11
ezlea fgetwc_unlocked,ax
jmp stdio_unlock
.endfn getwchar,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
putc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call putc
pop %rbp
ret
.endfn putc_unlocked,globl
// Writes character to stream.
//
// @param rdi c is byte to buffer or write, which is masked
// @param rsi has stream object pointer
// @return c as unsigned char if written or -1 w/ errno
// @see fputc_unlocked()
putc: mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn putc,globl

View file

@ -18,11 +18,14 @@
*/
#include "libc/macros.internal.h"
putchar_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call putchar
pop %rbp
ret
.endfn putchar_unlocked,globl
// Writes character to stdout.
//
// @param rdi has character
// @return c (as unsigned char) if written or -1 w/ errno
// @see fputc_unlocked()
putchar:
lea stdout(%rip),%rsi
mov %rsi,%r11
ezlea fputc_unlocked,ax
jmp stdio_unlock
.endfn putchar,globl

View file

@ -18,11 +18,13 @@
*/
#include "libc/macros.internal.h"
putwc_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call fputwc_unlocked
pop %rbp
ret
.endfn putwc_unlocked,globl
// Writes wide character to stream.
//
// @param rdi has wide character
// @param rsi has file object
// @return wc if written or -1 w/ errno
// @see putwc_unlocked()
putwc: mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn putwc,globl

View file

@ -1,4 +1,3 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
@ -19,11 +18,14 @@
*/
#include "libc/macros.internal.h"
putwchar_unlocked:
push %rbp
mov %rsp,%rbp
.profilable # note: no consensus for threads exists in abis
call putwchar
pop %rbp
ret
.endfn putwchar_unlocked,globl
// Writes wide character to stdout.
//
// @param rdi has wide character
// @return wc if written or -1 w/ errno
// @see fputwc_unlocked()
putwchar:
lea stdout(%rip),%rsi
mov %rsi,%r11
ezlea fputwc_unlocked,ax
jmp stdio_unlock
.endfn putwchar,globl

View file

@ -0,0 +1,70 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
#define LOCK 0x2c /* see struct file in stdio.h */
// Wrapper for applying locking to stdio functions.
//
// This function is intended to be called by thunks.
//
// @param rax has the delegate function pointer
// @param rdi is passed along as an arg
// @param rsi is passed along as an arg
// @param rdx is passed along as an arg
// @param rcx is passed along as an arg
// @param r8 is passed along as an arg
// @param r9 is passed along as an arg
// @param r10 is passed along as an arg
// @param r11 has the FILE* obj pointer
// @return rax is passed along as result
// @return rdx is passed along as result
stdio_unlock:
push %rbp
mov %rsp,%rbp
// acquires mutex
push %rcx
push %rdx
mov $1,%cl
0: mov LOCK(%r11),%dl # optimistic
test %dl,%dl
je 2f
1: pause # hyperyield
jmp 0b
2: mov %ecx,%edx
xchg LOCK(%r11),%dl # locks bus!
test %dl,%dl
jne 1b
pop %rdx
pop %rcx
// calls delegate
push %rsi
push %r11
call *%rax
pop %r11
pop %rsi
// releases mutex
movb $0,LOCK(%r11)
pop %rbp
ret
.endfn stdio_unlock,globl

View file

@ -0,0 +1,30 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetc_unlocked()
ungetc: mov %rsi,%r11
ezlea ungetc_unlocked,ax
jmp stdio_unlock
.endfn ungetc,globl

View file

@ -0,0 +1,31 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
// Pushes byte back to stream.
//
// @param rdi has character to push
// @param rds has stream object pointer
// @return rax has rdi on success or -1 w/ errno
// @see ungetwc_unlocked()
ungetwc:
mov %rsi,%r11
ezlea ungetwc_unlocked,ax
jmp stdio_unlock
.endfn ungetwc,globl