diff options
author | Harald Welte <laforge@gnumonks.org> | 2016-05-29 10:53:17 +0900 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2016-06-16 21:43:45 +0000 |
commit | 136e73764e7f58e52ffb13d01304fef30eb7d291 (patch) | |
tree | 5854f45d44f793d6467e000b314c0789e7c1cccb /include/osmocom/core | |
parent | 82f94ef50f592c8c89b848e91b7cb84587ef8733 (diff) |
Add Finite State Machine abstraction code
This code is supposed to formalize some of the state machine handling in
Osmocom code.
Change-Id: I0b0965a912598c1f6b84042a99fea9d522642466
Reviewed-on: https://gerrit.osmocom.org/163
Tested-by: Jenkins Builder
Reviewed-by: Harald Welte <laforge@gnumonks.org>
Diffstat (limited to 'include/osmocom/core')
-rw-r--r-- | include/osmocom/core/fsm.h | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/include/osmocom/core/fsm.h b/include/osmocom/core/fsm.h new file mode 100644 index 00000000..401ee04a --- /dev/null +++ b/include/osmocom/core/fsm.h @@ -0,0 +1,135 @@ +#pragma once + +#include <stdint.h> +#include <stdbool.h> + +#include <osmocom/core/linuxlist.h> +#include <osmocom/core/timer.h> +#include <osmocom/core/utils.h> + +/*! \defgroup fsm Finite State Machine abstraction + * @{ + */ + +/*! \file fsm.h + * \brief Finite State Machine + */ + +struct osmo_fsm_inst; + +enum osmo_fsm_term_cause { + /*! \brief terminate because parent terminated */ + OSMO_FSM_TERM_PARENT, + /*! \brief terminate on explicit user request */ + OSMO_FSM_TERM_REQUEST, + /*! \brief regular termination of process */ + OSMO_FSM_TERM_REGULAR, + /*! \brief erroneous termination of process */ + OSMO_FSM_TERM_ERROR, +}; + +/*! \brief description of a rule in the FSM */ +struct osmo_fsm_state { + /*! \brief bit-mask of permitted input events for this state */ + uint32_t in_event_mask; + /*! \brief bit-mask to which other states this state may transiton */ + uint32_t out_state_mask; + /*! \brief human-readable name of this state */ + const char *name; + /*! \brief function to be called for events arriving in this state */ + void (*action)(struct osmo_fsm_inst *fi, uint32_t event, void *data); + /*! \brief function to be called just after entering the state */ + void (*onenter)(struct osmo_fsm_inst *fi, uint32_t prev_state); + /*! \brief function to be called just before leaving the state */ + void (*onleave)(struct osmo_fsm_inst *fi, uint32_t next_state); +}; + +/*! \brief a description of an osmocom finite state machine */ +struct osmo_fsm { + /*! \brief global list */ + struct llist_head list; + /*! \brief list of instances of this FSM */ + struct llist_head instances; + /*! \brief human readable name */ + const char *name; + /*! \brief table of state transition rules */ + const struct osmo_fsm_state *states; + /*! \brief number of entries in \ref states */ + unsigned int num_states; + /*! \brief bit-mask of events permitted in all states */ + uint32_t allstate_event_mask; + /*! \brief function pointer to be called for allstate events */ + void (*allstate_action)(struct osmo_fsm_inst *fi, uint32_t event, void *data); + /*! \breif clean-up function, called during termination */ + void (*cleanup)(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause); + /*! \brief timer call-back for states with time-out */ + void (*timer_cb)(struct osmo_fsm_inst *fi); + /*! \brief logging sub-system for this FSM */ + int log_subsys; + /*! \brief human-readable names of events */ + const struct value_string *event_names; +}; + +/*! \brief a single instanceof an osmocom finite state machine */ +struct osmo_fsm_inst { + /*! \brief member in the fsm->instances list */ + struct llist_head list; + /*! \brief back-pointer to the FSM of which we are an instance */ + struct osmo_fsm *fsm; + /*! \brief human readable identifier */ + const char *id; + /*! \brief human readable fully-qualified name */ + const char *name; + /*! \brief some private data of this instance */ + void *priv; + /*! \brief logging level for this FSM */ + int log_level; + /*! \brief current state of the FSM */ + uint32_t state; + + /*! \brief timer number for states with time-out */ + int T; + /*! \brief timer back-end for states with time-out */ + struct osmo_timer_list timer; + + /*! \brief support for fsm-based procedures */ + struct { + /*! \brief the parent FSM that has created us */ + struct osmo_fsm_inst *parent; + /*! \brief the event we should send upon termination */ + uint32_t parent_term_event; + /*! \brief a list of children processes */ + struct llist_head children; + /*! \brief \ref llist_head linked to parent->proc.children */ + struct llist_head child; + } proc; +}; + +void osmo_fsm_log_addr(bool log_addr); + +#define LOGPFSM(fi, fmt, args...) \ + LOGP((fi)->fsm->log_subsys, (fi)->log_level, "%s{%s}: " fmt, \ + osmo_fsm_inst_name(fi), \ + osmo_fsm_state_name((fi)->fsm, (fi)->state), ## args) + +int osmo_fsm_register(struct osmo_fsm *fsm); + +struct osmo_fsm_inst *osmo_fsm_inst_alloc(struct osmo_fsm *fsm, void *ctx, void *priv, + int log_level, const char *id); +struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm, + struct osmo_fsm_inst *parent, + uint32_t parent_term_event); +void osmo_fsm_inst_free(struct osmo_fsm_inst *fi); + +const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event); +const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi); +const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state); + +int osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state, + unsigned long timeout_secs, int T); +int osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data); + +void osmo_fsm_inst_term(struct osmo_fsm_inst *fi, + enum osmo_fsm_term_cause cause, void *data); + +/*! @} */ |