// Although in an unstable state, there is an initial implementation for error
// handling. Roughly speaking: if a component has failed then it cannot complete
// any current or future synchronous rounds anymore. Hence, apart from some edge
// cases, any received message by a peer should cause a failure at that peer as
// well. We may have a look at the various places where a component with respect
// to a peer that is receiving its messages
enum ErrorLocation {
BeforeSync,
DuringSyncBeforeFirstInteraction,
DuringSyncBeforeSecondInteraction,
DuringSyncAfterInteractions,
AfterSync,
}
func error_location_to_string(ErrorLocation loc) -> string {
if (let ErrorLocation::BeforeSync = loc) {
return "before sync";
} else if (let ErrorLocation::DuringSyncBeforeFirstInteraction = loc) {
return "during sync before first interaction";
} else if (let ErrorLocation::DuringSyncBeforeSecondInteraction = loc) {
return "during sync before second interaction";
} else if (let ErrorLocation::DuringSyncAfterInteractions = loc) {
return "during sync after interactions";
} else { return "after sync"; }
}
func crash() -> u8 {
return {}[0]; // access index 1 of an empty array
}
comp sender_and_crasher(out<u32> value, ErrorLocation loc) {
print("sender: will crash " @ error_location_to_string(loc));
if (loc == ErrorLocation::BeforeSync) { crash(); }
sync {
if (loc == ErrorLocation::DuringSyncBeforeFirstInteraction) { crash(); }
print("sender: sending first value");
put(value, 0);
if (loc == ErrorLocation::DuringSyncBeforeSecondInteraction) { crash(); }
print("sender: sending second value");
put(value, 1);
if (loc == ErrorLocation::DuringSyncAfterInteractions) { crash(); }
}
if (loc == ErrorLocation::AfterSync) { crash(); }
}
comp receiver(in<u32> value) {
sync {
auto a = get(value);
auto b = get(value);
}
}
// Note that when we run the example with the error location before sync, or
// during sync, that the receiver always crashes. However the location where it
// will crash is somewhat random! Due to the asynchronous nature of the runtime
// a sender of messages will always just `put` the value onto the port and
// continue execution. So even though the sender component might already be done
// with its sync round, the receiver officially still has to receive its first
// message. In any case, a neat error message should be displayed in the
// console.
//
// Note especially, given the asynchronous nature of the runtime, that the
// receiver should figure out when the peer component has crashed, but it can
// still finish the current synchronous round. This might happen if the peer
// component crashes *just* after the synchronous round. There may be a case
// where the peer receives the information that the peer crashed *before* it
// receives the information that the synchronous round has succeeded.
comp main() {
channel tx -> rx;
new sender_and_crasher(tx, ErrorLocation::AfterSync);
new receiver(rx);
}