blob: 952f82fa8ef032a7ccbbc9b7c239fde13bd43e56 [file] [log] [blame]
Harald Welte136e7372016-05-29 10:53:17 +09001#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
18struct osmo_fsm_inst;
19
20enum 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 Weltef627c0f2016-06-18 10:36:25 +020029 /*! \brief termination due to time-out */
30 OSMO_FSM_TERM_TIMEOUT,
Harald Welte136e7372016-05-29 10:53:17 +090031};
32
Neels Hofmeyr5c5c78a2016-12-14 18:35:47 +010033extern const struct value_string osmo_fsm_term_cause_names[];
34static inline const char *osmo_fsm_term_cause_name(enum osmo_fsm_term_cause cause)
35{
36 return get_value_string(osmo_fsm_term_cause_names, cause);
37}
38
39
Harald Welte136e7372016-05-29 10:53:17 +090040/*! \brief description of a rule in the FSM */
41struct osmo_fsm_state {
42 /*! \brief bit-mask of permitted input events for this state */
43 uint32_t in_event_mask;
44 /*! \brief bit-mask to which other states this state may transiton */
45 uint32_t out_state_mask;
46 /*! \brief human-readable name of this state */
47 const char *name;
48 /*! \brief function to be called for events arriving in this state */
49 void (*action)(struct osmo_fsm_inst *fi, uint32_t event, void *data);
50 /*! \brief function to be called just after entering the state */
51 void (*onenter)(struct osmo_fsm_inst *fi, uint32_t prev_state);
52 /*! \brief function to be called just before leaving the state */
53 void (*onleave)(struct osmo_fsm_inst *fi, uint32_t next_state);
54};
55
56/*! \brief a description of an osmocom finite state machine */
57struct osmo_fsm {
58 /*! \brief global list */
59 struct llist_head list;
60 /*! \brief list of instances of this FSM */
61 struct llist_head instances;
62 /*! \brief human readable name */
63 const char *name;
64 /*! \brief table of state transition rules */
65 const struct osmo_fsm_state *states;
66 /*! \brief number of entries in \ref states */
67 unsigned int num_states;
68 /*! \brief bit-mask of events permitted in all states */
69 uint32_t allstate_event_mask;
70 /*! \brief function pointer to be called for allstate events */
71 void (*allstate_action)(struct osmo_fsm_inst *fi, uint32_t event, void *data);
Neels Hofmeyr42b59c12016-12-20 12:06:05 +010072 /*! \brief clean-up function, called during termination */
Harald Welte136e7372016-05-29 10:53:17 +090073 void (*cleanup)(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause);
Neels Hofmeyrdda5e792016-12-09 16:10:34 +010074 /*! \brief timer call-back for states with time-out.
75 * \returns 1 to request termination, 0 to keep running. */
Harald Weltef627c0f2016-06-18 10:36:25 +020076 int (*timer_cb)(struct osmo_fsm_inst *fi);
Harald Welte136e7372016-05-29 10:53:17 +090077 /*! \brief logging sub-system for this FSM */
78 int log_subsys;
79 /*! \brief human-readable names of events */
80 const struct value_string *event_names;
81};
82
83/*! \brief a single instanceof an osmocom finite state machine */
84struct osmo_fsm_inst {
85 /*! \brief member in the fsm->instances list */
86 struct llist_head list;
87 /*! \brief back-pointer to the FSM of which we are an instance */
88 struct osmo_fsm *fsm;
89 /*! \brief human readable identifier */
90 const char *id;
91 /*! \brief human readable fully-qualified name */
92 const char *name;
93 /*! \brief some private data of this instance */
94 void *priv;
95 /*! \brief logging level for this FSM */
96 int log_level;
97 /*! \brief current state of the FSM */
98 uint32_t state;
99
100 /*! \brief timer number for states with time-out */
101 int T;
102 /*! \brief timer back-end for states with time-out */
103 struct osmo_timer_list timer;
104
105 /*! \brief support for fsm-based procedures */
106 struct {
107 /*! \brief the parent FSM that has created us */
108 struct osmo_fsm_inst *parent;
109 /*! \brief the event we should send upon termination */
110 uint32_t parent_term_event;
111 /*! \brief a list of children processes */
112 struct llist_head children;
113 /*! \brief \ref llist_head linked to parent->proc.children */
114 struct llist_head child;
115 } proc;
116};
117
118void osmo_fsm_log_addr(bool log_addr);
119
Neels Hofmeyr6a13e7f2016-12-14 17:37:34 +0100120#define LOGPFSML(fi, level, fmt, args...) \
121 LOGP((fi)->fsm->log_subsys, level, "%s{%s}: " fmt, \
Harald Welte136e7372016-05-29 10:53:17 +0900122 osmo_fsm_inst_name(fi), \
123 osmo_fsm_state_name((fi)->fsm, (fi)->state), ## args)
124
Neels Hofmeyr6a13e7f2016-12-14 17:37:34 +0100125#define LOGPFSM(fi, fmt, args...) \
126 LOGPFSML(fi, (fi)->log_level, fmt, ## args)
127
Neels Hofmeyreeacf902016-12-23 01:00:13 +0100128#define LOGPFSMLSRC(fi, level, caller_file, caller_line, fmt, args...) \
129 LOGPSRC((fi)->fsm->log_subsys, level, \
130 caller_file, caller_line, \
131 "%s{%s}: " fmt, \
132 osmo_fsm_inst_name(fi), \
133 osmo_fsm_state_name((fi)->fsm, (fi)->state), \
134 ## args)
135
136#define LOGPFSMSRC(fi, caller_file, caller_line, fmt, args...) \
137 LOGPFSMLSRC(fi, (fi)->log_level, \
138 caller_file, caller_line, \
139 fmt, ## args)
140
Harald Welte136e7372016-05-29 10:53:17 +0900141int osmo_fsm_register(struct osmo_fsm *fsm);
Max8b25a3f2016-11-01 11:02:17 +0100142void osmo_fsm_unregister(struct osmo_fsm *fsm);
Harald Welte8808bb42017-01-07 11:11:03 +0100143struct osmo_fsm *osmo_fsm_find_by_name(const char *name);
Harald Welte136e7372016-05-29 10:53:17 +0900144struct osmo_fsm_inst *osmo_fsm_inst_alloc(struct osmo_fsm *fsm, void *ctx, void *priv,
145 int log_level, const char *id);
146struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm,
147 struct osmo_fsm_inst *parent,
148 uint32_t parent_term_event);
149void osmo_fsm_inst_free(struct osmo_fsm_inst *fi);
150
151const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event);
152const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi);
153const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state);
154
Neels Hofmeyr725698a2016-12-14 17:24:54 +0100155/*! \brief perform a state change of the given FSM instance
156 *
157 * This is a macro that calls _osmo_fsm_inst_state_chg() with the given
158 * parameters as well as the caller's source file and line number for logging
159 * purposes. See there for documentation.
160 */
161#define osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T) \
162 _osmo_fsm_inst_state_chg(fi, new_state, timeout_secs, T, \
163 __BASE_FILE__, __LINE__)
164int _osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
165 unsigned long timeout_secs, int T,
166 const char *file, int line);
Harald Welte136e7372016-05-29 10:53:17 +0900167
Neels Hofmeyr725698a2016-12-14 17:24:54 +0100168/*! \brief dispatch an event to an osmocom finite state machine instance
169 *
170 * This is a macro that calls _osmo_fsm_inst_dispatch() with the given
171 * parameters as well as the caller's source file and line number for logging
172 * purposes. See there for documentation.
173 */
174#define osmo_fsm_inst_dispatch(fi, event, data) \
175 _osmo_fsm_inst_dispatch(fi, event, data, __BASE_FILE__, __LINE__)
176int _osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data,
177 const char *file, int line);
178
179/*! \brief Terminate FSM instance with given cause
180 *
181 * This is a macro that calls _osmo_fsm_inst_term() with the given parameters
182 * as well as the caller's source file and line number for logging purposes.
183 * See there for documentation.
184 */
185#define osmo_fsm_inst_term(fi, cause, data) \
186 _osmo_fsm_inst_term(fi, cause, data, __BASE_FILE__, __LINE__)
187void _osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
188 enum osmo_fsm_term_cause cause, void *data,
189 const char *file, int line);
Harald Welte136e7372016-05-29 10:53:17 +0900190
Neels Hofmeyrc014f602016-12-23 04:26:39 +0100191/*! \brief Terminate all child FSM instances of an FSM instance.
192 *
193 * This is a macro that calls _osmo_fsm_inst_term_children() with the given
194 * parameters as well as the caller's source file and line number for logging
195 * purposes. See there for documentation.
196 */
197#define osmo_fsm_inst_term_children(fi, cause, data) \
198 _osmo_fsm_inst_term_children(fi, cause, data, __BASE_FILE__, __LINE__)
199void _osmo_fsm_inst_term_children(struct osmo_fsm_inst *fi,
200 enum osmo_fsm_term_cause cause,
201 void *data,
202 const char *file, int line);
203
Harald Welte136e7372016-05-29 10:53:17 +0900204/*! @} */