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:
Neels Hofmeyr 2016-12-23 04:26:39 +01:00 committed by Harald Welte
parent eeacf906dd
commit c014f606d0
2 changed files with 58 additions and 23 deletions

View File

@ -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);
/*! @} */

View File

@ -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),