summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fsm.c94
1 files changed, 64 insertions, 30 deletions
diff --git a/src/fsm.c b/src/fsm.c
index 0370f65e..b5af2e7a 100644
--- a/src/fsm.c
+++ b/src/fsm.c
@@ -429,33 +429,9 @@ const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state)
return fsm->states[state].name;
}
-/*! perform a state change of the given FSM instance
- *
- * Best invoke via the osmo_fsm_inst_state_chg() macro which logs the source
- * file where the state change was effected. Alternatively, you may pass \a
- * file as NULL to use the normal file/line indication instead.
- *
- * All changes to the FSM instance state must be made via this
- * function. It verifies that the existing state actually permits a
- * transiiton to new_state.
- *
- * timeout_secs and T are optional parameters, and only have any effect
- * if timeout_secs is not 0. If the timeout function is used, then the
- * new_state is entered, and the FSM instances timer is set to expire
- * in timeout_secs functions. At that time, the FSM's timer_cb
- * function will be called for handling of the timeout by the user.
- *
- * \param[in] fi FSM instance whose state is to change
- * \param[in] new_state The new state into which we should change
- * \param[in] timeout_secs Timeout in seconds (if !=0)
- * \param[in] T Timer number (if \ref timeout_secs != 0)
- * \param[in] file Calling source file (from osmo_fsm_inst_state_chg macro)
- * \param[in] line Calling source line (from osmo_fsm_inst_state_chg macro)
- * \returns 0 on success; negative on error
- */
-int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
- unsigned long timeout_secs, int T,
- const char *file, int line)
+static int state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
+ bool keep_timer, unsigned long timeout_secs, int T,
+ const char *file, int line)
{
struct osmo_fsm *fsm = fi->fsm;
uint32_t old_state = fi->state;
@@ -469,8 +445,10 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
return -EPERM;
}
- /* delete the old timer */
- osmo_timer_del(&fi->timer);
+ if (!keep_timer) {
+ /* delete the old timer */
+ osmo_timer_del(&fi->timer);
+ }
if (st->onleave)
st->onleave(fi, new_state);
@@ -480,7 +458,7 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
fi->state = new_state;
st = &fsm->states[new_state];
- if (timeout_secs) {
+ if (!keep_timer && timeout_secs) {
fi->T = T;
osmo_timer_schedule(&fi->timer, timeout_secs, 0);
}
@@ -492,6 +470,62 @@ int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
return 0;
}
+/*! perform a state change of the given FSM instance
+ *
+ * Best invoke via the osmo_fsm_inst_state_chg() macro which logs the source
+ * file where the state change was effected. Alternatively, you may pass \a
+ * file as NULL to use the normal file/line indication instead.
+ *
+ * All changes to the FSM instance state must be made via an osmo_fsm_inst_state_chg_*
+ * function. It verifies that the existing state actually permits a
+ * transition to new_state.
+ *
+ * timeout_secs and T are optional parameters, and only have any effect
+ * if timeout_secs is not 0. If the timeout function is used, then the
+ * new_state is entered, and the FSM instances timer is set to expire
+ * in timeout_secs functions. At that time, the FSM's timer_cb
+ * function will be called for handling of the timeout by the user.
+ *
+ * \param[in] fi FSM instance whose state is to change
+ * \param[in] new_state The new state into which we should change
+ * \param[in] timeout_secs Timeout in seconds (if !=0)
+ * \param[in] T Timer number (if \ref timeout_secs != 0)
+ * \param[in] file Calling source file (from osmo_fsm_inst_state_chg macro)
+ * \param[in] line Calling source line (from osmo_fsm_inst_state_chg macro)
+ * \returns 0 on success; negative on error
+ */
+int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
+ unsigned long timeout_secs, int T,
+ const char *file, int line)
+{
+ return state_chg(fi, new_state, false, timeout_secs, T, file, line);
+}
+
+/*! perform a state change while keeping the current timer running.
+ *
+ * This is useful to keep a timeout across several states (without having to round the
+ * remaining time to seconds).
+ *
+ * Best invoke via the osmo_fsm_inst_state_chg_keep_timer() macro which logs the source
+ * file where the state change was effected. Alternatively, you may pass \a
+ * file as NULL to use the normal file/line indication instead.
+ *
+ * All changes to the FSM instance state must be made via an osmo_fsm_inst_state_chg_*
+ * function. It verifies that the existing state actually permits a
+ * transition to new_state.
+ *
+ * \param[in] fi FSM instance whose state is to change
+ * \param[in] new_state The new state into which we should change
+ * \param[in] file Calling source file (from osmo_fsm_inst_state_chg macro)
+ * \param[in] line Calling source line (from osmo_fsm_inst_state_chg macro)
+ * \returns 0 on success; negative on error
+ */
+int _osmo_fsm_inst_state_chg_keep_timer(struct osmo_fsm_inst *fi, uint32_t new_state,
+ const char *file, int line)
+{
+ return state_chg(fi, new_state, true, 0, 0, file, line);
+}
+
/*! dispatch an event to an osmocom finite state machine instance
*
* Best invoke via the osmo_fsm_inst_dispatch() macro which logs the source