Make mappings unlimited on NT

This change might also fix fork() in certain cases on NT.
This commit is contained in:
Justine Tunney 2021-09-04 13:20:47 -07:00
parent ab64c746cc
commit 34b68f1945
31 changed files with 356 additions and 127 deletions

View file

@ -0,0 +1,24 @@
#if 0
/*─────────────────────────────────────────────────────────────────╗
To the extent possible under law, Justine Tunney has waived
all copyright and related or neighboring rights to this file,
as it is written in the following disclaimers:
http://unlicense.org/ │
http://creativecommons.org/publicdomain/zero/1.0/ │
*/
#endif
#include "libc/mem/mem.h"
#include "libc/runtime/gc.h"
#include "libc/stdio/stdio.h"
/**
* Cosmopolitan C is just as awesome as Go!
* Example contributed by @Keithcat1 (#266)
*/
main() {
_defer(printf, "Done!\n");
for (long i = 0; i < 100000; i++) {
printf("%i ", i);
_defer(free, malloc(100)); // longhand for _gc(malloc(100))
}
}

View file

@ -19,6 +19,7 @@
#include "libc/bits/bits.h" #include "libc/bits/bits.h"
#include "libc/bits/pushpop.h" #include "libc/bits/pushpop.h"
#include "libc/bits/safemacros.internal.h" #include "libc/bits/safemacros.internal.h"
#include "libc/calls/calls.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/dns/hoststxt.h" #include "libc/dns/hoststxt.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
@ -70,10 +71,12 @@ const struct HostsTxt *GetHostsTxt(void) {
if (IsWindows()) { if (IsWindows()) {
path = firstnonnull(GetNtHostsTxtPath(pathbuf, ARRAYLEN(pathbuf)), path); path = firstnonnull(GetNtHostsTxtPath(pathbuf, ARRAYLEN(pathbuf)), path);
} }
if (!(f = fopen(path, "r")) || ParseHostsTxt(g_hoststxt, f) == -1) { if (fileexists(path) && (f = fopen(path, "r"))) {
/* TODO(jart): Elevate robustness. */ if (ParseHostsTxt(g_hoststxt, f) == -1) {
/* TODO(jart): Elevate robustness. */
}
fclose(f);
} }
fclose(f);
} }
return g_hoststxt; return g_hoststxt;
} }

View file

@ -30,7 +30,7 @@
#include "libc/nt/enum/version.h" #include "libc/nt/enum/version.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"

View file

@ -27,7 +27,7 @@
#include "libc/log/color.internal.h" #include "libc/log/color.internal.h"
#include "libc/log/internal.h" #include "libc/log/internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h" #include "libc/sysv/consts/auxv.h"

View file

@ -35,7 +35,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nexgen32e/stackframe.h" #include "libc/nexgen32e/stackframe.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/pc.internal.h" #include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"

View file

@ -1,2 +1,12 @@
.include "o/libc/nt/codegen.inc" .include "o/libc/nt/codegen.inc"
.imp kernel32,__imp_GlobalAlloc,GlobalAlloc,0 .imp kernel32,__imp_GlobalAlloc,GlobalAlloc,0
.text.windows
GlobalAlloc:
push %rbp
mov %rsp,%rbp
.profilable
mov __imp_GlobalAlloc(%rip),%rax
jmp __sysv2nt
.endfn GlobalAlloc,globl
.previous

View file

@ -1,2 +1,15 @@
.include "o/libc/nt/codegen.inc" .include "o/libc/nt/codegen.inc"
.imp kernel32,__imp_GlobalFree,GlobalFree,0 .imp kernel32,__imp_GlobalFree,GlobalFree,0
.text.windows
GlobalFree:
push %rbp
mov %rsp,%rbp
.profilable
mov %rdi,%rcx
sub $32,%rsp
call *__imp_GlobalFree(%rip)
leave
ret
.endfn GlobalFree,globl
.previous

View file

@ -2785,14 +2785,14 @@ imp 'GlobalAddAtomA' GlobalAddAtomA kernel32 815
imp 'GlobalAddAtomExA' GlobalAddAtomExA kernel32 816 imp 'GlobalAddAtomExA' GlobalAddAtomExA kernel32 816
imp 'GlobalAddAtomEx' GlobalAddAtomExW kernel32 817 imp 'GlobalAddAtomEx' GlobalAddAtomExW kernel32 817
imp 'GlobalAddAtom' GlobalAddAtomW kernel32 818 imp 'GlobalAddAtom' GlobalAddAtomW kernel32 818
imp 'GlobalAlloc' GlobalAlloc kernel32 0 # KernelBase imp 'GlobalAlloc' GlobalAlloc kernel32 0 2 # KernelBase
imp 'GlobalCompact' GlobalCompact kernel32 820 imp 'GlobalCompact' GlobalCompact kernel32 820
imp 'GlobalDeleteAtom' GlobalDeleteAtom kernel32 821 imp 'GlobalDeleteAtom' GlobalDeleteAtom kernel32 821
imp 'GlobalFindAtomA' GlobalFindAtomA kernel32 822 imp 'GlobalFindAtomA' GlobalFindAtomA kernel32 822
imp 'GlobalFindAtom' GlobalFindAtomW kernel32 823 imp 'GlobalFindAtom' GlobalFindAtomW kernel32 823
imp 'GlobalFix' GlobalFix kernel32 824 imp 'GlobalFix' GlobalFix kernel32 824
imp 'GlobalFlags' GlobalFlags kernel32 825 imp 'GlobalFlags' GlobalFlags kernel32 825
imp 'GlobalFree' GlobalFree kernel32 0 # KernelBase imp 'GlobalFree' GlobalFree kernel32 0 1 # KernelBase
imp 'GlobalGetAtomNameA' GlobalGetAtomNameA kernel32 827 imp 'GlobalGetAtomNameA' GlobalGetAtomNameA kernel32 827
imp 'GlobalGetAtomName' GlobalGetAtomNameW kernel32 828 imp 'GlobalGetAtomName' GlobalGetAtomNameW kernel32 828
imp 'GlobalHandle' GlobalHandle kernel32 829 imp 'GlobalHandle' GlobalHandle kernel32 829

View file

@ -70,6 +70,9 @@ bool32 PrefetchVirtualMemory(int64_t hProcess, const uint32_t *NumberOfEntries,
bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size, bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size,
int Priority); int Priority);
void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) nodiscard;
void *GlobalFree(void *hMem);
#if ShouldUseMsabiAttribute() #if ShouldUseMsabiAttribute()
#include "libc/nt/thunk/memory.inc" #include "libc/nt/thunk/memory.inc"
#endif /* ShouldUseMsabiAttribute() */ #endif /* ShouldUseMsabiAttribute() */

View file

@ -16,7 +16,7 @@
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/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) {

View file

@ -16,7 +16,7 @@
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/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) {
unsigned l, m, r; unsigned l, m, r;

View file

@ -26,6 +26,7 @@
#include "libc/nexgen32e/nt2sysv.h" #include "libc/nexgen32e/nt2sysv.h"
#include "libc/nt/dll.h" #include "libc/nt/dll.h"
#include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/memflags.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
#include "libc/nt/enum/startf.h" #include "libc/nt/enum/startf.h"
#include "libc/nt/enum/wt.h" #include "libc/nt/enum/wt.h"
@ -37,7 +38,7 @@
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
@ -46,6 +47,51 @@
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static textwindows noasan void NtDebug(const char *fmt, ...) {
return;
int i;
va_list va;
uint32_t w, u;
const char *s;
unsigned long d;
char c, b[256], *p;
va_start(va, fmt);
for (p = b;;) {
switch ((c = *fmt++)) {
case '\0':
va_end(va);
WriteFile(GetStdHandle(kNtStdErrorHandle), b, p - b, &w, 0);
return;
case '%':
switch ((c = *fmt++)) {
case 's':
for (s = va_arg(va, const char *); s && *s;) *p++ = *s++;
break;
case 'd':
d = va_arg(va, unsigned long);
for (i = 16; i--;) {
u = (d >> (i * 4)) & 0xf;
if (u < 10) {
c = '0' + u;
} else {
u -= 10;
c = 'a' + u;
}
*p++ = c;
}
break;
default:
*p++ = c;
break;
}
break;
default:
*p++ = c;
break;
}
}
}
static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
*x = 0; *x = 0;
while (*p == ' ') p++; while (*p == ' ') p++;
@ -56,33 +102,42 @@ static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) {
return p; return p;
} }
static noinline textwindows noasan void ForkIo(int64_t h, void *buf, size_t n, static noinline textwindows noasan bool ForkIo(int64_t h, void *buf, size_t n,
bool32 (*f)()) { bool32 (*f)()) {
char *p; char *p;
size_t i; size_t i;
uint32_t x; uint32_t x;
for (p = buf, i = 0; i < n; i += x) { for (p = buf, i = 0; i < n; i += x) {
f(h, p + i, n - i, &x, NULL); if (!f(h, p + i, n - i, &x, NULL)) {
return false;
}
} }
return true;
} }
static noinline textwindows noasan void WriteAll(int64_t h, void *buf, static noinline textwindows noasan void WriteAll(int64_t h, void *buf,
size_t n) { size_t n) {
ForkIo(h, buf, n, WriteFile); if (!ForkIo(h, buf, n, WriteFile)) {
NtDebug("fork() WriteFile(%zu) failed %d\n", n, GetLastError());
}
} }
static textwindows noinline noasan void ReadAll(int64_t h, void *buf, static textwindows noinline noasan void ReadAll(int64_t h, void *buf,
size_t n) { size_t n) {
ForkIo(h, buf, n, ReadFile); if (!ForkIo(h, buf, n, ReadFile)) {
NtDebug("fork() ReadFile(%zu) failed %d\n", n, GetLastError());
}
} }
textwindows noasan void WinMainForked(void) { textwindows noasan void WinMainForked(void) {
void *addr; void *addr;
jmp_buf jb; jmp_buf jb;
long mapcount;
uint64_t size; uint64_t size;
uint32_t i, varlen; uint32_t i, varlen;
struct DirectMap dm; struct DirectMap dm;
int64_t reader, writer; int64_t reader, writer;
struct MemoryInterval *maps;
char16_t var[21 + 1 + 21 + 1]; char16_t var[21 + 1 + 21 + 1];
varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var));
if (!varlen) return; if (!varlen) return;
@ -90,29 +145,33 @@ textwindows noasan void WinMainForked(void) {
SetEnvironmentVariable(u"_FORK", NULL); SetEnvironmentVariable(u"_FORK", NULL);
ParseInt(ParseInt(var, &reader), &writer); ParseInt(ParseInt(var, &reader), &writer);
ReadAll(reader, jb, sizeof(jb)); ReadAll(reader, jb, sizeof(jb));
ReadAll(reader, &_mmi.i, sizeof(_mmi.i)); ReadAll(reader, &mapcount, sizeof(_mmi.i));
for (i = 0; i < _mmi.i; ++i) { maps = GlobalAlloc(0, mapcount * sizeof(*_mmi.p));
ReadAll(reader, &_mmi.p[i], sizeof(_mmi.p[i])); ReadAll(reader, maps, mapcount * sizeof(*_mmi.p));
addr = (void *)((uint64_t)_mmi.p[i].x << 16); for (i = 0; i < mapcount; ++i) {
size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE; addr = (void *)((uint64_t)maps[i].x << 16);
if (_mmi.p[i].flags & MAP_PRIVATE) { size = ((uint64_t)(maps[i].y - maps[i].x) << 16) + FRAMESIZE;
CloseHandle(_mmi.p[i].h); if (maps[i].flags & MAP_PRIVATE) {
_mmi.p[i].h = CloseHandle(maps[i].h);
sys_mmap_nt(addr, size, _mmi.p[i].prot, _mmi.p[i].flags, -1, 0) maps[i].h =
.maphandle; sys_mmap_nt(addr, size, maps[i].prot, maps[i].flags, -1, 0).maphandle;
ReadAll(reader, addr, size); ReadAll(reader, addr, size);
} else { } else {
MapViewOfFileExNuma( MapViewOfFileExNuma(
_mmi.p[i].h, maps[i].h,
(_mmi.p[i].prot & PROT_WRITE) (maps[i].prot & PROT_WRITE)
? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead ? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead
: kNtFileMapExecute | kNtFileMapRead, : kNtFileMapExecute | kNtFileMapRead,
0, 0, size, addr, kNtNumaNoPreferredNode); 0, 0, size, addr, kNtNumaNoPreferredNode);
} }
} }
ReadAll(reader, _edata, _end - _edata); ReadAll(reader, _etext, _end - _etext);
for (i = 0; i < mapcount; ++i) {
_mmi.p[i].h = maps[i].h;
}
CloseHandle(reader); CloseHandle(reader);
CloseHandle(writer); CloseHandle(writer);
GlobalFree(maps);
if (weaken(__wincrash_nt)) { if (weaken(__wincrash_nt)) {
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt)); AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
} }
@ -156,14 +215,14 @@ textwindows int sys_fork_nt(void) {
} }
WriteAll(writer, jb, sizeof(jb)); WriteAll(writer, jb, sizeof(jb));
WriteAll(writer, &_mmi.i, sizeof(_mmi.i)); WriteAll(writer, &_mmi.i, sizeof(_mmi.i));
WriteAll(writer, _mmi.p, _mmi.i * sizeof(*_mmi.p));
for (i = 0; i < _mmi.i; ++i) { for (i = 0; i < _mmi.i; ++i) {
WriteAll(writer, &_mmi.p[i], sizeof(_mmi.p[i]));
if (_mmi.p[i].flags & MAP_PRIVATE) { if (_mmi.p[i].flags & MAP_PRIVATE) {
WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE); ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE);
} }
} }
WriteAll(writer, _edata, _end - _edata); WriteAll(writer, _etext, _end - _etext);
CloseHandle(writer); CloseHandle(writer);
} else { } else {
rc = -1; rc = -1;

View file

@ -17,7 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
/** /**

View file

@ -17,9 +17,12 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/bits/bits.h"
#include "libc/bits/weaken.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/mem/mem.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -167,18 +170,38 @@ static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i,
mm->i -= n; mm->i -= n;
} }
static noasan void CreateMemoryInterval(struct MemoryIntervals *mm, int i) { static noasan int CreateMemoryInterval(struct MemoryIntervals *mm, int i) {
int rc;
void *p;
size_t n;
static bool noreentry;
rc = 0;
assert(i >= 0); assert(i >= 0);
assert(i <= mm->i); assert(i <= mm->i);
assert(mm->i < ARRAYLEN(mm->p)); assert(mm->i < mm->n);
MoveMemoryNoAsan(mm->p + i + 1, mm->p + i, MoveMemoryNoAsan(mm->p + i + 1, mm->p + i,
(intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i)); (intptr_t)(mm->p + mm->i) - (intptr_t)(mm->p + i));
++mm->i; if (++mm->i > (mm->n >> 1) && cmpxchg(&noreentry, false, true)) {
n = mm->n << 1;
p = weaken(malloc) ? weaken(malloc)(n * sizeof(*mm->p)) : 0;
if (p) {
memcpy(p, mm->p, mm->i * sizeof(*mm->p));
if (mm->p != mm->s && weaken(free)) {
weaken(free)(mm->p);
}
mm->p = p;
mm->n = n;
} else {
rc = enomem();
}
noreentry = false;
}
return 0;
} }
static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) { static noasan int PunchHole(struct MemoryIntervals *mm, int x, int y, int i) {
if (mm->i == ARRAYLEN(mm->p)) return enomem(); if (mm->i == mm->n) return enomem();
CreateMemoryInterval(mm, i); if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].y = x - 1; mm->p[i].y = x - 1;
mm->p[i + 1].x = y + 1; mm->p[i + 1].x = y + 1;
return 0; return 0;
@ -242,8 +265,8 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
prot == mm->p[i].prot && flags == mm->p[i].flags) { prot == mm->p[i].prot && flags == mm->p[i].flags) {
mm->p[i].x = x; mm->p[i].x = x;
} else { } else {
if (mm->i == ARRAYLEN(mm->p)) return enomem(); if (mm->i == mm->n) return enomem();
CreateMemoryInterval(mm, i); if (CreateMemoryInterval(mm, i) == -1) return -1;
mm->p[i].x = x; mm->p[i].x = x;
mm->p[i].y = y; mm->p[i].y = y;
mm->p[i].h = h; mm->p[i].h = h;

View file

@ -21,15 +21,18 @@ COSMOPOLITAN_C_START_
#define kAutomapSize MEMTRACK_ADDRESS(_kAutomapSize, 0x40000000) #define kAutomapSize MEMTRACK_ADDRESS(_kAutomapSize, 0x40000000)
#define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x40000000) #define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x40000000)
struct MemoryInterval {
int x;
int y;
long h;
int prot;
int flags;
};
struct MemoryIntervals { struct MemoryIntervals {
long i; long i, n;
struct MemoryInterval { struct MemoryInterval *p;
int x; struct MemoryInterval s[OPEN_MAX];
int y;
long h;
int prot;
int flags;
} p[128];
}; };
extern hidden struct MemoryIntervals _mmi; extern hidden struct MemoryIntervals _mmi;

View file

@ -19,7 +19,7 @@
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
static noasan void *GetFrameAddr(int f) { static noasan void *GetFrameAddr(int f) {

View file

@ -26,7 +26,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"

View file

@ -16,6 +16,8 @@
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/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
STATIC_YOINK("_init__mmi");
struct MemoryIntervals _mmi; struct MemoryIntervals _mmi;

24
libc/runtime/mmi.init.S Normal file
View file

@ -0,0 +1,24 @@
/*-*- 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 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/macros.internal.h"
.init.start 200,_init__mmi
movb $OPEN_MAX,_mmi+8
movl $_mmi+24,_mmi+16
.init.end 200,_init__mmi

View file

@ -20,7 +20,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
textwindows int sys_msync_nt(void *addr, size_t size, int flags) { textwindows int sys_msync_nt(void *addr, size_t size, int flags) {
int x, y, l, r, i; int x, y, l, r, i;

View file

@ -20,7 +20,7 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) { void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
int i, frames, maptally, gaptally; int i, frames, maptally, gaptally;

View file

@ -18,7 +18,7 @@
*/ */
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
int UntrackMemoryIntervals(void *addr, size_t size) { int UntrackMemoryIntervals(void *addr, size_t size) {
int a, b; int a, b;

View file

@ -38,7 +38,7 @@
#include "libc/nt/struct/teb.h" #include "libc/nt/struct/teb.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
@ -108,6 +108,8 @@ static noasan textwindows wontreturn void WinMainNew(void) {
kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput | kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput |
kNtEnableVirtualTerminalProcessing); kNtEnableVirtualTerminalProcessing);
} }
_mmi.p = _mmi.s;
_mmi.n = OPEN_MAX;
addr = version < 10 ? 0xff00000 : 0x777000000000; addr = version < 10 ? 0xff00000 : 0x777000000000;
size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE); size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE);
MapViewOfFileExNuma((_mmi.p[0].h = CreateFileMappingNuma( MapViewOfFileExNuma((_mmi.p[0].h = CreateFileMappingNuma(

View file

@ -357,10 +357,10 @@ _init_systemfive_stack: # determinism ftw!
shr $16,%r11 # for the stack range shr $16,%r11 # for the stack range
shr $16,%r9 shr $16,%r9
movb $1,(%rcx) # _mmi.i movb $1,(%rcx) # _mmi.i
mov %r11d,8(%rcx) # _mmi.p[0].x mov %r11d,24(%rcx) # _mmi.s[0].x
mov %r9d,12(%rcx) # _mmi.p[0].y mov %r9d,28(%rcx) # _mmi.s[0].y
mov %edx,20(%rcx) # _mmi.p[0].prot mov %edx,36(%rcx) # _mmi.s[0].prot
mov %r10d,24(%rcx) # _mmi.p[0].flags mov %r10d,40(%rcx) # _mmi.s[0].flags
3: pop %r9 # restore stack size 3: pop %r9 # restore stack size
pop %rsi pop %rsi
pop %rdi pop %rdi

View file

@ -23,7 +23,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.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"

View file

@ -23,6 +23,7 @@
#include "libc/runtime/runtime.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/testlib/ezbench.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/x/x.h" #include "libc/x/x.h"
@ -73,3 +74,22 @@ TEST(gclongjmp, test) {
free(y); free(y);
free(x); free(x);
} }
void F1(void) {
/* 3x slower than F2() but sooo worth it */
_gc(malloc(16));
}
void F2(void) {
void *volatile p;
p = malloc(16);
free(p);
}
void (*F1p)(void) = F1;
void (*F2p)(void) = F2;
BENCH(gc, bench) {
EZBENCH2("gc(malloc(16))", donothing, F1p());
EZBENCH2("free(malloc(16))", donothing, F2p());
}

View file

@ -20,7 +20,7 @@
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.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"
@ -86,10 +86,12 @@ static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2],
} }
TEST(TrackMemoryInterval, TestEmpty) { TEST(TrackMemoryInterval, TestEmpty) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{0, {}}, {0, OPEN_MAX, 0, {}},
{1, {{2, 2, 0}}}, {1, OPEN_MAX, 0, {{2, 2, 0}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 2, 2, 0); RunTrackMemoryIntervalTest(mm, 2, 2, 0);
} }
@ -97,7 +99,7 @@ TEST(TrackMemoryInterval, TestFull) {
int i; int i;
struct MemoryIntervals *mm; struct MemoryIntervals *mm;
mm = calloc(1, sizeof(struct MemoryIntervals)); mm = calloc(1, sizeof(struct MemoryIntervals));
for (i = 0; i < ARRAYLEN(mm->p); ++i) { for (i = 0; i < mm->n; ++i) {
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0));
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
@ -109,57 +111,71 @@ TEST(TrackMemoryInterval, TestFull) {
} }
TEST(TrackMemoryInterval, TestAppend) { TEST(TrackMemoryInterval, TestAppend) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{2, 2}}}, {1, OPEN_MAX, 0, {{2, 2}}},
{1, {{2, 3}}}, {1, OPEN_MAX, 0, {{2, 3}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 3, 3, 0); RunTrackMemoryIntervalTest(mm, 3, 3, 0);
} }
TEST(TrackMemoryInterval, TestPrepend) { TEST(TrackMemoryInterval, TestPrepend) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{2, 2}}}, {1, OPEN_MAX, 0, {{2, 2}}},
{1, {{1, 2}}}, {1, OPEN_MAX, 0, {{1, 2}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 1, 1, 0); RunTrackMemoryIntervalTest(mm, 1, 1, 0);
} }
TEST(TrackMemoryInterval, TestFillHole) { TEST(TrackMemoryInterval, TestFillHole) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{4, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}},
{3, {{1, 4}, {5, 5, 1}, {6, 8}}}, {3, OPEN_MAX, 0, {{1, 4}, {5, 5, 1}, {6, 8}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 2, 2, 0); RunTrackMemoryIntervalTest(mm, 2, 2, 0);
} }
TEST(TrackMemoryInterval, TestAppend2) { TEST(TrackMemoryInterval, TestAppend2) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{2, 2}}}, {1, OPEN_MAX, 0, {{2, 2}}},
{2, {{2, 2}, {3, 3, 1}}}, {2, OPEN_MAX, 0, {{2, 2}, {3, 3, 1}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 3, 3, 1); RunTrackMemoryIntervalTest(mm, 3, 3, 1);
} }
TEST(TrackMemoryInterval, TestPrepend2) { TEST(TrackMemoryInterval, TestPrepend2) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{2, 2}}}, {1, OPEN_MAX, 0, {{2, 2}}},
{2, {{1, 1, 1}, {2, 2}}}, {2, OPEN_MAX, 0, {{1, 1, 1}, {2, 2}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 1, 1, 1); RunTrackMemoryIntervalTest(mm, 1, 1, 1);
} }
TEST(TrackMemoryInterval, TestFillHole2) { TEST(TrackMemoryInterval, TestFillHole2) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{4, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, {4, OPEN_MAX, 0, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}},
{5, {{1, 1}, {2, 2, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, {5, OPEN_MAX, 0, {{1, 1}, {2, 2, 1}, {3, 4}, {5, 5, 1}, {6, 8}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
RunTrackMemoryIntervalTest(mm, 2, 2, 1); RunTrackMemoryIntervalTest(mm, 2, 2, 1);
} }
TEST(FindMemoryInterval, Test) { TEST(FindMemoryInterval, Test) {
static const struct MemoryIntervals mm[1] = { static struct MemoryIntervals mm[1] = {
{ {
4, 4,
OPEN_MAX,
0,
{ {
[0] = {1, 1}, [0] = {1, 1},
[1] = {3, 4}, [1] = {3, 4},
@ -168,6 +184,7 @@ TEST(FindMemoryInterval, Test) {
}, },
}, },
}; };
mm[0].p = mm[0].s;
EXPECT_EQ(0, FindMemoryInterval(mm, 0)); EXPECT_EQ(0, FindMemoryInterval(mm, 0));
EXPECT_EQ(0, FindMemoryInterval(mm, 1)); EXPECT_EQ(0, FindMemoryInterval(mm, 1));
EXPECT_EQ(1, FindMemoryInterval(mm, 2)); EXPECT_EQ(1, FindMemoryInterval(mm, 2));
@ -181,115 +198,141 @@ TEST(FindMemoryInterval, Test) {
} }
TEST(ReleaseMemoryIntervals, TestEmpty) { TEST(ReleaseMemoryIntervals, TestEmpty) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{0, {}}, {0, OPEN_MAX, 0, {}},
{0, {}}, {0, OPEN_MAX, 0, {}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2));
} }
TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{3, {{0, 0}, {2, 2}, {4, 4}}}, {3, OPEN_MAX, 0, {{0, 0}, {2, 2}, {4, 4}}},
{2, {{0, 0}, {4, 4}}}, {2, OPEN_MAX, 0, {{0, 0}, {4, 4}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2));
} }
TEST(ReleaseMemoryIntervals, TestPunchHole) { TEST(ReleaseMemoryIntervals, TestPunchHole) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{0, 9}}}, {1, OPEN_MAX, 0, {{0, 9}}},
{2, {{0, 3}, {6, 9}}}, {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 4, 5)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 4, 5));
} }
TEST(ReleaseMemoryIntervals, TestShortenLeft) { TEST(ReleaseMemoryIntervals, TestShortenLeft) {
if (IsWindows()) return; if (IsWindows()) return;
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{0, 9}}}, {1, OPEN_MAX, 0, {{0, 9}}},
{1, {{0, 7}}}, {1, OPEN_MAX, 0, {{0, 7}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 9)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 9));
} }
TEST(ReleaseMemoryIntervals, TestShortenRight) { TEST(ReleaseMemoryIntervals, TestShortenRight) {
if (IsWindows()) return; if (IsWindows()) return;
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{0, 9}}}, {1, OPEN_MAX, 0, {{0, 9}}},
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 2)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 2));
} }
TEST(ReleaseMemoryIntervals, TestShortenLeft2) { TEST(ReleaseMemoryIntervals, TestShortenLeft2) {
if (IsWindows()) return; if (IsWindows()) return;
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{0, 9}}}, {1, OPEN_MAX, 0, {{0, 9}}},
{1, {{0, 7}}}, {1, OPEN_MAX, 0, {{0, 7}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 11)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 8, 11));
} }
TEST(ReleaseMemoryIntervals, TestShortenRight2) { TEST(ReleaseMemoryIntervals, TestShortenRight2) {
if (IsWindows()) return; if (IsWindows()) return;
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{0, 9}}}, {1, OPEN_MAX, 0, {{0, 9}}},
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, -3, 2)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, -3, 2));
} }
TEST(ReleaseMemoryIntervals, TestZeroZero) { TEST(ReleaseMemoryIntervals, TestZeroZero) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 0)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 0, 0));
} }
TEST(ReleaseMemoryIntervals, TestNoopLeft) { TEST(ReleaseMemoryIntervals, TestNoopLeft) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 1, 2)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 1, 2));
} }
TEST(ReleaseMemoryIntervals, TestNoopRight) { TEST(ReleaseMemoryIntervals, TestNoopRight) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
{1, {{3, 9}}}, {1, OPEN_MAX, 0, {{3, 9}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 10, 10)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 10, 10));
} }
TEST(ReleaseMemoryIntervals, TestBigFree) { TEST(ReleaseMemoryIntervals, TestBigFree) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{2, {{0, 3}, {6, 9}}}, {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}},
{0, {}}, {0, OPEN_MAX, 0, {}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, INT_MIN, INT_MAX)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, INT_MIN, INT_MAX));
} }
TEST(ReleaseMemoryIntervals, TestWeirdGap) { TEST(ReleaseMemoryIntervals, TestWeirdGap) {
static const struct MemoryIntervals mm[2] = { static struct MemoryIntervals mm[2] = {
{3, {{10, 10}, {20, 20}, {30, 30}}}, {3, OPEN_MAX, 0, {{10, 10}, {20, 20}, {30, 30}}},
{2, {{10, 10}, {30, 30}}}, {2, OPEN_MAX, 0, {{10, 10}, {30, 30}}},
}; };
mm[0].p = mm[0].s;
mm[1].p = mm[1].s;
EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 15, 25)); EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 15, 25));
} }
TEST(ReleaseMemoryIntervals, TestOutOfMemory) { TEST(ReleaseMemoryIntervals, TestOutOfMemory_AllocatesMore) {
int i; int i;
struct MemoryIntervals *mm; struct MemoryIntervals *mm;
mm = calloc(1, sizeof(struct MemoryIntervals)); mm = calloc(1, sizeof(struct MemoryIntervals));
for (i = 0; i < ARRAYLEN(mm->p); ++i) { mm->n = OPEN_MAX;
mm->p = mm->s;
for (i = 0; i < OPEN_MAX * 2; ++i) {
CHECK_NE(-1, TrackMemoryInterval(mm, i * 10, i * 10 + 8, 0, 0, 0)); CHECK_NE(-1, TrackMemoryInterval(mm, i * 10, i * 10 + 8, 0, 0, 0));
} }
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
CHECK_EQ(-1, ReleaseMemoryIntervals(mm, 4, 4, NULL)); CHECK_EQ(0, ReleaseMemoryIntervals(mm, 4, 4, NULL));
CHECK_EQ(ENOMEM, errno);
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
free(mm->p);
free(mm); free(mm);
} }

View file

@ -23,7 +23,7 @@
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.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"

View file

@ -24,7 +24,7 @@
#include "libc/mem/fmt.h" #include "libc/mem/fmt.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/memtrack.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/mremap.h" #include "libc/sysv/consts/mremap.h"

View file

@ -388,7 +388,7 @@ int RunOnHost(char *spec) {
do { do {
Connect(); Connect();
EzFd(g_sock); EzFd(g_sock);
EzHandshake(); EzHandshake(); /* TODO(jart): Backoff on MBEDTLS_ERR_NET_CONN_RESET */
SendRequest(); SendRequest();
} while ((rc = ReadResponse()) == -1); } while ((rc = ReadResponse()) == -1);
return rc; return rc;