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); |
Neels Hofmeyr | dda5e79 | 2016-12-09 16:10:34 +0100 | [diff] [blame] | 67 | /*! \brief timer call-back for states with time-out. |
| 68 | * \returns 1 to request termination, 0 to keep running. */ |
Harald Welte | f627c0f | 2016-06-18 10:36:25 +0200 | [diff] [blame] | 69 | int (*timer_cb)(struct osmo_fsm_inst *fi); |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 70 | /*! \brief logging sub-system for this FSM */ |
| 71 | int log_subsys; |
| 72 | /*! \brief human-readable names of events */ |
| 73 | const struct value_string *event_names; |
| 74 | }; |
| 75 | |
| 76 | /*! \brief a single instanceof an osmocom finite state machine */ |
| 77 | struct osmo_fsm_inst { |
| 78 | /*! \brief member in the fsm->instances list */ |
| 79 | struct llist_head list; |
| 80 | /*! \brief back-pointer to the FSM of which we are an instance */ |
| 81 | struct osmo_fsm *fsm; |
| 82 | /*! \brief human readable identifier */ |
| 83 | const char *id; |
| 84 | /*! \brief human readable fully-qualified name */ |
| 85 | const char *name; |
| 86 | /*! \brief some private data of this instance */ |
| 87 | void *priv; |
| 88 | /*! \brief logging level for this FSM */ |
| 89 | int log_level; |
| 90 | /*! \brief current state of the FSM */ |
| 91 | uint32_t state; |
| 92 | |
| 93 | /*! \brief timer number for states with time-out */ |
| 94 | int T; |
| 95 | /*! \brief timer back-end for states with time-out */ |
| 96 | struct osmo_timer_list timer; |
| 97 | |
| 98 | /*! \brief support for fsm-based procedures */ |
| 99 | struct { |
| 100 | /*! \brief the parent FSM that has created us */ |
| 101 | struct osmo_fsm_inst *parent; |
| 102 | /*! \brief the event we should send upon termination */ |
| 103 | uint32_t parent_term_event; |
| 104 | /*! \brief a list of children processes */ |
| 105 | struct llist_head children; |
| 106 | /*! \brief \ref llist_head linked to parent->proc.children */ |
| 107 | struct llist_head child; |
| 108 | } proc; |
| 109 | }; |
| 110 | |
| 111 | void osmo_fsm_log_addr(bool log_addr); |
| 112 | |
Neels Hofmeyr | 6a13e7f | 2016-12-14 17:37:34 +0100 | [diff] [blame] | 113 | #define LOGPFSML(fi, level, fmt, args...) \ |
| 114 | LOGP((fi)->fsm->log_subsys, level, "%s{%s}: " fmt, \ |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 115 | osmo_fsm_inst_name(fi), \ |
| 116 | osmo_fsm_state_name((fi)->fsm, (fi)->state), ## args) |
| 117 | |
Neels Hofmeyr | 6a13e7f | 2016-12-14 17:37:34 +0100 | [diff] [blame] | 118 | #define LOGPFSM(fi, fmt, args...) \ |
| 119 | LOGPFSML(fi, (fi)->log_level, fmt, ## args) |
| 120 | |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 121 | int osmo_fsm_register(struct osmo_fsm *fsm); |
Max | 8b25a3f | 2016-11-01 11:02:17 +0100 | [diff] [blame] | 122 | void osmo_fsm_unregister(struct osmo_fsm *fsm); |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 123 | struct osmo_fsm_inst *osmo_fsm_inst_alloc(struct osmo_fsm *fsm, void *ctx, void *priv, |
| 124 | int log_level, const char *id); |
| 125 | struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm, |
| 126 | struct osmo_fsm_inst *parent, |
| 127 | uint32_t parent_term_event); |
| 128 | void osmo_fsm_inst_free(struct osmo_fsm_inst *fi); |
| 129 | |
| 130 | const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event); |
| 131 | const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi); |
| 132 | const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state); |
| 133 | |
Neels Hofmeyr | 725698a | 2016-12-14 17:24:54 +0100 | [diff] [blame^] | 134 | /*! \brief perform a state change of the given FSM instance |
| 135 | * |
| 136 | * This is a macro that calls _osmo_fsm_inst_state_chg() with the given |
| 137 | * parameters as well as the caller's source file and line number for logging |
| 138 | * purposes. See there for documentation. |
| 139 | */ |
| 140 | #define osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T) \ |
| 141 | _osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T, \ |
| 142 | __BASE_FILE__, __LINE__) |
| 143 | int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state, |
| 144 | unsigned long timeout_secs, int T, |
| 145 | const char *file, int line); |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 146 | |
Neels Hofmeyr | 725698a | 2016-12-14 17:24:54 +0100 | [diff] [blame^] | 147 | /*! \brief dispatch an event to an osmocom finite state machine instance |
| 148 | * |
| 149 | * This is a macro that calls _osmo_fsm_inst_dispatch() with the given |
| 150 | * parameters as well as the caller's source file and line number for logging |
| 151 | * purposes. See there for documentation. |
| 152 | */ |
| 153 | #define osmo_fsm_inst_dispatch(fi, event, data) \ |
| 154 | _osmo_fsm_inst_dispatch(fi, event, data, __BASE_FILE__, __LINE__) |
| 155 | int _osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data, |
| 156 | const char *file, int line); |
| 157 | |
| 158 | /*! \brief Terminate FSM instance with given cause |
| 159 | * |
| 160 | * This is a macro that calls _osmo_fsm_inst_term() with the given parameters |
| 161 | * as well as the caller's source file and line number for logging purposes. |
| 162 | * See there for documentation. |
| 163 | */ |
| 164 | #define osmo_fsm_inst_term(fi, cause, data) \ |
| 165 | _osmo_fsm_inst_term(fi, cause, data, __BASE_FILE__, __LINE__) |
| 166 | void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi, |
| 167 | enum osmo_fsm_term_cause cause, void *data, |
| 168 | const char *file, int line); |
Harald Welte | 136e737 | 2016-05-29 10:53:17 +0900 | [diff] [blame] | 169 | |
| 170 | /*! @} */ |