* Suppress duplicate signals.
*
* For some reason on macOS we get multiple signals
- * for the same event (SIGTERM).
+ * for the same event (SIGINT).
*
* ...this also fixes the problem of the user hammering
* Ctrl-C and causing ungraceful exits as we try and
#endif
typedef enum {
- REQUEST_ACTIVE = 1,
- REQUEST_STOP_PROCESSING,
- REQUEST_COUNTED
+ REQUEST_ACTIVE = 1, //!< Request is active (running or runnable)
+ REQUEST_STOP_PROCESSING, //!< Request has been signalled to stop
+ REQUEST_DONE, //!< Request has completed
} request_master_state_t;
#define REQUEST_MASTER_NUM_STATES (REQUEST_COUNTED + 1)
char const *component; //!< Section the request is in.
char const *module; //!< Module the request is currently being processed by.
- fr_packet_t *packet; //!< Incoming request.
- fr_packet_t *reply; //!< Outgoing response.
+ fr_packet_t *packet; //!< Incoming request.
+ fr_packet_t *reply; //!< Outgoing response.
fr_client_t *client; //!< The client that originally sent us the request.
request_master_state_t master_state; //!< Set by the master thread to signal the child that's currently
//!< working with the request, to do something.
+ bool counted; //!< Set if the request has been counted in the stats.
rlm_rcode_t rcode; //!< Last rcode returned by a module
void request_stats_final(request_t *request)
{
- if (request->master_state == REQUEST_COUNTED) return;
+ if (request->counted) return;
#if 0
if (!request->listener) return;
break;
}
- request->master_state = REQUEST_COUNTED;
+ request->counted = true;
}
void radius_stats_init(int flag)
intp->funcs.done_detached(request, stack->result, intp->uctx); /* Callback will usually free the request */
break;
}
+
+ request->master_state = REQUEST_DONE;
}
static inline CC_HINT(always_inline)
return (request->master_state == REQUEST_STOP_PROCESSING);
}
+/** Return whether a request has been marked done
+ */
+bool unlang_request_is_done(request_t const *request)
+{
+ return (request->master_state == REQUEST_DONE);
+}
+
/** Check if a request as resumable.
*
* @param[in] request The current request.
bool unlang_request_is_cancelled(request_t const *request);
+bool unlang_request_is_done(request_t const *request);
+
void unlang_interpret_request_done(request_t *request);
void unlang_interpret_mark_runnable(request_t *request);
/** Send a signal from parent request to subrequest
*
*/
-static void unlang_subrequest_parent_signal(UNUSED request_t *request, unlang_stack_frame_t *frame,
- fr_signal_t action)
+static void unlang_subrequest_signal_child(UNUSED request_t *request, unlang_stack_frame_t *frame,
+ fr_signal_t action)
{
unlang_frame_state_subrequest_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_subrequest_t);
request_t *child = talloc_get_type_abort(state->child, request_t);
*/
fr_assert(action != FR_SIGNAL_DETACH);
+ /*
+ * If the server is stopped, inside a breakpoint,
+ * whilst processing a child, on resumption both
+ * requests (parent and child) may need to be
+ * cancelled as they've both hit max request_time.
+ *
+ * Sometimes the child will run to completion before
+ * the cancellation is processed, but the parent
+ * will still be cancelled.
+ *
+ * When the parent is cancelled this function is
+ * executed, which will signal an already stopped
+ * child to cancel itself.
+ *
+ * This triggers asserts in the time tracking code.
+ *
+ * ...so we check to see if the child is done before
+ * sending a signal.
+ */
+ if (unlang_request_is_done(child)) return;
+
/*
* Forward other signals to the child
*/
&(unlang_op_t){
.name = "subrequest",
.interpret = unlang_subrequest_parent_init,
- .signal = unlang_subrequest_parent_signal,
+ .signal = unlang_subrequest_signal_child,
.debug_braces = true,
.frame_state_size = sizeof(unlang_frame_state_subrequest_t),
.frame_state_type = "unlang_frame_state_subrequest_t",
FALL_THROUGH;
case FR_SIGNAL_CANCEL:
+ RDEBUG3("Removing subrequest from parent, and marking parent as runnable");
+
/*
* Indicate to the parent there's no longer a child
*/