mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-03-03 07:29:23 +00:00
Make mappings unlimited on NT
This change might also fix fork() in certain cases on NT.
This commit is contained in:
parent
ab64c746cc
commit
34b68f1945
31 changed files with 356 additions and 127 deletions
24
examples/defer-statements.c
Normal file
24
examples/defer-statements.c
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() */
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
|
@ -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) {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
24
libc/runtime/mmi.init.S
Normal 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
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue