summaryrefslogtreecommitdiffstats
path: root/include/osmocom/core
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-05-29 10:53:17 +0900
committerHarald Welte <laforge@gnumonks.org>2016-06-16 21:43:45 +0000
commit136e73764e7f58e52ffb13d01304fef30eb7d291 (patch)
tree5854f45d44f793d6467e000b314c0789e7c1cccb /include/osmocom/core
parent82f94ef50f592c8c89b848e91b7cb84587ef8733 (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.h135
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);
+
+/*! @} */