diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.c | 45 | ||||
| -rw-r--r-- | src/core/io_linux.c | 21 |
2 files changed, 47 insertions, 19 deletions
diff --git a/src/core/core.c b/src/core/core.c index bf48b19..77c4a99 100644 --- a/src/core/core.c +++ b/src/core/core.c @@ -256,6 +256,7 @@ static atomic_int context_records_live, context_code_live, context_memory_live; size_t io_context_size(void); void io_context_snapshot(void *destination); void io_context_restore(const void *source); +void io_context_release(void); #else static VM_TLS int context_default_stop; #endif @@ -622,10 +623,6 @@ typedef struct { Uop *u; signed char *reg; /* physical register per value, for the jit; 0 if it didn't fit */ } Enh; -static VM_TLS Enh enh[NENH]; -static VM_TLS int need_flush; - -#define MAXUOP 4096 /* large per-thread tables live behind a pointer and are mapped on first use, so a worker thread that never compiles anything pays nothing for them (as static tls they were zeroed into every thread's stack mapping: about 13 MB per actor) */ @@ -655,6 +652,12 @@ static void tls_big_free(void) } } #define TLS_BIG(p) (*((p) ? (p) : (__typeof__(p))tls_big(sizeof *(p), (void **)&(p)))) +static VM_TLS Enh (*enh_tls)[NENH]; +#define enh TLS_BIG(enh_tls) + +static VM_TLS int need_flush; + +#define MAXUOP 4096 static VM_TLS Uop (*ub_tls)[MAXUOP]; #define ub TLS_BIG(ub_tls) static VM_TLS int un, unv, uerr; /* the program being built */ @@ -1154,11 +1157,19 @@ typedef struct { unsigned gen; /* bumped every time the region's code is dropped: a copy made from an older one is stale */ } Rg; #define MAXRG 4096 -static VM_TLS Rg *rgs[MAXRG]; +static VM_TLS Rg * (*rgs_tls)[MAXRG]; +#define rgs TLS_BIG(rgs_tls) + static VM_TLS int nrg; -static VM_TLS int fn_pc[MAXRG]; -static VM_TLS Rg *fn_rg_[MAXRG]; -static VM_TLS Rg *fn_cache[1024]; +static VM_TLS int (*fn_pc_tls)[MAXRG]; +#define fn_pc TLS_BIG(fn_pc_tls) + +static VM_TLS Rg * (*fn_rg__tls)[MAXRG]; +#define fn_rg_ TLS_BIG(fn_rg__tls) + +static VM_TLS Rg * (*fn_cache_tls)[1024]; +#define fn_cache TLS_BIG(fn_cache_tls) + static VM_TLS int nfn; /* ---- bookkeeping for translated code, shared by the backends ---- @@ -1809,7 +1820,9 @@ static Cell ffi_cbmake(Cell entry, Cell sig) /* a native call the o3 lifter has resolved: the micro-ops narg and ncall carry an index into this table. imm of narg is the argument's position */ typedef struct { void *f; Cell sig; int n; char name[48]; } Ncd; -static VM_TLS Ncd ncd[256]; +static VM_TLS Ncd (*ncd_tls)[256]; +#define ncd TLS_BIG(ncd_tls) + static VM_TLS int nncd; static int ncd_get(Cell blk) { @@ -2407,7 +2420,9 @@ static VM_TLS int (*g_isk_tls)[MAXUOP * 4]; #define g_isk TLS_BIG(g_isk_tls) static VM_TLS Cell (*g_kv_tls)[MAXUOP * 4]; #define g_kv TLS_BIG(g_kv_tls) -static VM_TLS int g_omap[MAXUOP + 16]; +static VM_TLS int (*g_omap_tls)[MAXUOP + 16]; +#define g_omap TLS_BIG(g_omap_tls) + static int cjoin(CIn *d, const CIn *s) { int j, ch = 0; @@ -3360,7 +3375,9 @@ static VM_TLS void **tab; /* vm address -> translation */ typedef struct { void *stub; int fslots; int argc; } FnNat; static VM_TLS FnNat *fn_nat; #define LINKN 1024 -static VM_TLS void *linkstk[LINKN]; +static VM_TLS void * (*linkstk_tls)[LINKN]; +#define linkstk TLS_BIG(linkstk_tls) + static VM_TLS Cell jit_depth; #endif static void be_drop(int j) { tab[ix_blk[j].a] = 0; cdec(cov, ix_blk[j].a, ix_blk[j].b); if (trace) fprintf(stderr, "jit: dropped %d..%d\n", ix_blk[j].a, ix_blk[j].b - 1); } @@ -6307,7 +6324,9 @@ static void x64_enh(Enh *e) under ZYO3INTERP=1. */ static VM_TLS int x64_o3interp; static void perfmap_note(JW *start, JW *end, const char *kind, int a, int b); -static VM_TLS signed char rxr[MAXUOP * 4 + 16]; +static VM_TLS signed char (*rxr_tls)[MAXUOP * 4 + 16]; +#define rxr TLS_BIG(rxr_tls) + #define RXNREG 6 static void rsave(void) { int j; for (j = 0; j < RXNREG; j++) push_r(xreg[j]); } static void rrest(void) { int j; for (j = RXNREG - 1; j >= 0; j--) pop_r(xreg[j]); } @@ -7563,7 +7582,7 @@ static void context_engine_free(void) { free(lcov); free(lt); free(hot); #endif #endif - if (memory_mapped) vm_memory_unmap(m); else free(m); m = 0; snap_drop(); tls_big_free(); atomic_fetch_sub(&context_memory_live, 1); + if (memory_mapped) vm_memory_unmap(m); else free(m); m = 0; snap_drop(); tls_big_free(); io_context_release(); atomic_fetch_sub(&context_memory_live, 1); } static void *context_worker(void *opaque) { VmContext *context = opaque; diff --git a/src/core/io_linux.c b/src/core/io_linux.c index aaf6a18..c3e05dd 100644 --- a/src/core/io_linux.c +++ b/src/core/io_linux.c @@ -1,3 +1,4 @@ +#include <stdlib.h> #include <stdio.h> #include <string.h> #ifdef _WIN32 @@ -25,7 +26,11 @@ char Q(void){int c=getchar();J=pk();return c;} one would wait for a message that comes only after the answer. so J is 1 only when the end is known, and 0 when more may come. the output is flushed before any read that can wait, for the same reason. */ -static VM_TLS unsigned char ib[65536]; +#define IBN 65536 +/* each vm thread's buffer is allocated when it first reads, so an actor that never + reads standard input carries none */ +static VM_TLS unsigned char *ibp; +#define ib (ibp ? ibp : (ibp = malloc(IBN)) ? ibp : (fputs("zy: out of memory\n", stderr), exit(2), ibp)) static VM_TLS int ip, in, ieof; /* make a byte available. wait is 0 to look without waiting. returns 1 when one is ready */ static int fill(int wait) @@ -37,7 +42,7 @@ static int fill(int wait) struct pollfd f; f.fd = 0; f.events = POLLIN; f.revents = 0; if (poll(&f, 1, 0) <= 0) return 0; /* nothing yet: not the end, not a byte */ } else fflush(stdout); - n = (int)read(0, ib, sizeof ib); + n = (int)read(0, ib, IBN); if (n <= 0) { ieof = 1; return 0; } ip = 0; in = n; return 1; @@ -62,16 +67,20 @@ int input_pending(void) #endif } #ifndef _WIN32 -struct IoSnapshot { unsigned char bytes[65536]; int position, count, ended, flag; }; -size_t io_context_size(void) { return sizeof(struct IoSnapshot); } +/* what a new worker inherits: the bytes read ahead and not consumed yet, and the flags */ +struct IoSnapshot { int position, count, ended, flag; unsigned char bytes[]; }; +size_t io_context_size(void) { return sizeof(struct IoSnapshot) + (size_t)(ip < in ? in - ip : 0); } void io_context_snapshot(void *destination) { struct IoSnapshot *snapshot = destination; - memcpy(snapshot->bytes, ib, sizeof ib); snapshot->position = ip; snapshot->count = in; snapshot->ended = ieof; snapshot->flag = J; + if (ip < in) memcpy(snapshot->bytes, ib + ip, (size_t)(in - ip)); + snapshot->position = ip; snapshot->count = in; snapshot->ended = ieof; snapshot->flag = J; } void io_context_restore(const void *source) { const struct IoSnapshot *snapshot = source; - memcpy(ib, snapshot->bytes, sizeof ib); ip = snapshot->position; in = snapshot->count; ieof = snapshot->ended; J = snapshot->flag; + ip = snapshot->position; in = snapshot->count; ieof = snapshot->ended; J = snapshot->flag; + if (ip < in) memcpy(ib + ip, snapshot->bytes, (size_t)(in - ip)); } +void io_context_release(void) { free(ibp); ibp = 0; } #endif void G(char c){putchar(c);} |
