* There may be multiple resumption points in the
* stack, as modules can push xlats and function
* calls.
+ *
+ * Note: Slightly confusingly, a cancellation signal
+ * can still be delivered to a frame that is not
+ * cancellable, but the frame won't be automatically
+ * unwound.
*/
for (i = depth; i >= limit; i--) {
frame = &stack->frame[i];
switch (action) {
case FR_SIGNAL_CANCEL:
+ {
+ unlang_stack_frame_t *frame = &stack->frame[stack->depth];
/*
* Let anything that cares, know that the
* request was forcefully stopped.
/*
* If the request is yielded, mark it as runnable
+ *
+ * If the request was _not_ cancelled, it means
+ * it's not cancellable, and we need to let the
+ * request progress normally.
*/
- if (stack && is_yielded(&stack->frame[stack->depth]) && !unlang_request_is_scheduled(request)) {
+ if (stack && is_yielded(frame) && is_cancelled(frame) && !unlang_request_is_scheduled(request)) {
unlang_interpret_mark_runnable(request);
}
+ }
break;
case FR_SIGNAL_DETACH:
.name = "subrequest",
.interpret = unlang_subrequest_parent_init,
.signal = unlang_subrequest_signal_child,
- .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET,
+ /*
+ * Frame can't be cancelled, because children need to
+ * write out status to the parent. If we don't do this,
+ * then all children must be detachable and must detach
+ * so they don't try and write out status to a "done"
+ * parent.
+ *
+ * It's easier to allow the child/parent relationship
+ * to end normally so that non-detachable requests are
+ * guaranteed the parent still exists.
+ */
+ .flag = UNLANG_OP_FLAG_DEBUG_BRACES | UNLANG_OP_FLAG_RCODE_SET | UNLANG_OP_FLAG_NO_CANCEL,
.frame_state_size = sizeof(unlang_frame_state_subrequest_t),
.frame_state_type = "unlang_frame_state_subrequest_t",
});
UNLANG_OP_FLAG_DEBUG_BRACES = 0x01, //!< Print debug braces.
UNLANG_OP_FLAG_RCODE_SET = 0x02, //!< Set request->rcode to the result of this operation.
UNLANG_OP_FLAG_NO_CANCEL = 0x04, //!< Must not be cancelled.
+ ///< @Note Slightly confusingly, a cancellation signal
+ ///< can still be delivered to a frame that is not
+ ///< cancellable, but the frame won't be automatically
+ ///< unwound. This lets the frame know that cancellation
+ ///< is desired, but can be ignored.
UNLANG_OP_FLAG_BREAK_POINT = 0x08, //!< Break point.
UNLANG_OP_FLAG_RETURN_POINT = 0x10, //!< Return point.
UNLANG_OP_FLAG_CONTINUE_POINT = 0x20 //!< Continue point.