diff --git a/examples/defer-statements.c b/examples/defer-statements.c new file mode 100644 index 000000000..e2a7b2852 --- /dev/null +++ b/examples/defer-statements.c @@ -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)) + } +} diff --git a/libc/dns/gethoststxt.c b/libc/dns/gethoststxt.c index d7a3603b9..1fed2f92e 100644 --- a/libc/dns/gethoststxt.c +++ b/libc/dns/gethoststxt.c @@ -19,6 +19,7 @@ #include "libc/bits/bits.h" #include "libc/bits/pushpop.h" #include "libc/bits/safemacros.internal.h" +#include "libc/calls/calls.h" #include "libc/dce.h" #include "libc/dns/hoststxt.h" #include "libc/fmt/fmt.h" @@ -70,10 +71,12 @@ const struct HostsTxt *GetHostsTxt(void) { if (IsWindows()) { path = firstnonnull(GetNtHostsTxtPath(pathbuf, ARRAYLEN(pathbuf)), path); } - if (!(f = fopen(path, "r")) || ParseHostsTxt(g_hoststxt, f) == -1) { - /* TODO(jart): Elevate robustness. */ + if (fileexists(path) && (f = fopen(path, "r"))) { + if (ParseHostsTxt(g_hoststxt, f) == -1) { + /* TODO(jart): Elevate robustness. */ + } + fclose(f); } - fclose(f); } return g_hoststxt; } diff --git a/libc/intrin/asan.c b/libc/intrin/asan.c index 0b2ee1d04..7d836e71e 100644 --- a/libc/intrin/asan.c +++ b/libc/intrin/asan.c @@ -30,7 +30,7 @@ #include "libc/nt/enum/version.h" #include "libc/nt/runtime.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/sysv/consts/auxv.h" #include "libc/sysv/consts/map.h" diff --git a/libc/log/checkfail.c b/libc/log/checkfail.c index 0ea0dd770..2ed387673 100644 --- a/libc/log/checkfail.c +++ b/libc/log/checkfail.c @@ -27,7 +27,7 @@ #include "libc/log/color.internal.h" #include "libc/log/internal.h" #include "libc/log/log.h" -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" diff --git a/libc/log/oncrash.c b/libc/log/oncrash.c index 3336c0c33..592586e32 100644 --- a/libc/log/oncrash.c +++ b/libc/log/oncrash.c @@ -35,7 +35,7 @@ #include "libc/macros.internal.h" #include "libc/nexgen32e/stackframe.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/runtime.h" #include "libc/str/str.h" diff --git a/libc/nt/kernel32/GlobalAlloc.s b/libc/nt/kernel32/GlobalAlloc.s index cdbdfad34..9333459f1 100644 --- a/libc/nt/kernel32/GlobalAlloc.s +++ b/libc/nt/kernel32/GlobalAlloc.s @@ -1,2 +1,12 @@ .include "o/libc/nt/codegen.inc" .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 diff --git a/libc/nt/kernel32/GlobalFree.s b/libc/nt/kernel32/GlobalFree.s index 6cea22339..ef35d98f4 100644 --- a/libc/nt/kernel32/GlobalFree.s +++ b/libc/nt/kernel32/GlobalFree.s @@ -1,2 +1,15 @@ .include "o/libc/nt/codegen.inc" .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 diff --git a/libc/nt/master.sh b/libc/nt/master.sh index 85f8f5e56..99a6fe8cf 100755 --- a/libc/nt/master.sh +++ b/libc/nt/master.sh @@ -2785,14 +2785,14 @@ imp 'GlobalAddAtomA' GlobalAddAtomA kernel32 815 imp 'GlobalAddAtomExA' GlobalAddAtomExA kernel32 816 imp 'GlobalAddAtomEx' GlobalAddAtomExW kernel32 817 imp 'GlobalAddAtom' GlobalAddAtomW kernel32 818 -imp 'GlobalAlloc' GlobalAlloc kernel32 0 # KernelBase +imp 'GlobalAlloc' GlobalAlloc kernel32 0 2 # KernelBase imp 'GlobalCompact' GlobalCompact kernel32 820 imp 'GlobalDeleteAtom' GlobalDeleteAtom kernel32 821 imp 'GlobalFindAtomA' GlobalFindAtomA kernel32 822 imp 'GlobalFindAtom' GlobalFindAtomW kernel32 823 imp 'GlobalFix' GlobalFix kernel32 824 imp 'GlobalFlags' GlobalFlags kernel32 825 -imp 'GlobalFree' GlobalFree kernel32 0 # KernelBase +imp 'GlobalFree' GlobalFree kernel32 0 1 # KernelBase imp 'GlobalGetAtomNameA' GlobalGetAtomNameA kernel32 827 imp 'GlobalGetAtomName' GlobalGetAtomNameW kernel32 828 imp 'GlobalHandle' GlobalHandle kernel32 829 diff --git a/libc/nt/memory.h b/libc/nt/memory.h index 07b51842d..c729f9726 100644 --- a/libc/nt/memory.h +++ b/libc/nt/memory.h @@ -70,6 +70,9 @@ bool32 PrefetchVirtualMemory(int64_t hProcess, const uint32_t *NumberOfEntries, bool32 OfferVirtualMemory(void *inout_VirtualAddress, size_t Size, int Priority); +void *GlobalAlloc(uint32_t uFlags, uint64_t dwBytes) nodiscard; +void *GlobalFree(void *hMem); + #if ShouldUseMsabiAttribute() #include "libc/nt/thunk/memory.inc" #endif /* ShouldUseMsabiAttribute() */ diff --git a/libc/runtime/arememoryintervalsok.c b/libc/runtime/arememoryintervalsok.c index 66943a1ff..85af56bba 100644 --- a/libc/runtime/arememoryintervalsok.c +++ b/libc/runtime/arememoryintervalsok.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" noasan bool AreMemoryIntervalsOk(const struct MemoryIntervals *mm) { diff --git a/libc/runtime/findmemoryinterval.c b/libc/runtime/findmemoryinterval.c index 7e37d39f0..d6119d80f 100644 --- a/libc/runtime/findmemoryinterval.c +++ b/libc/runtime/findmemoryinterval.c @@ -16,7 +16,7 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" noasan unsigned FindMemoryInterval(const struct MemoryIntervals *mm, int x) { unsigned l, m, r; diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index 35ba46248..21dde5b91 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -26,6 +26,7 @@ #include "libc/nexgen32e/nt2sysv.h" #include "libc/nt/dll.h" #include "libc/nt/enum/filemapflags.h" +#include "libc/nt/enum/memflags.h" #include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/startf.h" #include "libc/nt/enum/wt.h" @@ -37,7 +38,7 @@ #include "libc/nt/synchronization.h" #include "libc/nt/thread.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/str/str.h" #include "libc/sysv/consts/map.h" @@ -46,6 +47,51 @@ #include "libc/sysv/consts/sig.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) { *x = 0; while (*p == ' ') p++; @@ -56,33 +102,42 @@ static textwindows noasan char16_t *ParseInt(char16_t *p, int64_t *x) { 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)()) { char *p; size_t i; uint32_t 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, 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, 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) { void *addr; jmp_buf jb; + long mapcount; uint64_t size; uint32_t i, varlen; struct DirectMap dm; int64_t reader, writer; + struct MemoryInterval *maps; char16_t var[21 + 1 + 21 + 1]; varlen = GetEnvironmentVariable(u"_FORK", var, ARRAYLEN(var)); if (!varlen) return; @@ -90,29 +145,33 @@ textwindows noasan void WinMainForked(void) { SetEnvironmentVariable(u"_FORK", NULL); ParseInt(ParseInt(var, &reader), &writer); ReadAll(reader, jb, sizeof(jb)); - ReadAll(reader, &_mmi.i, sizeof(_mmi.i)); - for (i = 0; i < _mmi.i; ++i) { - ReadAll(reader, &_mmi.p[i], sizeof(_mmi.p[i])); - addr = (void *)((uint64_t)_mmi.p[i].x << 16); - size = ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE; - if (_mmi.p[i].flags & MAP_PRIVATE) { - CloseHandle(_mmi.p[i].h); - _mmi.p[i].h = - sys_mmap_nt(addr, size, _mmi.p[i].prot, _mmi.p[i].flags, -1, 0) - .maphandle; + ReadAll(reader, &mapcount, sizeof(_mmi.i)); + maps = GlobalAlloc(0, mapcount * sizeof(*_mmi.p)); + ReadAll(reader, maps, mapcount * sizeof(*_mmi.p)); + for (i = 0; i < mapcount; ++i) { + addr = (void *)((uint64_t)maps[i].x << 16); + size = ((uint64_t)(maps[i].y - maps[i].x) << 16) + FRAMESIZE; + if (maps[i].flags & MAP_PRIVATE) { + CloseHandle(maps[i].h); + maps[i].h = + sys_mmap_nt(addr, size, maps[i].prot, maps[i].flags, -1, 0).maphandle; ReadAll(reader, addr, size); } else { MapViewOfFileExNuma( - _mmi.p[i].h, - (_mmi.p[i].prot & PROT_WRITE) + maps[i].h, + (maps[i].prot & PROT_WRITE) ? kNtFileMapWrite | kNtFileMapExecute | kNtFileMapRead : kNtFileMapExecute | kNtFileMapRead, 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(writer); + GlobalFree(maps); if (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, &_mmi.i, sizeof(_mmi.i)); + WriteAll(writer, _mmi.p, _mmi.i * sizeof(*_mmi.p)); for (i = 0; i < _mmi.i; ++i) { - WriteAll(writer, &_mmi.p[i], sizeof(_mmi.p[i])); if (_mmi.p[i].flags & MAP_PRIVATE) { WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16), ((uint64_t)(_mmi.p[i].y - _mmi.p[i].x) << 16) + FRAMESIZE); } } - WriteAll(writer, _edata, _end - _edata); + WriteAll(writer, _etext, _end - _etext); CloseHandle(writer); } else { rc = -1; diff --git a/libc/runtime/isheap.c b/libc/runtime/isheap.c index 37cf9d834..8acbe88af 100644 --- a/libc/runtime/isheap.c +++ b/libc/runtime/isheap.c @@ -17,7 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/macros.internal.h" -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" /** diff --git a/libc/runtime/memtrack.c b/libc/runtime/memtrack.c index 9ad09c30b..a5c3e3c5d 100644 --- a/libc/runtime/memtrack.c +++ b/libc/runtime/memtrack.c @@ -17,9 +17,12 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/assert.h" +#include "libc/bits/bits.h" +#include "libc/bits/weaken.h" #include "libc/dce.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/str/str.h" #include "libc/sysv/errfuns.h" @@ -167,18 +170,38 @@ static noasan void RemoveMemoryIntervals(struct MemoryIntervals *mm, int i, 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 <= mm->i); - assert(mm->i < ARRAYLEN(mm->p)); + assert(mm->i < mm->n); MoveMemoryNoAsan(mm->p + i + 1, 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) { - if (mm->i == ARRAYLEN(mm->p)) return enomem(); - CreateMemoryInterval(mm, i); + if (mm->i == mm->n) return enomem(); + if (CreateMemoryInterval(mm, i) == -1) return -1; mm->p[i].y = x - 1; mm->p[i + 1].x = y + 1; 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) { mm->p[i].x = x; } else { - if (mm->i == ARRAYLEN(mm->p)) return enomem(); - CreateMemoryInterval(mm, i); + if (mm->i == mm->n) return enomem(); + if (CreateMemoryInterval(mm, i) == -1) return -1; mm->p[i].x = x; mm->p[i].y = y; mm->p[i].h = h; diff --git a/libc/runtime/memtrack.h b/libc/runtime/memtrack.internal.h similarity index 91% rename from libc/runtime/memtrack.h rename to libc/runtime/memtrack.internal.h index 5862f8a72..e1ad39066 100644 --- a/libc/runtime/memtrack.h +++ b/libc/runtime/memtrack.internal.h @@ -21,15 +21,18 @@ COSMOPOLITAN_C_START_ #define kAutomapSize MEMTRACK_ADDRESS(_kAutomapSize, 0x40000000) #define kFixedmapStart MEMTRACK_ADDRESS(_kFixedmapStart, 0x40000000) +struct MemoryInterval { + int x; + int y; + long h; + int prot; + int flags; +}; + struct MemoryIntervals { - long i; - struct MemoryInterval { - int x; - int y; - long h; - int prot; - int flags; - } p[128]; + long i, n; + struct MemoryInterval *p; + struct MemoryInterval s[OPEN_MAX]; }; extern hidden struct MemoryIntervals _mmi; diff --git a/libc/runtime/memtracknt.c b/libc/runtime/memtracknt.c index 307bbd071..01bd3a6a8 100644 --- a/libc/runtime/memtracknt.c +++ b/libc/runtime/memtracknt.c @@ -19,7 +19,7 @@ #include "libc/assert.h" #include "libc/nt/memory.h" #include "libc/nt/runtime.h" -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" static noasan void *GetFrameAddr(int f) { diff --git a/libc/runtime/mmap.c b/libc/runtime/mmap.c index 60b85bdba..168bb6812 100644 --- a/libc/runtime/mmap.c +++ b/libc/runtime/mmap.c @@ -26,7 +26,7 @@ #include "libc/macros.internal.h" #include "libc/rand/rand.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/str/str.h" #include "libc/sysv/consts/map.h" diff --git a/libc/runtime/mmi.c b/libc/runtime/mmi.c index 7fdaa9b8b..f4268fc0a 100644 --- a/libc/runtime/mmi.c +++ b/libc/runtime/mmi.c @@ -16,6 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" + +STATIC_YOINK("_init__mmi"); struct MemoryIntervals _mmi; diff --git a/libc/runtime/mmi.init.S b/libc/runtime/mmi.init.S new file mode 100644 index 000000000..e55f2884d --- /dev/null +++ b/libc/runtime/mmi.init.S @@ -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 diff --git a/libc/runtime/msync-nt.c b/libc/runtime/msync-nt.c index 51601d7ec..72d601377 100644 --- a/libc/runtime/msync-nt.c +++ b/libc/runtime/msync-nt.c @@ -20,7 +20,7 @@ #include "libc/macros.internal.h" #include "libc/nt/files.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) { int x, y, l, r, i; diff --git a/libc/runtime/munmap.c b/libc/runtime/munmap.c index 0b9831702..badf8fd90 100644 --- a/libc/runtime/munmap.c +++ b/libc/runtime/munmap.c @@ -20,7 +20,7 @@ #include "libc/dce.h" #include "libc/macros.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/sysv/errfuns.h" diff --git a/libc/runtime/printmemoryintervals.c b/libc/runtime/printmemoryintervals.c index c858f5d60..424578f9b 100644 --- a/libc/runtime/printmemoryintervals.c +++ b/libc/runtime/printmemoryintervals.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/calls/calls.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) { int i, frames, maptally, gaptally; diff --git a/libc/runtime/untrackmemoryintervals.c b/libc/runtime/untrackmemoryintervals.c index 8d9dc8857..58d757ce4 100644 --- a/libc/runtime/untrackmemoryintervals.c +++ b/libc/runtime/untrackmemoryintervals.c @@ -18,7 +18,7 @@ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/dce.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 a, b; diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 519620be1..6adacd617 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -38,7 +38,7 @@ #include "libc/nt/struct/teb.h" #include "libc/runtime/directmap.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/sock/internal.h" @@ -108,6 +108,8 @@ static noasan textwindows wontreturn void WinMainNew(void) { kNtEnableProcessedOutput | kNtEnableWrapAtEolOutput | kNtEnableVirtualTerminalProcessing); } + _mmi.p = _mmi.s; + _mmi.n = OPEN_MAX; addr = version < 10 ? 0xff00000 : 0x777000000000; size = ROUNDUP(STACKSIZE + sizeof(struct WinArgs), FRAMESIZE); MapViewOfFileExNuma((_mmi.p[0].h = CreateFileMappingNuma( diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 8d8964404..afd91f1a6 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -357,10 +357,10 @@ _init_systemfive_stack: # determinism ftw! shr $16,%r11 # for the stack range shr $16,%r9 movb $1,(%rcx) # _mmi.i - mov %r11d,8(%rcx) # _mmi.p[0].x - mov %r9d,12(%rcx) # _mmi.p[0].y - mov %edx,20(%rcx) # _mmi.p[0].prot - mov %r10d,24(%rcx) # _mmi.p[0].flags + mov %r11d,24(%rcx) # _mmi.s[0].x + mov %r9d,28(%rcx) # _mmi.s[0].y + mov %edx,36(%rcx) # _mmi.s[0].prot + mov %r10d,40(%rcx) # _mmi.s[0].flags 3: pop %r9 # restore stack size pop %rsi pop %rdi diff --git a/test/libc/mem/malloc_test.c b/test/libc/mem/malloc_test.c index 39384cec1..787066ef1 100644 --- a/test/libc/mem/malloc_test.c +++ b/test/libc/mem/malloc_test.c @@ -23,7 +23,7 @@ #include "libc/macros.internal.h" #include "libc/mem/mem.h" #include "libc/rand/rand.h" -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" diff --git a/test/libc/nexgen32e/gclongjmp_test.c b/test/libc/nexgen32e/gclongjmp_test.c index a000df1fb..c9b572729 100644 --- a/test/libc/nexgen32e/gclongjmp_test.c +++ b/test/libc/nexgen32e/gclongjmp_test.c @@ -23,6 +23,7 @@ #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" +#include "libc/testlib/ezbench.h" #include "libc/testlib/testlib.h" #include "libc/x/x.h" @@ -73,3 +74,22 @@ TEST(gclongjmp, test) { free(y); 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()); +} diff --git a/test/libc/runtime/memtrack_test.c b/test/libc/runtime/memtrack_test.c index 8bc0b028d..5a616100e 100644 --- a/test/libc/runtime/memtrack_test.c +++ b/test/libc/runtime/memtrack_test.c @@ -20,7 +20,7 @@ #include "libc/limits.h" #include "libc/log/check.h" #include "libc/mem/mem.h" -#include "libc/runtime/memtrack.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" @@ -86,10 +86,12 @@ static int RunReleaseMemoryIntervalsTest(const struct MemoryIntervals t[2], } TEST(TrackMemoryInterval, TestEmpty) { - static const struct MemoryIntervals mm[2] = { - {0, {}}, - {1, {{2, 2, 0}}}, + static struct MemoryIntervals mm[2] = { + {0, OPEN_MAX, 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); } @@ -97,7 +99,7 @@ TEST(TrackMemoryInterval, TestFull) { int i; struct MemoryIntervals *mm; mm = calloc(1, sizeof(struct MemoryIntervals)); - for (i = 0; i < ARRAYLEN(mm->p); ++i) { + for (i = 0; i < mm->n; ++i) { CheckMemoryIntervalsAreOk(mm); CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0)); CheckMemoryIntervalsAreOk(mm); @@ -109,57 +111,71 @@ TEST(TrackMemoryInterval, TestFull) { } TEST(TrackMemoryInterval, TestAppend) { - static const struct MemoryIntervals mm[2] = { - {1, {{2, 2}}}, - {1, {{2, 3}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{2, 2}}}, + {1, OPEN_MAX, 0, {{2, 3}}}, }; + mm[0].p = mm[0].s; + mm[1].p = mm[1].s; RunTrackMemoryIntervalTest(mm, 3, 3, 0); } TEST(TrackMemoryInterval, TestPrepend) { - static const struct MemoryIntervals mm[2] = { - {1, {{2, 2}}}, - {1, {{1, 2}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{2, 2}}}, + {1, OPEN_MAX, 0, {{1, 2}}}, }; + mm[0].p = mm[0].s; + mm[1].p = mm[1].s; RunTrackMemoryIntervalTest(mm, 1, 1, 0); } TEST(TrackMemoryInterval, TestFillHole) { - static const struct MemoryIntervals mm[2] = { - {4, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {3, {{1, 4}, {5, 5, 1}, {6, 8}}}, + static struct MemoryIntervals mm[2] = { + {4, OPEN_MAX, 0, {{1, 1}, {3, 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); } TEST(TrackMemoryInterval, TestAppend2) { - static const struct MemoryIntervals mm[2] = { - {1, {{2, 2}}}, - {2, {{2, 2}, {3, 3, 1}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{2, 2}}}, + {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); } TEST(TrackMemoryInterval, TestPrepend2) { - static const struct MemoryIntervals mm[2] = { - {1, {{2, 2}}}, - {2, {{1, 1, 1}, {2, 2}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{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); } TEST(TrackMemoryInterval, TestFillHole2) { - static const struct MemoryIntervals mm[2] = { - {4, {{1, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, - {5, {{1, 1}, {2, 2, 1}, {3, 4}, {5, 5, 1}, {6, 8}}}, + static struct MemoryIntervals mm[2] = { + {4, OPEN_MAX, 0, {{1, 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); } TEST(FindMemoryInterval, Test) { - static const struct MemoryIntervals mm[1] = { + static struct MemoryIntervals mm[1] = { { 4, + OPEN_MAX, + 0, { [0] = {1, 1}, [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, 1)); EXPECT_EQ(1, FindMemoryInterval(mm, 2)); @@ -181,115 +198,141 @@ TEST(FindMemoryInterval, Test) { } TEST(ReleaseMemoryIntervals, TestEmpty) { - static const struct MemoryIntervals mm[2] = { - {0, {}}, - {0, {}}, + static struct MemoryIntervals mm[2] = { + {0, OPEN_MAX, 0, {}}, + {0, OPEN_MAX, 0, {}}, }; + mm[0].p = mm[0].s; + mm[1].p = mm[1].s; EXPECT_NE(-1, RunReleaseMemoryIntervalsTest(mm, 2, 2)); } TEST(ReleaseMemoryIntervals, TestRemoveElement_UsesInclusiveRange) { - static const struct MemoryIntervals mm[2] = { - {3, {{0, 0}, {2, 2}, {4, 4}}}, - {2, {{0, 0}, {4, 4}}}, + static struct MemoryIntervals mm[2] = { + {3, OPEN_MAX, 0, {{0, 0}, {2, 2}, {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)); } TEST(ReleaseMemoryIntervals, TestPunchHole) { - static const struct MemoryIntervals mm[2] = { - {1, {{0, 9}}}, - {2, {{0, 3}, {6, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{0, 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)); } TEST(ReleaseMemoryIntervals, TestShortenLeft) { if (IsWindows()) return; - static const struct MemoryIntervals mm[2] = { - {1, {{0, 9}}}, - {1, {{0, 7}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{0, 9}}}, + {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)); } TEST(ReleaseMemoryIntervals, TestShortenRight) { if (IsWindows()) return; - static const struct MemoryIntervals mm[2] = { - {1, {{0, 9}}}, - {1, {{3, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{0, 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)); } TEST(ReleaseMemoryIntervals, TestShortenLeft2) { if (IsWindows()) return; - static const struct MemoryIntervals mm[2] = { - {1, {{0, 9}}}, - {1, {{0, 7}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{0, 9}}}, + {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)); } TEST(ReleaseMemoryIntervals, TestShortenRight2) { if (IsWindows()) return; - static const struct MemoryIntervals mm[2] = { - {1, {{0, 9}}}, - {1, {{3, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{0, 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)); } TEST(ReleaseMemoryIntervals, TestZeroZero) { - static const struct MemoryIntervals mm[2] = { - {1, {{3, 9}}}, - {1, {{3, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{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)); } TEST(ReleaseMemoryIntervals, TestNoopLeft) { - static const struct MemoryIntervals mm[2] = { - {1, {{3, 9}}}, - {1, {{3, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{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)); } TEST(ReleaseMemoryIntervals, TestNoopRight) { - static const struct MemoryIntervals mm[2] = { - {1, {{3, 9}}}, - {1, {{3, 9}}}, + static struct MemoryIntervals mm[2] = { + {1, OPEN_MAX, 0, {{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)); } TEST(ReleaseMemoryIntervals, TestBigFree) { - static const struct MemoryIntervals mm[2] = { - {2, {{0, 3}, {6, 9}}}, - {0, {}}, + static struct MemoryIntervals mm[2] = { + {2, OPEN_MAX, 0, {{0, 3}, {6, 9}}}, + {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)); } TEST(ReleaseMemoryIntervals, TestWeirdGap) { - static const struct MemoryIntervals mm[2] = { - {3, {{10, 10}, {20, 20}, {30, 30}}}, - {2, {{10, 10}, {30, 30}}}, + static struct MemoryIntervals mm[2] = { + {3, OPEN_MAX, 0, {{10, 10}, {20, 20}, {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)); } -TEST(ReleaseMemoryIntervals, TestOutOfMemory) { +TEST(ReleaseMemoryIntervals, TestOutOfMemory_AllocatesMore) { int i; struct MemoryIntervals *mm; 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)); } CheckMemoryIntervalsAreOk(mm); - CHECK_EQ(-1, ReleaseMemoryIntervals(mm, 4, 4, NULL)); - CHECK_EQ(ENOMEM, errno); + CHECK_EQ(0, ReleaseMemoryIntervals(mm, 4, 4, NULL)); CheckMemoryIntervalsAreOk(mm); + free(mm->p); free(mm); } diff --git a/test/libc/runtime/mmap_test.c b/test/libc/runtime/mmap_test.c index dec67cdbf..045ce2b50 100644 --- a/test/libc/runtime/mmap_test.c +++ b/test/libc/runtime/mmap_test.c @@ -23,7 +23,7 @@ #include "libc/log/log.h" #include "libc/mem/mem.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/stdio/stdio.h" #include "libc/str/str.h" diff --git a/tool/build/lib/elfwriter.c b/tool/build/lib/elfwriter.c index d5bf9371f..580c2df47 100644 --- a/tool/build/lib/elfwriter.c +++ b/tool/build/lib/elfwriter.c @@ -24,7 +24,7 @@ #include "libc/mem/fmt.h" #include "libc/mem/mem.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/sysv/consts/map.h" #include "libc/sysv/consts/mremap.h" diff --git a/tool/build/runit.c b/tool/build/runit.c index f3932c22e..046ad7085 100644 --- a/tool/build/runit.c +++ b/tool/build/runit.c @@ -388,7 +388,7 @@ int RunOnHost(char *spec) { do { Connect(); EzFd(g_sock); - EzHandshake(); + EzHandshake(); /* TODO(jart): Backoff on MBEDTLS_ERR_NET_CONN_RESET */ SendRequest(); } while ((rc = ReadResponse()) == -1); return rc;