Skip to content

Commit

Permalink
Merge pull request #1307 from ziglang/cancel-semantics
Browse files Browse the repository at this point in the history
improved coroutine cancel semantics
  • Loading branch information
andrewrk committed Jul 30, 2018
2 parents 608ff52 + cfe03c7 commit 5d4a02c
Show file tree
Hide file tree
Showing 10 changed files with 486 additions and 142 deletions.
14 changes: 7 additions & 7 deletions doc/langref.html.in
Expand Up @@ -4665,24 +4665,24 @@ async fn testSuspendBlock() void {
block, while the old thread continued executing the suspend block.
</p>
<p>
However, if you use labeled <code>break</code> on the suspend block, the coroutine
However, the coroutine can be directly resumed from the suspend block, in which case it
never returns to its resumer and continues executing.
</p>
{#code_begin|test#}
const std = @import("std");
const assert = std.debug.assert;

test "break from suspend" {
test "resume from suspend" {
var buf: [500]u8 = undefined;
var a = &std.heap.FixedBufferAllocator.init(buf[0..]).allocator;
var my_result: i32 = 1;
const p = try async<a> testBreakFromSuspend(&my_result);
const p = try async<a> testResumeFromSuspend(&my_result);
cancel p;
std.debug.assert(my_result == 2);
}
async fn testBreakFromSuspend(my_result: *i32) void {
s: suspend |p| {
break :s;
async fn testResumeFromSuspend(my_result: *i32) void {
suspend |p| {
resume p;
}
my_result.* += 1;
suspend;
Expand Down Expand Up @@ -7336,7 +7336,7 @@ Defer(body) = ("defer" | "deferror") body

IfExpression(body) = "if" "(" Expression ")" body option("else" BlockExpression(body))

SuspendExpression(body) = option(Symbol ":") "suspend" option(("|" Symbol "|" body))
SuspendExpression(body) = "suspend" option(("|" Symbol "|" body))

IfErrorExpression(body) = "if" "(" Expression ")" option("|" option("*") Symbol "|") body "else" "|" Symbol "|" BlockExpression(body)

Expand Down
6 changes: 2 additions & 4 deletions src/all_types.hpp
Expand Up @@ -60,7 +60,7 @@ struct IrExecutable {
ZigList<Tld *> tld_list;

IrInstruction *coro_handle;
IrInstruction *coro_awaiter_field_ptr; // this one is shared and in the promise
IrInstruction *atomic_state_field_ptr; // this one is shared and in the promise
IrInstruction *coro_result_ptr_field_ptr;
IrInstruction *coro_result_field_ptr;
IrInstruction *await_handle_var_ptr; // this one is where we put the one we extracted from the promise
Expand Down Expand Up @@ -898,7 +898,6 @@ struct AstNodeAwaitExpr {
};

struct AstNodeSuspend {
Buf *name;
AstNode *block;
AstNode *promise_symbol;
};
Expand Down Expand Up @@ -1929,7 +1928,6 @@ struct ScopeLoop {
struct ScopeSuspend {
Scope base;

Buf *name;
IrBasicBlock *resume_block;
bool reported_err;
};
Expand Down Expand Up @@ -3245,7 +3243,7 @@ static const size_t stack_trace_ptr_count = 30;
#define RESULT_FIELD_NAME "result"
#define ASYNC_ALLOC_FIELD_NAME "allocFn"
#define ASYNC_FREE_FIELD_NAME "freeFn"
#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
#define ATOMIC_STATE_FIELD_NAME "atomic_state"
// these point to data belonging to the awaiter
#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
#define RESULT_PTR_FIELD_NAME "result_ptr"
Expand Down
14 changes: 9 additions & 5 deletions src/analyze.cpp
Expand Up @@ -161,7 +161,6 @@ ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent) {
assert(node->type == NodeTypeSuspend);
ScopeSuspend *scope = allocate<ScopeSuspend>(1);
init_scope(&scope->base, ScopeIdSuspend, node, parent);
scope->name = node->data.suspend.name;
return scope;
}

Expand Down Expand Up @@ -519,11 +518,11 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
return return_type->promise_frame_parent;
}

TypeTableEntry *awaiter_handle_type = get_optional_type(g, g->builtin_types.entry_promise);
TypeTableEntry *atomic_state_type = g->builtin_types.entry_usize;
TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);

ZigList<const char *> field_names = {};
field_names.append(AWAITER_HANDLE_FIELD_NAME);
field_names.append(ATOMIC_STATE_FIELD_NAME);
field_names.append(RESULT_FIELD_NAME);
field_names.append(RESULT_PTR_FIELD_NAME);
if (g->have_err_ret_tracing) {
Expand All @@ -533,7 +532,7 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
}

ZigList<TypeTableEntry *> field_types = {};
field_types.append(awaiter_handle_type);
field_types.append(atomic_state_type);
field_types.append(return_type);
field_types.append(result_ptr_type);
if (g->have_err_ret_tracing) {
Expand Down Expand Up @@ -6228,7 +6227,12 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
} else if (type_entry->id == TypeTableEntryIdOpaque) {
return 1;
} else {
return LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
uint32_t llvm_alignment = LLVMABIAlignmentOfType(g->target_data_ref, type_entry->type_ref);
// promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw
if (type_entry->id == TypeTableEntryIdPromise && llvm_alignment < 8) {
return 8;
}
return llvm_alignment;
}
}

Expand Down

0 comments on commit 5d4a02c

Please sign in to comment.