Skip to content

Commit aa785cc

Browse files
committed
Futures
1 parent 0659bf4 commit aa785cc

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

libraries/common/io.effekt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ extern async def abort(): Nothing =
3535
ret void
3636
"""
3737

38+
// Futures
39+
// -------
40+
41+
extern type Future[T]
42+
43+
extern global def allocate[T](): Future[T] =
44+
llvm """
45+
%future = call %Pos @c_future_make()
46+
ret %Pos %future
47+
"""
48+
49+
extern global def fill[T](future: Future[T], value: T): Unit =
50+
llvm """
51+
call void @c_future_fill(%Pos ${future}, %Pos ${value})
52+
ret %Pos zeroinitializer
53+
"""
54+
55+
extern async def wait[T](future: Future[T]): T =
56+
llvm """
57+
call void @c_future_wait(%Pos ${future}, %Stack %stack)
58+
ret void
59+
"""
60+
61+
extern llvm """
62+
declare %Pos @c_future_make()
63+
declare void @c_future_fill(%Pos, %Pos)
64+
declare void @c_future_wait(%Pos, %Stack)
65+
"""
3866

3967
// Promises
4068
// --------

libraries/llvm/io.c

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,90 @@ void c_yield(Stack stack) {
295295
c_timer_start(0, stack);
296296
}
297297

298+
// Futures
299+
// -------
300+
301+
typedef enum { EMPTY, FILLED, WAITED } future_state_t;
302+
303+
typedef struct {
304+
uint64_t rc;
305+
void* eraser;
306+
future_state_t state;
307+
union {
308+
struct Pos value;
309+
Stack stack;
310+
} payload;
311+
} Future;
312+
313+
void c_future_erase(void *envPtr) {
314+
// envPtr points to a Future _after_ the eraser, so let's adjust it to point to the beginning.
315+
Future *future = (Future*) (envPtr - offsetof(Future, state));
316+
future_state_t state = future->state;
317+
switch (state) {
318+
case EMPTY:
319+
break;
320+
case FILLED:
321+
erasePositive(future->payload.value);
322+
break;
323+
case WAITED:
324+
eraseStack(future->payload.stack);
325+
break;
326+
}
327+
}
328+
329+
struct Pos c_future_make() {
330+
Future* future = (Future*)malloc(sizeof(Future));
331+
332+
future->rc = 0;
333+
future->eraser = c_future_erase;
334+
future->state = EMPTY;
335+
336+
return (struct Pos) { .tag = 0, .obj = future, };
337+
}
338+
339+
void c_future_fill(struct Pos future, struct Pos value) {
340+
Future* f = (Future*)future.obj;
341+
switch (f->state) {
342+
case EMPTY:
343+
f->state = FILLED;
344+
f->payload.value = value;
345+
break;
346+
case FILLED:
347+
erasePositive(future);
348+
erasePositive(value);
349+
// TODO more graceful panic
350+
fprintf(stderr, "ERROR: Future already filled\n");
351+
exit(1);
352+
break;
353+
case WAITED:
354+
Stack stack = f->payload.stack;
355+
free(f);
356+
resume_Pos(stack, value);
357+
break;
358+
}
359+
}
360+
361+
void c_future_wait(struct Pos future, Stack stack) {
362+
Future* f = (Future*)future.obj;
363+
switch (f->state) {
364+
case EMPTY:
365+
f->state = WAITED;
366+
f->payload.stack = stack;
367+
break;
368+
case FILLED:
369+
struct Pos value = f->payload.value;
370+
free(f);
371+
resume_Pos(stack, value);
372+
break;
373+
case WAITED:
374+
erasePositive(future);
375+
eraseStack(stack);
376+
// TODO more graceful panic
377+
fprintf(stderr, "ERROR: Future already waited\n");
378+
exit(1);
379+
break;
380+
}
381+
}
298382

299383
// Promises
300384
// --------

0 commit comments

Comments
 (0)