aboutsummaryrefslogtreecommitdiff
path: root/src/micro/port_linux.c
diff options
context:
space:
mode:
authorGravatar Moon Flower <moonflower@elhenney.local> 2026-10-14 08:29:46 +0330
committerGravatar Moon Flower <moonflower@elhenney.local> 2026-10-14 08:29:46 +0330
commit1c53304d03414890af0da7432d1aea87e754a14a (patch)
tree97190d86cf548c9bc63f68c86a4d2a4f09809713 /src/micro/port_linux.c
parenta (diff)
feat: grow memory limits, add icon/actor libraries, overhaul LSP diagnostics
Compiler and VM - make every memory map limit dynamic and adjustable at both build time and runtime, including compiler tables, stacks, and every execution region - reserve and grow tables, operand and return stacks, frame segments, and image-building output without relocating live code or globals - rename i/o and string helpers consistently (puts -> put_s, putn -> put_n, scat -> cat_s) across compiler, runtime, examples, tests, and docs - recast and consume values assigned to globals from inside functions - allow fixed and const together, add typed closure returns (fn:t(...)), multi-include syntax (include rt, run, core;), and recurse type inference - never infer string literals as word, anywhere, as argument, variable, or return type - draft docs/BORROW.md: a borrow checker less intrusive than Rust's but more intelligent LSP and editor integration - require explicit includes and give every toolchain area its own namespace (rt, lsp, run, core) - hover for built-in types, inferred types, values known at hover time, array and pointer lifetime/size, library names in include statements, and inferred lifetimes with explanations - honor /* */ comments as documentation for variables and arguments, and stop misattributing section headers or trailing comments as variable hints - stream diagnostics and cancel stale requests on change - jump to definition and references, including cross-file - quick fixes with automatic library import, and namespace completion Hints and diagnostics - render hints as blue squigglies by default, with hints on/small/off per file - suppress magic-number hints via a preceding /* */ comment, and say so - warn on unused arguments; allow multiple _ discards in parameters, pattern matching, and tagged enums, warning if a _ is actually used - rewrite hint and comment prose in professional compiler-doc register Libraries - add icon.zc: run-time self-modification, find/replace syntax, type and block edits, and step-through inspection of locals and globals - add actor.zc: async actors with Actor<I,O>, implicit this, spawn/recv/send, injected into the compiler machinery at include time rather than built in Tooling and docs - reorganize sources, tests, and designs into subdirectories - unify windows entry points in tinyvm.bat and add a matching tinyvm.sh - add --help across the toolchain - polish the learning guide, stdlib docs, and design notes Tests - add accept, reject, and regression coverage across the compiler, LSP, - runtime, icon, actors, threads, formatting, and the toolchain contracts, plus fuzzers and property tests
Diffstat (limited to 'src/micro/port_linux.c')
-rw-r--r--src/micro/port_linux.c167
1 files changed, 148 insertions, 19 deletions
diff --git a/src/micro/port_linux.c b/src/micro/port_linux.c
index e6c8847..9331a0b 100644
--- a/src/micro/port_linux.c
+++ b/src/micro/port_linux.c
@@ -19,6 +19,10 @@
#endif
#else
#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <poll.h>
+#include <signal.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
@@ -28,11 +32,16 @@
#include <time.h>
#include "micro_port.h"
#include "bops.h"
+#ifdef ZY_THREADS
+#define VM_TLS _Thread_local
+#else
+#define VM_TLS
+#endif
/* the machine's memory: a block that grows by realloc, zero in the new part. the
base can move on a grow, which micro.c takes into account (it re-reads m). */
-static Cell *lmem;
-static UCell lcap;
+static VM_TLS Cell *lmem;
+static VM_TLS UCell lcap;
Cell *micro_mem_alloc(UCell words)
{
@@ -47,19 +56,24 @@ Cell *micro_mem_alloc(UCell words)
return n;
}
-int micro_getc(void)
-{
- int c = getchar();
- return c == EOF ? -1 : c;
-}
-
-int micro_eof(void)
-{
- int c = getchar();
- if (c == EOF) return 1;
- ungetc(c, stdin);
- return 0;
+#if defined(ZY_THREADS)
+static VM_TLS unsigned char input_bytes[65536];
+static VM_TLS int input_position, input_count, input_ended;
+static int input_fill(int wait) {
+ if (input_position < input_count) return 1;
+ if (input_ended) return 0;
+ if (!wait) { struct pollfd descriptor = {0, POLLIN, 0}; if (poll(&descriptor, 1, 0) <= 0) return 0; }
+ else fflush(stdout);
+ int n = (int)read(0, input_bytes, sizeof input_bytes);
+ if (n <= 0) { input_ended = 1; return 0; }
+ input_position = 0; input_count = n; return 1;
}
+int micro_getc(void) { return input_fill(1) ? input_bytes[input_position++] : -1; }
+int micro_eof(void) { input_fill(0); return input_ended; }
+#else
+int micro_getc(void) { int c = getchar(); return c == EOF ? -1 : c; }
+int micro_eof(void) { int c = getchar(); if (c == EOF) return 1; ungetc(c, stdin); return 0; }
+#endif
void micro_putc(int c) { putchar(c & 255); }
@@ -87,10 +101,10 @@ static int inmem(Cell a) { return (UCell)a < (UCell)micro_mem_words(); }
#ifndef _WIN32
extern char **environ;
#endif
-static int zy_argc;
-static char **zy_argv;
-static int zy_envc;
-static char **zy_envp;
+static VM_TLS int zy_argc;
+static VM_TLS char **zy_argv;
+static VM_TLS int zy_envc;
+static VM_TLS char **zy_envp;
static void zy_args(int argc, char **argv)
{
@@ -126,7 +140,7 @@ static Cell vecstr(Cell *mem, char **v, int count, Cell a, Cell b, Cell c, const
static Cell host_rand(void)
{
- static uint64_t s;
+ static VM_TLS uint64_t s;
if (!s) s = (uint64_t)time(0) ^ 0x9E3779B97F4A7C15ull;
if (!s) s = 0x9E3779B97F4A7C15ull;
s ^= s << 13; s ^= s >> 7; s ^= s << 17;
@@ -152,6 +166,84 @@ Cell micro_syscall(Cell *mem, Cell op, Cell a, Cell b, Cell c)
char path[1024], tmp[512];
int n, i, got;
switch (op) {
+ case 43: { /* clone an isolated execution context with a bidirectional channel */
+#if !defined(_WIN32) && !defined(__wasm__)
+ int fd[2]; pid_t child;
+ if (!inmem(a) || socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) return -1;
+ fflush(NULL); child = fork();
+ if (child < 0) { close(fd[0]); close(fd[1]); return -1; }
+ if (!child) { close(fd[0]); mem[a] = fd[1]; return 0; }
+ close(fd[1]); mem[a] = fd[0]; return child;
+#else
+ return -1;
+#endif
+ }
+ case 44: case 45: { /* write/read complete word buffers on a context channel */
+#if !defined(_WIN32) && !defined(__wasm__)
+ size_t done = 0, length; ssize_t got; unsigned char *buffer;
+ if (b < 0 || c < 0 || c > (Cell)micro_mem_words() - b) return -1;
+ buffer = (unsigned char *)(mem + b); length = (size_t)c * sizeof(Cell);
+ while (done < length) {
+ if (op == 44) {
+#ifdef __APPLE__
+ int enabled = 1; setsockopt((int)a, SOL_SOCKET, SO_NOSIGPIPE, &enabled, sizeof enabled);
+ #ifdef MSG_NOSIGNAL
+ got = send((int)a, buffer + done, length - done, MSG_NOSIGNAL);
+#else
+ got = send((int)a, buffer + done, length - done, 0);
+#endif
+#else
+ got = send((int)a, buffer + done, length - done, MSG_NOSIGNAL);
+#endif
+ } else got = read((int)a, buffer + done, length - done);
+ if (got < 0 && errno == EINTR) continue;
+ if (got <= 0) return -1;
+ done += (size_t)got;
+ }
+ return c;
+#else
+ return -1;
+#endif
+ }
+ case 46: { /* channel readiness, with a millisecond timeout */
+#if !defined(_WIN32) && !defined(__wasm__)
+ struct pollfd fd; int ready; fd.fd = (int)a; fd.events = POLLIN; fd.revents = 0;
+ do { ready = poll(&fd, 1, (int)b); } while (ready < 0 && errno == EINTR);
+ return ready > 0 ? !!(fd.revents & (POLLIN | POLLHUP)) : ready;
+#else
+ return -1;
+#endif
+ }
+ case 47: case 49: { /* join a child context, optionally terminating it first */
+#if !defined(_WIN32) && !defined(__wasm__)
+ int status; pid_t joined;
+ if (a <= 0) return -1;
+ if (op == 49) kill((pid_t)a, SIGTERM);
+ do { joined = waitpid((pid_t)a, &status, 0); } while (joined < 0 && errno == EINTR);
+ return joined < 0 ? -1 : WIFEXITED(status) ? WEXITSTATUS(status) : -1;
+#else
+ return -1;
+#endif
+ }
+ case 50: { /* monotonic milliseconds for elapsed-time measurements */
+#if !defined(_WIN32) && !defined(__wasm__)
+ struct timespec now; if (clock_gettime(CLOCK_MONOTONIC, &now) < 0) return -1;
+ return (Cell)now.tv_sec * 1000 + now.tv_nsec / 1000000;
+#else
+ return -1;
+#endif
+ }
+ case 48: { /* sleep for a bounded millisecond duration */
+#if !defined(_WIN32) && !defined(__wasm__)
+ struct timespec duration;
+ if (a < 0 || a > 86400000) return -1;
+ duration.tv_sec = (time_t)(a / 1000); duration.tv_nsec = (long)(a % 1000) * 1000000;
+ while (nanosleep(&duration, &duration) < 0) if (errno != EINTR) return -1;
+ return 0;
+#else
+ return -1;
+#endif
+ }
case 1:
if (zcstr(mem, a, path, 1024) < 0) return -1;
if (b == 1) return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
@@ -269,6 +361,21 @@ Cell micro_syscall(Cell *mem, Cell op, Cell a, Cell b, Cell c)
int main(int argc, char **argv) {
UCell initial, limit;
+ if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) {
+ fputs("usage: zym [program arguments] < input\n"
+ "runs the embedded image with the portable vm; compiler images read source from stdin.\n"
+ "input after a backtick is program input; run-only images read program input directly.\n"
+ "program arguments are available through std.argv; stdin has the name <eval>.\n"
+ "options:\n --help, -h show this help and exit\n"
+ "environment:\n"
+ " TINYVM_MEMORY_WORDS initial vm memory in words\n"
+ " TINYVM_MAX_MEMORY_WORDS maximum vm memory in words\n", stdout);
+ return 0;
+ }
+ if (argc > 1 && argv[1][0] == '-' && argv[1][1] == '-') {
+ fprintf(stderr, "micro: unknown option %s; use --help for usage\n", argv[1]);
+ return 2;
+ }
#ifdef _WIN32
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
@@ -282,3 +389,25 @@ int main(int argc, char **argv) {
}
return micro_run();
}
+
+#ifdef ZY_THREADS
+struct PortSnapshot {
+ unsigned char bytes[65536];
+ int position, count, ended, argc, envc;
+ char **argv, **envp;
+};
+size_t micro_context_port_size(void) { return sizeof(struct PortSnapshot); }
+void micro_context_port_save(void *destination) {
+ struct PortSnapshot *snapshot = destination;
+ memcpy(snapshot->bytes, input_bytes, sizeof input_bytes);
+ snapshot->position = input_position; snapshot->count = input_count; snapshot->ended = input_ended;
+ snapshot->argc = zy_argc; snapshot->argv = zy_argv; snapshot->envc = zy_envc; snapshot->envp = zy_envp;
+}
+void micro_context_port_restore(const void *source) {
+ const struct PortSnapshot *snapshot = source;
+ memcpy(input_bytes, snapshot->bytes, sizeof input_bytes);
+ input_position = snapshot->position; input_count = snapshot->count; input_ended = snapshot->ended;
+ zy_argc = snapshot->argc; zy_argv = snapshot->argv; zy_envc = snapshot->envc; zy_envp = snapshot->envp;
+}
+void micro_context_port_free(void) { free(lmem); lmem = 0; lcap = 0; }
+#endif