aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/core.c45
-rw-r--r--src/core/io_linux.c21
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);}