feat: async functions with return values
- runtime: bux_async_return(value, size) copies result to task->result - runtime: bux_async_await returns void* result pointer - runtime: bux_async_result(handle) to retrieve result - sema: ekAwait returns *void - HIR: await lowered to bux_async_await returning *void - Example: async Compute() -> int with interleaved execution and result await
This commit is contained in:
+27
-17
@@ -1,32 +1,42 @@
|
|||||||
import Std::Io::PrintLine;
|
import Std::Io::{PrintLine, PrintInt};
|
||||||
|
|
||||||
extern func bux_async_yield();
|
extern func bux_async_yield();
|
||||||
extern func bux_async_run();
|
extern func bux_async_run();
|
||||||
extern func bux_async_spawn(fn: *void) -> *void;
|
extern func bux_async_spawn(fn: *void) -> *void;
|
||||||
extern func bux_async_await(handle: *void);
|
extern func bux_async_await(handle: *void) -> *void;
|
||||||
|
extern func bux_async_return(value: *void, size: int64);
|
||||||
|
|
||||||
async func WorkA() {
|
async func Compute() -> int {
|
||||||
PrintLine("WorkA: step 1");
|
PrintLine("Compute: step 1");
|
||||||
bux_async_yield();
|
bux_async_yield();
|
||||||
PrintLine("WorkA: step 2");
|
PrintLine("Compute: step 2");
|
||||||
bux_async_yield();
|
let result: int = 42;
|
||||||
PrintLine("WorkA: done");
|
bux_async_return((&result) as *void, sizeof(int));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async func WorkB() {
|
async func Double() -> int {
|
||||||
PrintLine("WorkB: step 1");
|
PrintLine("Double: step 1");
|
||||||
bux_async_yield();
|
bux_async_yield();
|
||||||
PrintLine("WorkB: step 2");
|
PrintLine("Double: step 2");
|
||||||
bux_async_yield();
|
let result: int = 84;
|
||||||
PrintLine("WorkB: done");
|
bux_async_return((&result) as *void, sizeof(int));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() -> int {
|
func Main() -> int {
|
||||||
PrintLine("Main: start");
|
PrintLine("Main: start");
|
||||||
let h1: *void = spawn WorkA();
|
let h1: *void = spawn Compute();
|
||||||
let h2: *void = spawn WorkB();
|
let h2: *void = spawn Double();
|
||||||
bux_async_await(h1);
|
let r1Ptr: *int = h1.await as *int;
|
||||||
bux_async_await(h2);
|
let r2Ptr: *int = h2.await as *int;
|
||||||
PrintLine("Main: all done");
|
let r1: int = *r1Ptr;
|
||||||
|
let r2: int = *r2Ptr;
|
||||||
|
PrintLine("Results:");
|
||||||
|
PrintInt(r1);
|
||||||
|
PrintLine("");
|
||||||
|
PrintInt(r2);
|
||||||
|
PrintLine("");
|
||||||
|
PrintLine("Main: done");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -770,7 +770,7 @@ proc lowerExpr(ctx: var LowerCtx, expr: Expr): HirNode =
|
|||||||
|
|
||||||
of ekAwait:
|
of ekAwait:
|
||||||
let lowered = ctx.lowerExpr(expr.exprAwaitOperand)
|
let lowered = ctx.lowerExpr(expr.exprAwaitOperand)
|
||||||
return hirCall("bux_async_await", @[lowered], makeVoid(), loc)
|
return hirCall("bux_async_await", @[lowered], makePointer(makeVoid()), loc)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc),
|
return HirNode(kind: hLit, litToken: Token(kind: tkIntLiteral, text: "0", loc: loc),
|
||||||
|
|||||||
+2
-2
@@ -1010,8 +1010,8 @@ proc checkExpr(sema: var Sema, expr: Expr, scope: Scope): Type =
|
|||||||
return makePointer(makeVoid())
|
return makePointer(makeVoid())
|
||||||
of ekAwait:
|
of ekAwait:
|
||||||
let operand = sema.checkExpr(expr.exprAwaitOperand, scope)
|
let operand = sema.checkExpr(expr.exprAwaitOperand, scope)
|
||||||
# await on a task handle returns void for now
|
# await on a task handle returns *void (result pointer)
|
||||||
return makeVoid()
|
return makePointer(makeVoid())
|
||||||
of ekSpread:
|
of ekSpread:
|
||||||
return sema.checkExpr(expr.exprSpreadOperand, scope)
|
return sema.checkExpr(expr.exprSpreadOperand, scope)
|
||||||
|
|
||||||
|
|||||||
+18
-2
@@ -808,6 +808,7 @@ typedef struct bux_async_task {
|
|||||||
uint8_t* stack;
|
uint8_t* stack;
|
||||||
int state; /* 0 = ready, 1 = running, 2 = done */
|
int state; /* 0 = ready, 1 = running, 2 = done */
|
||||||
void (*entry)(void);
|
void (*entry)(void);
|
||||||
|
void* result; /* pointer to heap-allocated result */
|
||||||
struct bux_async_task* next;
|
struct bux_async_task* next;
|
||||||
} bux_async_task_t;
|
} bux_async_task_t;
|
||||||
|
|
||||||
@@ -883,8 +884,8 @@ void bux_async_yield(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void bux_async_await(void* handle) {
|
void* bux_async_await(void* handle) {
|
||||||
if (!handle) return;
|
if (!handle) return NULL;
|
||||||
bux_async_task_t* target = (bux_async_task_t*)handle;
|
bux_async_task_t* target = (bux_async_task_t*)handle;
|
||||||
while (target->state != 2) {
|
while (target->state != 2) {
|
||||||
if (bux_current_task != NULL) {
|
if (bux_current_task != NULL) {
|
||||||
@@ -897,6 +898,7 @@ void bux_async_await(void* handle) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return target->result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bux_async_run(void) {
|
void bux_async_run(void) {
|
||||||
@@ -931,3 +933,17 @@ void bux_async_sleep(int64_t ms) {
|
|||||||
bux_async_yield();
|
bux_async_yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bux_async_return(void* value, size_t size) {
|
||||||
|
if (bux_current_task != NULL && value != NULL && size > 0) {
|
||||||
|
void* copy = malloc(size);
|
||||||
|
if (copy) memcpy(copy, value, size);
|
||||||
|
bux_current_task->result = copy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* bux_async_result(void* handle) {
|
||||||
|
if (!handle) return NULL;
|
||||||
|
bux_async_task_t* task = (bux_async_task_t*)handle;
|
||||||
|
return task->result;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user