Add shared memory apis to redbean

You can now do things like implement mutexes using futexes in your
redbean lua code. This provides the fastest possible inter-process
communication for your production systems when SQLite alone as ipc
or things like pipes aren't sufficient.
This commit is contained in:
Justine Tunney 2022-10-06 04:55:26 -07:00
parent 81ee11a16e
commit 7822917fc2
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
21 changed files with 988 additions and 23 deletions

View file

@ -49,7 +49,7 @@ int __ensurefds_unlocked(int fd) {
bool relocate;
if (fd < g_fds.n) return fd;
g_fds.n = fd + 1;
g_fds.e = _extend(g_fds.p, g_fds.n * sizeof(*g_fds.p), g_fds.e,
g_fds.e = _extend(g_fds.p, g_fds.n * sizeof(*g_fds.p), g_fds.e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize);
return fd;
}

View file

@ -29,11 +29,11 @@
#define G FRAMESIZE
static void _mapframe(void *p) {
static void _mapframe(void *p, int f) {
int prot, flags;
struct DirectMap dm;
prot = PROT_READ | PROT_WRITE;
flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
flags = f | MAP_ANONYMOUS | MAP_FIXED;
if ((dm = sys_mmap(p, G, prot, flags, -1, 0)).addr != p) {
notpossible;
}
@ -60,9 +60,10 @@ static void _mapframe(void *p) {
* @param n specifies how many bytes are needed
* @param e points to end of memory that's allocated
* @param h is highest address to which `e` may grow
* @param f should be `MAP_PRIVATE` or `MAP_SHARED`
* @return new value for `e`
*/
noasan void *_extend(void *p, size_t n, void *e, intptr_t h) {
noasan void *_extend(void *p, size_t n, void *e, int f, intptr_t h) {
char *q;
#ifndef NDEBUG
if ((uintptr_t)SHADOW(p) & (G - 1)) notpossible;
@ -71,10 +72,10 @@ noasan void *_extend(void *p, size_t n, void *e, intptr_t h) {
for (q = e; q < ((char *)p + n); q += 8) {
if (!((uintptr_t)q & (G - 1))) {
if (q + G > (char *)h) notpossible;
_mapframe(q);
_mapframe(q, f);
if (IsAsan()) {
if (!((uintptr_t)SHADOW(q) & (G - 1))) {
_mapframe(SHADOW(q));
_mapframe(SHADOW(q), f);
__asan_poison(q, G << kAsanScale, kAsanProtected);
}
}

View file

@ -3,7 +3,7 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
void *_extend(void *, size_t, void *, intptr_t);
void *_extend(void *, size_t, void *, int, intptr_t);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -23,6 +23,7 @@
#include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/thread/thread.h"
@ -47,7 +48,7 @@ textstartup void InitializeFileDescriptors(void) {
fds->p = fds->e = (void *)kMemtrackFdsStart;
fds->n = 4;
fds->f = 3;
fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e,
fds->e = _extend(fds->p, fds->n * sizeof(*fds->p), fds->e, MAP_PRIVATE,
kMemtrackFdsStart + kMemtrackFdsSize);
if (IsMetal()) {
extern const char vga_console[];

View file

@ -21,7 +21,7 @@
#include "libc/macros.internal.h"
.privileged
// Asks kernel to let other threads be scheduled.
// Relinquishes scheduled quantum.
//
// @return 0 on success, or -1 w/ errno
// @norestart

31
libc/intrin/sys_umtx_op.S Normal file
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"
.privileged
// Calls FreeBSD's futex() API.
// Normalizes return value to Linux ABI -errno convention.
sys_umtx_op:
mov $0x1c6,%eax
syscall
jc 1f
ret
1: neg %eax
ret
.endfn sys_umtx_op,globl,hidden

View file

@ -1,2 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_clock_nanosleep,0x1ddfff0f4ffff0e6,globl
.scall sys_clock_nanosleep,0x1ddfff0f4ffff0e6,globl,hidden

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_umtx_op,0xffffff1c6fffffff,globl

View file

@ -642,7 +642,7 @@ scall sys_bsdthread_register 0xfffffffff216efff globl hidden
#scall write_nocancel 0xfffffffff218dfff globl
#scall writev_nocancel 0xfffffffff219cfff globl
#──────────────────────────FREEBSD───────────────────────────
scall sys_umtx_op 0xffffff1c6fffffff globl
#scall sys_umtx_op 0xffffff1c6fffffff globl
#scall abort2 0xffffff1cffffffff globl
#scall afs3_syscall 0xffffff179fffffff globl
#scall bindat 0xffffff21afffffff globl

View file

@ -54,7 +54,7 @@ static void *__zipos_mmap(size_t mapsize) {
maptotal += mapsize;
start = (char *)kMemtrackZiposStart;
if (!mapend) mapend = start;
mapend = _extend(start, maptotal, mapend,
mapend = _extend(start, maptotal, mapend, MAP_PRIVATE,
kMemtrackZiposStart + kMemtrackZiposSize);
return start + offset;
}