Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 1 | #pragma once |
| 2 | |
| 3 | #include <stdint.h> |
| 4 | #include <stdbool.h> |
| 5 | |
| 6 | #include <osmocom/core/linuxlist.h> |
| 7 | #include <osmocom/core/timer.h> |
| 8 | #include <osmocom/core/utils.h> |
| 9 | |
| 10 | /*! \defgroup fsm Finite State Machine abstraction |
| 11 | * @{ |
| 12 | */ |
| 13 | |
| 14 | /*! \file fsm.h |
| 15 | * \brief Finite State Machine |
| 16 | */ |
| 17 | |
| 18 | struct osmo_fsm_inst; |
| 19 | |
| 20 | enum osmo_fsm_term_cause { |
| 21 | /*! \brief terminate because parent terminated */ |
| 22 | OSMO_FSM_TERM_PARENT, |
| 23 | /*! \brief terminate on explicit user request */ |
| 24 | OSMO_FSM_TERM_REQUEST, |
| 25 | /*! \brief regular termination of process */ |
| 26 | OSMO_FSM_TERM_REGULAR, |
| 27 | /*! \brief erroneous termination of process */ |
| 28 | OSMO_FSM_TERM_ERROR, |
Harald Welte | f627c0f | 2016-06-18 10:36:25 +0200 | [diff] [blame] | 29 | /*! \brief termination due to time-out */ |
| 30 | OSMO_FSM_TERM_TIMEOUT, |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 31 | }; |
| 32 | |
| 33 | /*! \brief description of a rule in the FSM */ |
| 34 | struct osmo_fsm_state { |
| 35 | /*! \brief bit-mask of permitted input events for this state */ |
| 36 | uint32_t in_event_mask; |
| 37 | /*! \brief bit-mask to which other states this state may transiton */ |
| 38 | uint32_t out_state_mask; |
| 39 | /*! \brief human-readable name of this state */ |
| 40 | const char *name; |
| 41 | /*! \brief function to be called for events arriving in this state */ |
| 42 | void (*action)(struct osmo_fsm_inst *fi, uint32_t event, void *data); |
| 43 | /*! \brief function to be called just after entering the state */ |
| 44 | void (*onenter)(struct osmo_fsm_inst *fi, uint32_t prev_state); |
| 45 | /*! \brief function to be called just before leaving the state */ |
| 46 | void (*onleave)(struct osmo_fsm_inst *fi, uint32_t next_state); |
| 47 | }; |
| 48 | |
| 49 | /*! \brief a description of an osmocom finite state machine */ |
| 50 | struct osmo_fsm { |
| 51 | /*! \brief global list */ |
| 52 | struct llist_head list; |
| 53 | /*! \brief list of instances of this FSM */ |
| 54 | struct llist_head instances; |
| 55 | /*! \brief human readable name */ |
| 56 | const char *name; |
| 57 | /*! \brief table of state transition rules */ |
| 58 | const struct osmo_fsm_state *states; |
| 59 | /*! \brief number of entries in \ref states */ |
| 60 | unsigned int num_states; |
| 61 | /*! \brief bit-mask of events permitted in all states */ |
| 62 | uint32_t allstate_event_mask; |
| 63 | /*! \brief function pointer to be called for allstate events */ |
| 64 | void (*allstate_action)(struct osmo_fsm_inst *fi, uint32_t event, void *data); |
| 65 | /*! \breif clean-up function, called during termination */ |
| 66 | void (*cleanup)(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause); |
| 67 | /*! \brief timer call-back for states with time-out */ |
Harald Welte | f627c0f | 2016-06-18 10:36:25 +0200 | [diff] [blame] | 68 | int (*timer_cb)(struct osmo_fsm_inst *fi); |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 69 | /*! \brief logging sub-system for this FSM */ |
| 70 | int log_subsys; |
| 71 | /*! \brief human-readable names of events */ |
| 72 | const struct value_string *event_names; |
| 73 | }; |
| 74 | |
| 75 | /*! \brief a single instanceof an osmocom finite state machine */ |
| 76 | struct osmo_fsm_inst { |
| 77 | /*! \brief member in the fsm->instances list */ |
| 78 | struct llist_head list; |
| 79 | /*! \brief back-pointer to the FSM of which we are an instance */ |
| 80 | struct osmo_fsm *fsm; |
| 81 | /*! \brief human readable identifier */ |
| 82 | const char *id; |
| 83 | /*! \brief human readable fully-qualified name */ |
| 84 | const char *name; |
| 85 | /*! \brief some private data of this instance */ |
| 86 | void *priv; |
| 87 | /*! \brief logging level for this FSM */ |
| 88 | int log_level; |
| 89 | /*! \brief current state of the FSM */ |
| 90 | uint32_t state; |
| 91 | |
| 92 | /*! \brief timer number for states with time-out */ |
| 93 | int T; |
| 94 | /*! \brief timer back-end for states with time-out */ |
| 95 | struct osmo_timer_list timer; |
| 96 | |
| 97 | /*! \brief support for fsm-based procedures */ |
| 98 | struct { |
| 99 | /*! \brief the parent FSM that has created us */ |
| 100 | struct osmo_fsm_inst *parent; |
| 101 | /*! \brief the event we should send upon termination */ |
| 102 | uint32_t parent_term_event; |
| 103 | /*! \brief a list of children processes */ |
| 104 | struct llist_head children; |
| 105 | /*! \brief \ref llist_head linked to parent->proc.children */ |
| 106 | struct llist_head child; |
| 107 | } proc; |
| 108 | }; |
| 109 | |
| 110 | void osmo_fsm_log_addr(bool log_addr); |
| 111 | |
| 112 | #define LOGPFSM(fi, fmt, args...) \ |
| 113 | LOGP((fi)->fsm->log_subsys, (fi)->log_level, "%s{%s}: " fmt, \ |
| 114 | osmo_fsm_inst_name(fi), \ |
| 115 | osmo_fsm_state_name((fi)->fsm, (fi)->state), ## args) |
| 116 | |
| 117 | int osmo_fsm_register(struct osmo_fsm *fsm); |
| 118 | |
| 119 | struct osmo_fsm_inst *osmo_fsm_inst_alloc(struct osmo_fsm *fsm, void *ctx, void *priv, |
| 120 | int log_level, const char *id); |
| 121 | struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm, |
| 122 | struct osmo_fsm_inst *parent, |
| 123 | uint32_t parent_term_event); |
| 124 | void osmo_fsm_inst_free(struct osmo_fsm_inst *fi); |
| 125 | |
| 126 | const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event); |
| 127 | const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi); |
| 128 | const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state); |
| 129 | |
| 130 | int osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state, |
| 131 | unsigned long timeout_secs, int T); |
| 132 | int osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data); |
| 133 | |
| 134 | void osmo_fsm_inst_term(struct osmo_fsm_inst *fi, |
| 135 | enum osmo_fsm_term_cause cause, void *data); |
| 136 | |
| 137 | /*! @} */ |