blob: 401ee04a18a1e58c310921047f2b8cf9c42c441f [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,
29};
30
31/*! \brief description of a rule in the FSM */
32struct osmo_fsm_state {
33 /*! \brief bit-mask of permitted input events for this state */
34 uint32_t in_event_mask;
35 /*! \brief bit-mask to which other states this state may transiton */
36 uint32_t out_state_mask;
37 /*! \brief human-readable name of this state */
38 const char *name;
39 /*! \brief function to be called for events arriving in this state */
40 void (*action)(struct osmo_fsm_inst *fi, uint32_t event, void *data);
41 /*! \brief function to be called just after entering the state */
42 void (*onenter)(struct osmo_fsm_inst *fi, uint32_t prev_state);
43 /*! \brief function to be called just before leaving the state */
44 void (*onleave)(struct osmo_fsm_inst *fi, uint32_t next_state);
45};
46
47/*! \brief a description of an osmocom finite state machine */
48struct osmo_fsm {
49 /*! \brief global list */
50 struct llist_head list;
51 /*! \brief list of instances of this FSM */
52 struct llist_head instances;
53 /*! \brief human readable name */
54 const char *name;
55 /*! \brief table of state transition rules */
56 const struct osmo_fsm_state *states;
57 /*! \brief number of entries in \ref states */
58 unsigned int num_states;
59 /*! \brief bit-mask of events permitted in all states */
60 uint32_t allstate_event_mask;
61 /*! \brief function pointer to be called for allstate events */
62 void (*allstate_action)(struct osmo_fsm_inst *fi, uint32_t event, void *data);
63 /*! \breif clean-up function, called during termination */
64 void (*cleanup)(struct osmo_fsm_inst *fi, enum osmo_fsm_term_cause cause);
65 /*! \brief timer call-back for states with time-out */
66 void (*timer_cb)(struct osmo_fsm_inst *fi);
67 /*! \brief logging sub-system for this FSM */
68 int log_subsys;
69 /*! \brief human-readable names of events */
70 const struct value_string *event_names;
71};
72
73/*! \brief a single instanceof an osmocom finite state machine */
74struct osmo_fsm_inst {
75 /*! \brief member in the fsm->instances list */
76 struct llist_head list;
77 /*! \brief back-pointer to the FSM of which we are an instance */
78 struct osmo_fsm *fsm;
79 /*! \brief human readable identifier */
80 const char *id;
81 /*! \brief human readable fully-qualified name */
82 const char *name;
83 /*! \brief some private data of this instance */
84 void *priv;
85 /*! \brief logging level for this FSM */
86 int log_level;
87 /*! \brief current state of the FSM */
88 uint32_t state;
89
90 /*! \brief timer number for states with time-out */
91 int T;
92 /*! \brief timer back-end for states with time-out */
93 struct osmo_timer_list timer;
94
95 /*! \brief support for fsm-based procedures */
96 struct {
97 /*! \brief the parent FSM that has created us */
98 struct osmo_fsm_inst *parent;
99 /*! \brief the event we should send upon termination */
100 uint32_t parent_term_event;
101 /*! \brief a list of children processes */
102 struct llist_head children;
103 /*! \brief \ref llist_head linked to parent->proc.children */
104 struct llist_head child;
105 } proc;
106};
107
108void osmo_fsm_log_addr(bool log_addr);
109
110#define LOGPFSM(fi, fmt, args...) \
111 LOGP((fi)->fsm->log_subsys, (fi)->log_level, "%s{%s}: " fmt, \
112 osmo_fsm_inst_name(fi), \
113 osmo_fsm_state_name((fi)->fsm, (fi)->state), ## args)
114
115int osmo_fsm_register(struct osmo_fsm *fsm);
116
117struct osmo_fsm_inst *osmo_fsm_inst_alloc(struct osmo_fsm *fsm, void *ctx, void *priv,
118 int log_level, const char *id);
119struct osmo_fsm_inst *osmo_fsm_inst_alloc_child(struct osmo_fsm *fsm,
120 struct osmo_fsm_inst *parent,
121 uint32_t parent_term_event);
122void osmo_fsm_inst_free(struct osmo_fsm_inst *fi);
123
124const char *osmo_fsm_event_name(struct osmo_fsm *fsm, uint32_t event);
125const char *osmo_fsm_inst_name(struct osmo_fsm_inst *fi);
126const char *osmo_fsm_state_name(struct osmo_fsm *fsm, uint32_t state);
127
128int osmo_fsm_inst_state_chg(struct osmo_fsm_inst *fi, uint32_t new_state,
129 unsigned long timeout_secs, int T);
130int osmo_fsm_inst_dispatch(struct osmo_fsm_inst *fi, uint32_t event, void *data);
131
132void osmo_fsm_inst_term(struct osmo_fsm_inst *fi,
133 enum osmo_fsm_term_cause cause, void *data);
134
135/*! @} */