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/fsm.h | |
| 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/fsm.h')
| -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); + +/*! @} */ | 
