mirror of https://gerrit.osmocom.org/libosmocore
fsm: factor out osmo_fsm_inst_term_children() from osmo_fsm_inst_term()
osmo_fsm_inst_term() has code for safe child removal, publish that part as osmo_fsm_inst_term_children(); also use from osmo_fsm_inst_term(). As with osmo_fsm_inst_term(), add osmo_fsm_inst_term_children() macro to pass the caller's source file and line to new _osmo_fsm_inst_term_children(). Rationale: in openbsc's VLR, I want to discard child FSMs when certain events are handled. I could keep a pointer to each one, or simply iterate all children, making the code a lot simpler in some places. (Unfortunately, the patch may be displayed subobtimally. This really only moves the children-loop to a new function, replaces it with a call to _osmo_fsm_inst_term_children(fi, OSMO_FSM_TERM_PARENT, NULL, file, line) and drops two local iterator variables. No other code changes are made, even though the diff may show large removal + addition chunks) Change-Id: I8dac1206259cbd251660f793ad023aaa1dc705a2
This commit is contained in:
parent
eeacf906dd
commit
c014f606d0
|
@ -187,4 +187,17 @@ void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
|
|||
enum osmo_fsm_term_cause cause, void *data,
|
||||
const char *file, int line);
|
||||
|
||||
/*! \brief Terminate all child FSM instances of an FSM instance.
|
||||
*
|
||||
* This is a macro that calls _osmo_fsm_inst_term_children() with the given
|
||||
* parameters as well as the caller's source file and line number for logging
|
||||
* purposes. See there for documentation.
|
||||
*/
|
||||
#define osmo_fsm_inst_term_children(fi, cause, data) \
|
||||
_osmo_fsm_inst_term_children(fi, cause, data, __BASE_FILE__, __LINE__)
|
||||
void _osmo_fsm_inst_term_children(struct osmo_fsm_inst *fi,
|
||||
enum osmo_fsm_term_cause cause,
|
||||
void *data,
|
||||
const char *file, int line);
|
||||
|
||||
/*! @} */
|
||||
|
|
68
src/fsm.c
68
src/fsm.c
|
@ -421,35 +421,14 @@ void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
|
|||
enum osmo_fsm_term_cause cause, void *data,
|
||||
const char *file, int line)
|
||||
{
|
||||
struct osmo_fsm_inst *first_child, *last_seen_first_child;
|
||||
struct osmo_fsm_inst *parent = fi->proc.parent;
|
||||
uint32_t parent_term_event = fi->proc.parent_term_event;
|
||||
|
||||
LOGPFSMSRC(fi, file, line, "Terminating (cause = %s)\n",
|
||||
osmo_fsm_term_cause_name(cause));
|
||||
|
||||
/* iterate over all children, starting from the beginning every time:
|
||||
* terminating an FSM may emit events that cause other FSMs to also
|
||||
* terminate and remove themselves from this list. */
|
||||
last_seen_first_child = NULL;
|
||||
while (!llist_empty(&fi->proc.children)) {
|
||||
first_child = llist_entry(fi->proc.children.next,
|
||||
typeof(*first_child),
|
||||
proc.child);
|
||||
|
||||
/* paranoia: do not loop forever */
|
||||
if (first_child == last_seen_first_child) {
|
||||
LOGPFSMLSRC(fi, LOGL_ERROR, file, line,
|
||||
"Internal error while terminating child"
|
||||
" FSMs: a child FSM is stuck\n");
|
||||
break;
|
||||
}
|
||||
last_seen_first_child = first_child;
|
||||
|
||||
/* terminate child */
|
||||
_osmo_fsm_inst_term(first_child, OSMO_FSM_TERM_PARENT, NULL,
|
||||
file, line);
|
||||
}
|
||||
_osmo_fsm_inst_term_children(fi, OSMO_FSM_TERM_PARENT, NULL,
|
||||
file, line);
|
||||
|
||||
/* delete ourselves from the parent */
|
||||
if (parent)
|
||||
|
@ -470,6 +449,49 @@ void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
|
|||
file, line);
|
||||
}
|
||||
|
||||
/*! \brief Terminate all child FSM instances of an FSM instance.
|
||||
*
|
||||
* Iterate over all children and send them a termination event, with the given
|
||||
* cause. Pass OSMO_FSM_TERM_PARENT to avoid dispatching events from the
|
||||
* terminated child FSMs.
|
||||
*
|
||||
* \param[in] fi FSM instance that should be cleared of child FSMs
|
||||
* \param[in] cause Cause / reason for termination (OSMO_FSM_TERM_PARENT)
|
||||
* \param[in] data Opaque event data to be passed with the parent term events
|
||||
* \param[in] file Calling source file (from osmo_fsm_inst_term_children macro)
|
||||
* \param[in] line Calling source line (from osmo_fsm_inst_term_children macro)
|
||||
*/
|
||||
void _osmo_fsm_inst_term_children(struct osmo_fsm_inst *fi,
|
||||
enum osmo_fsm_term_cause cause,
|
||||
void *data,
|
||||
const char *file, int line)
|
||||
{
|
||||
struct osmo_fsm_inst *first_child, *last_seen_first_child;
|
||||
|
||||
/* iterate over all children, starting from the beginning every time:
|
||||
* terminating an FSM may emit events that cause other FSMs to also
|
||||
* terminate and remove themselves from this list. */
|
||||
last_seen_first_child = NULL;
|
||||
while (!llist_empty(&fi->proc.children)) {
|
||||
first_child = llist_entry(fi->proc.children.next,
|
||||
typeof(*first_child),
|
||||
proc.child);
|
||||
|
||||
/* paranoia: do not loop forever */
|
||||
if (first_child == last_seen_first_child) {
|
||||
LOGPFSMLSRC(fi, LOGL_ERROR, file, line,
|
||||
"Internal error while terminating child"
|
||||
" FSMs: a child FSM is stuck\n");
|
||||
break;
|
||||
}
|
||||
last_seen_first_child = first_child;
|
||||
|
||||
/* terminate child */
|
||||
_osmo_fsm_inst_term(first_child, cause, data,
|
||||
file, line);
|
||||
}
|
||||
}
|
||||
|
||||
const struct value_string osmo_fsm_term_cause_names[] = {
|
||||
OSMO_VALUE_STRING(OSMO_FSM_TERM_PARENT),
|
||||
OSMO_VALUE_STRING(OSMO_FSM_TERM_REQUEST),
|
||||
|
|
Loading…
Reference in New Issue