REXDENT();
}
+static char *stack_unwind_flag_dump(uint8_t unwind)
+{
+ static __thread char buf[256];
+ size_t len;
+
+#define UNWIND_FLAG_DUMP(attrib) \
+ if (unwind & attrib) strcat(buf, #attrib" ");
+
+ snprintf(buf, sizeof(buf), "unwind=0x%x (", unwind);
+
+ UNWIND_FLAG_DUMP(UNWIND_FLAG_TOP_FRAME);
+ UNWIND_FLAG_DUMP(UNWIND_FLAG_BREAK_POINT);
+ UNWIND_FLAG_DUMP(UNWIND_FLAG_RETURN_POINT);
+
+ len = strlen(buf);
+ if (buf[len - 1] == ' ') buf[len - 1] = '\0'; /* Trim trailing space */
+ strcat(buf, ")");
+
+#undef UNWIND_FLAG_DUMP
+
+ return buf;
+}
+
static void stack_dump(request_t *request)
{
int i;
unlang_stack_t *stack = request->stack;
- RDEBUG2("----- Begin stack debug [depth %i, unwind %i] -----", stack->depth, stack->unwind);
+ RDEBUG2("----- Begin stack debug [depth %i, %s] -----", stack->depth, stack_unwind_flag_dump(stack->unwind));
for (i = stack->depth; i >= 0; i--) {
unlang_stack_frame_t *frame = &stack->frame[i];
RDEBUG2("[%d] Frame contents", i);
frame_dump(request, frame);
}
-
- RDEBUG2("----- End stack debug [depth %i, unwind %i] -------", stack->depth, stack->unwind);
+ RDEBUG2("----- End stack debug [depth %i, %s] -------", stack->depth, stack_unwind_flag_dump(stack->unwind));
}
#define DUMP_STACK if (DEBUG_ENABLED5) stack_dump(request)
#else
repeatable_clear(frame);
ua = frame->process(result, request, frame);
+ /*
+ * If this frame is breaking or returning
+ * frame then clear that unwind flag,
+ * it's been consumed by this call.
+ *
+ * We leave the unwind flags for the eval
+ * call so that the process function knows
+ * that the stack is being unwound.
+ */
+ if (is_break_point(frame)) {
+ stack_unwind_break_clear(stack);
+ stack_unwind_top_frame_clear(stack);
+ }
+ if (is_return_point(frame)) {
+ stack_unwind_return_clear(stack);
+ stack_unwind_top_frame_clear(stack);
+ }
+
RDEBUG4("** [%i] %s << %s (%d)", stack->depth, __FUNCTION__,
fr_table_str_by_value(unlang_action_table, ua, "<INVALID>"), *priority);
/*
* Head on back up the stack
*/
- frame_pop(stack);
+ frame_pop(request, stack);
frame = &stack->frame[stack->depth];
DUMP_STACK;
*/
void unlang_interpet_frame_discard(request_t *request)
{
- frame_pop(request->stack);
+ frame_pop(request, request->stack);
}
/** Set a specific interpreter for a request
return UNLANG_ACTION_UNWIND;
}
+static inline bool is_stack_unwinding_to_top_frame(unlang_stack_t *stack) { return stack->unwind & UNWIND_FLAG_TOP_FRAME; }
+static inline bool is_stack_unwinding_to_break(unlang_stack_t *stack) { return stack->unwind & UNWIND_FLAG_BREAK_POINT; }
+static inline bool is_stack_unwinding_to_return(unlang_stack_t *stack) { return stack->unwind & UNWIND_FLAG_RETURN_POINT; }
+static inline void stack_unwind_top_frame_clear(unlang_stack_t *stack) { stack->unwind &= ~UNWIND_FLAG_TOP_FRAME; }
+static inline void stack_unwind_break_clear(unlang_stack_t *stack) { stack->unwind &= ~UNWIND_FLAG_BREAK_POINT; }
+static inline void stack_unwind_return_clear(unlang_stack_t *stack) { stack->unwind &= ~UNWIND_FLAG_RETURN_POINT; }
+
static inline unlang_stack_frame_t *frame_current(request_t *request)
{
unlang_stack_t *stack = request->stack;
/** Pop a stack frame, removing any associated dynamically allocated state
*
+ * @param[in] request The current request.
* @param[in] stack frame to pop.
*/
-static inline void frame_pop(unlang_stack_t *stack)
+static inline void frame_pop(request_t *request, unlang_stack_t *stack)
{
unlang_stack_frame_t *frame;
frame = &stack->frame[--stack->depth];
- if (stack->unwind && is_repeatable(frame) && !is_break_point(frame) && !is_return_point(frame)) {
+ /*
+ * Signal the frame to get it back into a consistent state
+ * as we won't be calling the resume function.
+ */
+ if (stack->unwind && is_repeatable(frame) &&
+ ((is_stack_unwinding_to_break(stack) && !is_break_point(frame)) ||
+ (is_stack_unwinding_to_return(stack) && !is_return_point(frame)))) {
+ if (frame->signal) frame->signal(request, frame, FR_SIGNAL_CANCEL);
repeatable_clear(frame);
}
}