/* future.c — a FUTURE as one more magic-tagged heap object. * * Fixture for tests/integration/async_future.sh. Linked into the probe but * never referenced from El source: everything here is reached only by binding * a construct AFTER the binary exists. * * The claim under test: @async needs no compiler change. el_val_t already * carries List, Map, Geometry, Manifold and Bin as magic-tagged heap pointers; * a future is one more, and el_seam_wrap hands the target the body so it can * decide whether and when to invoke it. */ #include #include #include #include #include #include typedef int64_t el_val_t; #define EL_MAGIC_FUT 0xE1F07000u typedef struct { uint32_t magic; pthread_t th; el_val_t result; int done; el_val_t (*body)(void*); void* env; } ElFuture; static long t0_us; static long now_us(void){ struct timespec ts; clock_gettime(CLOCK_MONOTONIC,&ts); return ts.tv_sec*1000000L + ts.tv_nsec/1000; } static void* fut_runner(void* v){ ElFuture* f = (ElFuture*)v; printf("BODY_START %ld\n", now_us()-t0_us); usleep(50000); /* 50ms, so interleaving is visible */ f->result = f->body(f->env); f->done = 1; printf("BODY_END %ld\n", now_us()-t0_us); return NULL; } /* wraps_body target: returns the HANDLE immediately, never the result */ el_val_t defer(el_val_t fn, el_val_t con, el_val_t (*b)(void*), void* e){ (void)fn; (void)con; t0_us = now_us(); ElFuture* f = calloc(1,sizeof(ElFuture)); f->magic = EL_MAGIC_FUT; f->body = b; f->env = e; pthread_create(&f->th, NULL, fut_runner, f); printf("WRAP_RETURNED %ld\n", now_us()-t0_us); return (el_val_t)(intptr_t)f; } /* el_await — block on the handle and yield the real result. * * NEVER dereference to decide whether a slot is a pointer. el_val_t carries * integers too, so reading ->magic off an integer dereferences that integer AS * AN ADDRESS. The first version of this function did exactly that and * SIGSEGV'd on the unbound path -- sixty seconds after the same defect was * diagnosed elsewhere in the runtime. Check the floor and alignment first. */ el_val_t el_await(el_val_t h){ if (h < 0x10000) return h; /* small ints / low addresses */ if (h & 0x7) return h; /* malloc returns 8-aligned */ ElFuture* f = (ElFuture*)(intptr_t)h; if (f->magic != EL_MAGIC_FUT) return h; /* safe to read now */ pthread_join(f->th, NULL); el_val_t r = f->result; free(f); return r; }