Motr  M0
State machine

Data Structures

struct  sm_call
 
struct  m0_sm
 
struct  m0_sm_conf
 
struct  m0_sm_state_descr
 
struct  m0_sm_trans_descr
 
struct  m0_sm_ast
 
struct  m0_sm_group
 
struct  m0_sm_timer
 
struct  m0_sm_timeout
 
struct  m0_sm_addb2_stats
 
struct  m0_sm_group_addb2
 
struct  m0_sm_ast_wait
 

Enumerations

enum  timer_state { INIT, ARMED, DONE }
 
enum  { M0_SM_MAX_STATES = 64 }
 
enum  m0_sm_state_descr_flags { M0_SDF_INITIAL = 1 << 0, M0_SDF_FAILURE = 1 << 1, M0_SDF_TERMINAL = 1 << 2, M0_SDF_FINAL = 1 << 3 }
 
enum  m0_sm_return { M0_SM_BREAK = -1 }
 

Functions

M0_INTERNAL void m0_sm_group_init (struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_group_fini (struct m0_sm_group *grp)
 
static void _sm_group_lock (struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_group_lock (struct m0_sm_group *grp)
 
static void _sm_group_unlock (struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_group_unlock (struct m0_sm_group *grp)
 
static bool grp_is_locked (const struct m0_sm_group *grp)
 
M0_INTERNAL bool m0_sm_group_is_locked (const struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_group_lock_rec (struct m0_sm_group *grp, bool runast)
 
M0_INTERNAL void m0_sm_group_unlock_rec (struct m0_sm_group *grp, bool runast)
 
M0_INTERNAL void m0_sm_ast_post (struct m0_sm_group *grp, struct m0_sm_ast *ast)
 
M0_INTERNAL void m0_sm_asts_run (struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_ast_cancel (struct m0_sm_group *grp, struct m0_sm_ast *ast)
 
static void sm_lock (struct m0_sm *mach)
 
static void sm_unlock (struct m0_sm *mach)
 
static bool sm_is_locked (const struct m0_sm *mach)
 
static bool state_is_valid (const struct m0_sm_conf *conf, uint32_t state)
 
static const struct m0_sm_state_descrstate_get (const struct m0_sm *mach, uint32_t state)
 
static const struct m0_sm_state_descrsm_state (const struct m0_sm *mach)
 
M0_INTERNAL bool sm_invariant0 (const struct m0_sm *mach)
 
M0_INTERNAL bool m0_sm_invariant (const struct m0_sm *mach)
 
static bool conf_invariant (const struct m0_sm_conf *conf)
 
M0_INTERNAL void m0_sm_init (struct m0_sm *mach, const struct m0_sm_conf *conf, uint32_t state, struct m0_sm_group *grp)
 
M0_INTERNAL void m0_sm_fini (struct m0_sm *mach)
 
M0_INTERNAL void m0_sm_conf_init (struct m0_sm_conf *conf)
 
M0_INTERNAL void m0_sm_conf_fini (struct m0_sm_conf *conf)
 
M0_INTERNAL bool m0_sm_conf_is_initialized (const struct m0_sm_conf *conf)
 
M0_INTERNAL int m0_sm_timedwait (struct m0_sm *mach, uint64_t states, m0_time_t deadline)
 
static void state_set (struct m0_sm *mach, int state, int32_t rc)
 
M0_INTERNAL void m0_sm_fail (struct m0_sm *mach, int fail_state, int32_t rc)
 
void m0_sm_state_set (struct m0_sm *mach, int state)
 
M0_INTERNAL void m0_sm_move (struct m0_sm *mach, int32_t rc, int state)
 
static unsigned long sm_timer_top (unsigned long data)
 
static void timer_done (struct m0_sm_timer *timer)
 
static void sm_timer_bottom (struct m0_sm_group *grp, struct m0_sm_ast *ast)
 
M0_INTERNAL void m0_sm_timer_init (struct m0_sm_timer *timer)
 
M0_INTERNAL void m0_sm_timer_fini (struct m0_sm_timer *timer)
 
M0_INTERNAL int m0_sm_timer_start (struct m0_sm_timer *timer, struct m0_sm_group *group, void(*cb)(struct m0_sm_timer *), m0_time_t deadline)
 
M0_INTERNAL void m0_sm_timer_cancel (struct m0_sm_timer *timer)
 
M0_INTERNAL bool m0_sm_timer_is_armed (const struct m0_sm_timer *timer)
 
static void timeout_ast (struct m0_sm_timer *timer)
 
static bool sm_timeout_cancel (struct m0_clink *link)
 
M0_INTERNAL void m0_sm_timeout_init (struct m0_sm_timeout *to)
 
M0_INTERNAL int m0_sm_timeout_arm (struct m0_sm *mach, struct m0_sm_timeout *to, m0_time_t timeout, int state, uint64_t bitmask)
 
M0_INTERNAL void m0_sm_timeout_fini (struct m0_sm_timeout *to)
 
M0_INTERNAL bool m0_sm_timeout_is_armed (const struct m0_sm_timeout *to)
 
static bool trans_exists (const struct m0_sm_conf *conf, uint32_t src, uint32_t tgt)
 
M0_INTERNAL void m0_sm_conf_trans_extend (const struct m0_sm_conf *base, struct m0_sm_conf *sub)
 
M0_INTERNAL void m0_sm_conf_extend (const struct m0_sm_state_descr *base, struct m0_sm_state_descr *sub, uint32_t nr)
 
M0_INTERNAL const char * m0_sm_conf_state_name (const struct m0_sm_conf *conf, int state)
 
M0_INTERNAL const char * m0_sm_state_name (const struct m0_sm *mach, int state)
 
static void sm_call_ast (struct m0_sm_group *grp, struct m0_sm_ast *ast)
 
int m0_sm_group_call (struct m0_sm_group *group, int(*cb)(void *), void *data)
 
static int sm_addb2_ctor (struct m0_sm_addb2_stats *stats, const struct m0_sm_conf *c)
 
static void sm_addb2_dtor (struct m0_sm_addb2_stats *stats, const struct m0_sm_conf *c)
 
M0_INTERNAL int m0_sm_addb2_init (struct m0_sm_conf *conf, uint64_t id, uint64_t counter)
 
M0_INTERNAL void m0_sm_addb2_fini (struct m0_sm_conf *conf)
 
static void sm_addb2_counter_init_add (struct m0_sm *sm)
 
M0_INTERNAL bool m0_sm_addb2_counter_init (struct m0_sm *sm)
 
M0_INTERNAL void m0_sm_ast_wait_init (struct m0_sm_ast_wait *wait, struct m0_mutex *ch_guard)
 
M0_INTERNAL void m0_sm_ast_wait_fini (struct m0_sm_ast_wait *wait)
 
M0_INTERNAL void m0_sm_ast_wait_prepare (struct m0_sm_ast_wait *wait, struct m0_clink *clink)
 
M0_INTERNAL void m0_sm_ast_wait_complete (struct m0_sm_ast_wait *wait, struct m0_clink *clink)
 
M0_INTERNAL void m0_sm_ast_wait_loop (struct m0_sm_ast_wait *wait, struct m0_clink *clink)
 
M0_INTERNAL void m0_sm_ast_wait (struct m0_sm_ast_wait *wait)
 
M0_INTERNAL void m0_sm_ast_wait_post (struct m0_sm_ast_wait *wait, struct m0_sm_group *grp, struct m0_sm_ast *ast)
 
M0_INTERNAL void m0_sm_ast_wait_signal (struct m0_sm_ast_wait *wait)
 
M0_INTERNAL void m0_sm_conf_print (const struct m0_sm_conf *conf)
 
M0_INTERNAL uint64_t m0_sm_id_get (const struct m0_sm *sm)
 

Variables

static struct m0_sm_ast eoq
 
M0_INTERNAL void(* m0_sm__conf_init )(const struct m0_sm_conf *conf) = NULL
 

Detailed Description

This modules defines interfaces to functionality common to typical non-blocking state machines extensively used by Motr.

The main difference between "state machine" (non-blocking) code and "threaded" (blocking) code is that the latter blocks waiting for some events while having some computational state stored in the "native" C language stack (in the form of automatic variables allocated across the call-chain). Because of this the thread must remain dedicated to the same threaded activity not only during actual "computation", when processor is actively used, but also for the duration of wait. In many circumstances this is too expensive, because threads are heavy objects.

Non-blocking code, on the other hand, packs all its state into a special data-structures before some potential blocking points and unpacks it after the event of interest occurs. This allows the same thread to be re-used for multiple non-blocking computations.

Which blocking points deserve packing-unpacking depends on circumstances. Long-term waits for network or storage communication are prime candidates for non-blocking handling. Memory accesses, which can incur blocking page faults in a user space process are probably too ubiquitous for this. Memory allocations and data-structure locks fall into an intermediate group.

This module defines data-structures and interfaces to handle common non-blocking state-machine functionality:

- state tracking and state transitions;

- concurrency;

- interaction between a state machine and external world (both
  non-blocking and threaded);

- accounting and statistics collection.

State and transitions.

State machine state is recorded in m0_sm::sm_state. This is supposed to be a relatively coarse-grained high level state, broadly determining state machine behaviour. An instance of m0_sm will typically be embedded into a larger structure containing fields fully determining state machine behaviour. Each state comes with a description. All descriptions for a particular state machine are packed into a m0_sm_conf::scf_state[] array.

State machine is transferred from one state to another by a call to m0_sm_state_set() (or its variant m0_sm_fail()) or via "chained" transitions, see below.

Concurrency.

State machine is a part of a state machine group (m0_sm_group). All state machines in a group use group's mutex to serialise their state transitions. One possible scenario is to have a group for all state machines associated with a given locality (m0_fom_locality). Alternatively a group-per-machine can be used.

Interaction.

The only "output" event that a state machine communicates to the external world is (from this module's point of view) its state transition. State transitions are announced on a per-machine channel (m0_sm::sm_chan). This mechanism works both for threaded and non-blocking event consumers. The formers use m0_sm_timedwait() to wait until the state machine reaches desirable state, the latter register a clink with m0_sm::sm_chan.

"Input" events cause state transitions. Typical examples of such events are: completion of a network or storage communication, timeout or a state transition in a different state machine. Such events often happen in "awkward" context: signal and interrupt handlers, timer call-backs and similar. Acquiring the group's mutex, necessary for state transition in such places is undesirable for multiple reasons:

- to avoid self-deadlock in a case where an interrupt or signal is
  serviced by a thread that already holds the mutex, the latter must be
  made "async-safe", which is quite expensive;

- implementation of a module that provides a call-back must take into
  account the possibility of the call-back blocking waiting for a
  mutex. This is also quite expensive;

- locking order dependencies arise between otherwise unrelated
  components;

- all these issues are exasperated in a situation where state transition
  must take additional locks, which it often does.

The solution to these problems comes from operating system kernels design, see the AST section below.

There are 2 ways to implement state machine input event processing:

- "external" state transition, where input event processing is done
  outside of state machine, and m0_sm_state_set() is called to record
  state change:
struct foo {
struct m0_sm f_sm;
...
};
void event_X(struct foo *f)
{
m0_sm_group_lock(f->f_sm.sm_grp);
process_X(f);
m0_sm_state_set(&f->f_sm, NEXT_STATE);
m0_sm_group_unlock(f->f_sm.sm_grp);
}
  - "chained" state transition, where event processing logic is encoded in
  m0_sm_state_descr::sd_in() methods and a call to m0_sm_state_set() causes
  actual event processing to happen:
int X_in(struct m0_sm *mach)
{
struct foo *f = container_of(mach, struct foo, f_sm);
// group lock is held.
process_X(f);
return NEXT_STATE;
}
const struct m0_sm_conf foo_sm_conf = {
...
.scf_state = foo_sm_states
};
struct m0_sm_state_descr foo_sm_states[] = {
...
[STATE_X] = {
...
.sd_in = X_in
},
...
};
void event_X(struct foo *f)
{
m0_sm_group_lock(f->f_sm.sm_grp);
// this calls X_in() and goes through the chain of state transitions.
m0_sm_state_set(&f->f_sm, STATE_X);
m0_sm_group_unlock(f->f_sm.sm_grp);
}

Accounting and statistics.

This module accumulates statistics about state transitions and time spent in particular states. Statistics are reported through m0_sm_addb2_stats structure, associated with the state machine.

AST.

Asynchronous System Trap (AST) is a mechanism that allows a code running in an "awkward context" (see above) to post a call-back to be executed at the "base level" under a group mutex. UNIX kernels traditionally used a similar mechanism, where an interrupt handler does little more than setting a flag and returning. This flag is checked when the kernel is just about to return to the user space. If the flag is set, the rest of interrupt processing happens. In Linux a similar mechanism is called a "top-half" and "bottom-half" of interrupt processing. In Windows it is a DPC (http://en.wikipedia.org/wiki/Deferred_Procedure_Call) mechanism, in older DEC kernels it was called a "fork queue".

m0_sm_ast structure represents a call-back to be invoked under group mutex. An ast is "posted" to a state machine group by a call to m0_sm_ast_post(), which can be done in any context, in the sense that it doesn't take any locks. Posted asts are executed

- just after group mutex is taken;

- just before group mutex is released;

- whenever m0_sm_asts_run() is called.

Ast mechanism solves the problems with input events mentioned above at the expense of

- an increased latency: the call-back is not executed immediately;

- an additional burden of ast-related book-keeping: it is up to the ast
  user to free ast structure when it is safe to do so (i.e., after the
  ast completed execution).

To deal with the latency problem, a user must arrange m0_sm_asts_run() to be called during long state transitions (typically within loops).

There are a few ways to deal with the ast book-keeping problem:

- majority of asts will be embedded in some longer living data-structures
  like foms and won't need separate allocation of freeing;

- some ast users might allocate asts dynamically;

- the users which have neither a long-living data-structure to embed ast
  in nor can call dynamic allocator, have to pre-allocate a pool of asts
  and to guarantee somehow that it is never exhausted.

If an ast is posted a m0_sm_group::s_clink clink is signalled. A user managing a state machine group might arrange a special "ast" thread (or a group of threads) to wait on this channel and to call m0_sm_asts_run() when the channel is signalled:

A special "ast" thread is not needed if there is an always running "worker" thread or pool of threads associated with the state machine group. In the latter case, the worker thread can wait on m0_sm_group::s_clink in addition to other channels it waits on (see m0_clink_attach()).

m0_sm_group_init() initialises m0_sm_group::s_clink with a NULL call-back. If a user wants to re-initialise it with a different call-back or to attach it to a clink group, it should call m0_clink_fini() followed by m0_clink_init() or m0_link_attach() before any state machine is created in the group.

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
M0_SM_MAX_STATES 

Definition at line 366 of file sm.h.

◆ m0_sm_return

Enumerator
M0_SM_BREAK 

Negative mumbers are used to return from state function without transitioning to next state.

Definition at line 735 of file sm.h.

◆ m0_sm_state_descr_flags

Flags for state classification, used in m0_sm_state_descr::sd_flags.

Enumerator
M0_SDF_INITIAL 

An initial state.

State machine, must start execution in a state marked with this flag. Multiple states can be marked with this flag, for example, to share a code between similar state machines, that only differ in initial conditions.

See also
m0_sm_init()
M0_SDF_FAILURE 

A state marked with this flag is a failure state. m0_sm::sm_rc is set to a non-zero value on entering this state.

In a such state, state machine is supposed to handle or report the error indicated by m0_sm::sm_rc. Typically (but not necessary), the state machine will transit into am M0_SDF_TERMINAL state immediately after a failure state.

See also
m0_sm_fail()
M0_SDF_TERMINAL 

A state marked with this flag is a terminal state. No transitions out of this state are allowed (checked by m0_sm_conf_invariant()) and an attempt to wait for a state transition, while the state machine is in a terminal state, immediately returns -ESRCH.

See also
m0_sm_timedwait()
M0_SDF_FINAL 

A state marked with this flag is a "final" state. State machine can be finalised iff it is in state marked as M0_SDF_FINAL or M0_SDF_TERMINAL. There can be multiple states marked as M0_SDF_FINAL. M0_SDF_FINAL differs from M0_SDF_TERMINAL in that, state machine can transition out of a final state.

Definition at line 439 of file sm.h.

◆ timer_state

m0_sm_timer state machine

*                              INIT
*                                 |
*                         +-----+ | m0_sm_timer_start()
*          sm_timer_top() |     | |
*                         |     V V
*                         +----ARMED
*                               | |
*          m0_sm_timer_cancel() | | sm_timer_bottom()
*                               | |
*                               V V
*                               DONE
* 
Enumerator
INIT 
ARMED 
DONE 

Definition at line 508 of file sm.c.

Function Documentation

◆ _sm_group_lock()

static void _sm_group_lock ( struct m0_sm_group grp)
static

Definition at line 76 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _sm_group_unlock()

static void _sm_group_unlock ( struct m0_sm_group grp)
static

Definition at line 89 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ conf_invariant()

static bool conf_invariant ( const struct m0_sm_conf conf)
static

Definition at line 274 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ grp_is_locked()

static bool grp_is_locked ( const struct m0_sm_group grp)
static

Definition at line 102 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_addb2_counter_init()

M0_INTERNAL bool m0_sm_addb2_counter_init ( struct m0_sm sm)

Definition at line 891 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_addb2_fini()

M0_INTERNAL void m0_sm_addb2_fini ( struct m0_sm_conf conf)

Definition at line 870 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_addb2_init()

M0_INTERNAL int m0_sm_addb2_init ( struct m0_sm_conf conf,
uint64_t  id,
uint64_t  counter 
)

Definition at line 846 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_cancel()

M0_INTERNAL void m0_sm_ast_cancel ( struct m0_sm_group grp,
struct m0_sm_ast ast 
)

Cancels a posted AST.

If the AST has already been executed, nothing is done.

Postcondition
ast->sa_next == NULL

Definition at line 183 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_post()

M0_INTERNAL void m0_sm_ast_post ( struct m0_sm_group grp,
struct m0_sm_ast ast 
)

Posts an AST to a group.

An AST must not be re-posted until its previous (already posted) execution completes.

Definition at line 135 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_ast_wait()

M0_INTERNAL void m0_sm_ast_wait ( struct m0_sm_ast_wait wait)

Waits until all m0_sm_ast_wait_post()ed ASTs are executed.

Precondition
m0_chan_is_locked(&wait->aw_chan)

Definition at line 950 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_complete()

M0_INTERNAL void m0_sm_ast_wait_complete ( struct m0_sm_ast_wait wait,
struct m0_clink clink 
)

Definition at line 935 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_fini()

M0_INTERNAL void m0_sm_ast_wait_fini ( struct m0_sm_ast_wait wait)

Definition at line 910 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_init()

M0_INTERNAL void m0_sm_ast_wait_init ( struct m0_sm_ast_wait wait,
struct m0_mutex ch_guard 
)

Definition at line 903 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_loop()

M0_INTERNAL void m0_sm_ast_wait_loop ( struct m0_sm_ast_wait wait,
struct m0_clink clink 
)

Definition at line 942 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_post()

M0_INTERNAL void m0_sm_ast_wait_post ( struct m0_sm_ast_wait wait,
struct m0_sm_group grp,
struct m0_sm_ast ast 
)

Posts an AST that might be waited for.

Note
ast->sa_cb must call m0_sm_ast_wait_signal() as its last action.

Definition at line 961 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_prepare()

M0_INTERNAL void m0_sm_ast_wait_prepare ( struct m0_sm_ast_wait wait,
struct m0_clink clink 
)

Definition at line 917 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_ast_wait_signal()

M0_INTERNAL void m0_sm_ast_wait_signal ( struct m0_sm_ast_wait wait)

Signifies completion of an AST, posted with m0_sm_ast_wait_post().

Precondition
m0_chan_is_locked(&wait->aw_chan)

Definition at line 985 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_asts_run()

M0_INTERNAL void m0_sm_asts_run ( struct m0_sm_group grp)

Runs posted, but not yet executed ASTs.

Precondition
m0_mutex_is_locked(&grp->s_lock)
Postcondition
m0_mutex_is_locked(&grp->s_lock)

Definition at line 150 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_conf_extend()

M0_INTERNAL void m0_sm_conf_extend ( const struct m0_sm_state_descr base,
struct m0_sm_state_descr sub,
uint32_t  nr 
)

"Extends" base state descriptions with the given sub descriptions.

Updates sub in place to become a merged state machine descriptions array that uses base state descriptors, unless overridden by sub.

Definition at line 763 of file sm.c.

Here is the caller graph for this function:

◆ m0_sm_conf_fini()

M0_INTERNAL void m0_sm_conf_fini ( struct m0_sm_conf conf)

Finalises state machine configuration.

See also
m0_addb_rec_type_umregister()
Precondition
conf->scf_magic == M0_SM_CONF_MAGIC

Definition at line 376 of file sm.c.

Here is the caller graph for this function:

◆ m0_sm_conf_init()

M0_INTERNAL void m0_sm_conf_init ( struct m0_sm_conf conf)

Initialises state machine configuration.

Traverses transitions description array and constructs m0_sm_state_descr::sd_trans transitions map array for each state. It also makes sure (asserts) that transitions configuration in transitions description array matches with the same at states description array according to m0_sm_state_descr::sd_allowed flags.

Precondition
!m0_sm_conf_is_initialized(conf)
conf->scf_trans_nr > 0

Definition at line 340 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_conf_is_initialized()

M0_INTERNAL bool m0_sm_conf_is_initialized ( const struct m0_sm_conf conf)

Returns true if sm configuration was initialized already.

Definition at line 382 of file sm.c.

Here is the caller graph for this function:

◆ m0_sm_conf_print()

M0_INTERNAL void m0_sm_conf_print ( const struct m0_sm_conf conf)

Outputs the dot-language description of the configuration to the console.

Definition at line 993 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_conf_state_name()

M0_INTERNAL const char * m0_sm_conf_state_name ( const struct m0_sm_conf conf,
int  state 
)

Definition at line 774 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_conf_trans_extend()

M0_INTERNAL void m0_sm_conf_trans_extend ( const struct m0_sm_conf base,
struct m0_sm_conf sub 
)

Extends transition table of "base" with new transitions from "sub".

Resulting table is stored in "sub", which should be of sufficient size. Transitions in "sub" override matching transitions in "base".

sub->scf_trans[] reserves array elements for base. Empty slots in sub->scf_trans[] could be in arbitrary places.

Definition at line 726 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_fail()

M0_INTERNAL void m0_sm_fail ( struct m0_sm mach,
int  fail_state,
int32_t  rc 
)

Moves a state machine into fail_state state atomically with setting rc code.

Precondition
rc != 0
m0_mutex_is_locked(&mach->sm_grp->s_lock)
mach->sm_rc == 0
mach->sm_conf->scf_state[fail_state].sd_flags & M0_SDF_FAILURE
Postcondition
mach->sm_rc == rc
mach->sm_state == fail_state
m0_mutex_is_locked(&mach->sm_grp->s_lock)

Definition at line 468 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_fini()

M0_INTERNAL void m0_sm_fini ( struct m0_sm mach)

Finalises a state machine.

Precondition
conf->scf_state[state].sd_flags & (M0_SDF_TERMINAL | M0_SDF_FINAL)

Definition at line 331 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_group_call()

int m0_sm_group_call ( struct m0_sm_group group,
int(*)(void *)  cb,
void *  data 
)

Definition at line 801 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_group_fini()

M0_INTERNAL void m0_sm_group_fini ( struct m0_sm_group grp)

Definition at line 65 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_group_init()

M0_INTERNAL void m0_sm_group_init ( struct m0_sm_group grp)

Definition at line 53 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_group_is_locked()

M0_INTERNAL bool m0_sm_group_is_locked ( const struct m0_sm_group grp)

Definition at line 107 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_group_lock()

M0_INTERNAL void m0_sm_group_lock ( struct m0_sm_group grp)

Definition at line 83 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_group_lock_rec()

M0_INTERNAL void m0_sm_group_lock_rec ( struct m0_sm_group grp,
bool  runast 
)

Definition at line 112 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_group_unlock()

M0_INTERNAL void m0_sm_group_unlock ( struct m0_sm_group grp)

Definition at line 96 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_group_unlock_rec()

M0_INTERNAL void m0_sm_group_unlock_rec ( struct m0_sm_group grp,
bool  runast 
)

Definition at line 123 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_id_get()

M0_INTERNAL uint64_t m0_sm_id_get ( const struct m0_sm sm)
Returns
given SM identifier.

Definition at line 1021 of file sm.c.

Here is the caller graph for this function:

◆ m0_sm_init()

M0_INTERNAL void m0_sm_init ( struct m0_sm mach,
const struct m0_sm_conf conf,
uint32_t  state,
struct m0_sm_group grp 
)

Initialises a state machine.

Precondition
conf->scf_state[state].sd_flags & M0_SDF_INITIAL

Definition at line 313 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_invariant()

M0_INTERNAL bool m0_sm_invariant ( const struct m0_sm mach)

Definition at line 267 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_move()

M0_INTERNAL void m0_sm_move ( struct m0_sm mach,
int32_t  rc,
int  state 
)

Moves a state machine into the next state, calling either m0_sm_state_set() or m0_sm_fail() depending on "rc".

Definition at line 485 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_state_name()

M0_INTERNAL const char * m0_sm_state_name ( const struct m0_sm mach,
int  state 
)

Get human readable name (m0_sm_state_descr::sd_name) for the given state

Definition at line 781 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_state_set()

void m0_sm_state_set ( struct m0_sm mach,
int  state 
)

Transits a state machine into the indicated state.

Calls ex- and in- methods of the corresponding states (even if the state doesn't change after all).

The (mach->sm_state == state) post-condition cannot be asserted, because of chained state transitions.

Updates m0_sm_state_stats::smss_times statistics for the current state and sets the m0_sm::sm_state_epoch for the next state.

Precondition
m0_mutex_is_locked(&mach->sm_grp->s_lock)
Postcondition
m0_mutex_is_locked(&mach->sm_grp->s_lock)

Definition at line 478 of file sm.c.

Here is the call graph for this function:

◆ m0_sm_timedwait()

M0_INTERNAL int m0_sm_timedwait ( struct m0_sm mach,
uint64_t  states,
m0_time_t  deadline 
)

Waits until a given state machine enters any of states enumerated by a given bit-mask.

Return values
0- one of the states reached
-ESRCH- terminal state reached, see m0_sm_state_descr_flags::M0_SDF_TERMINAL
-ETIMEDOUT- deadline passed

In case where multiple wait termination conditions hold simultaneously (e.g., includes a terminal state), the result is implementation dependent.

Note
this interface assumes that states are numbered by numbers less than 64.

Definition at line 387 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timeout_arm()

M0_INTERNAL int m0_sm_timeout_arm ( struct m0_sm mach,
struct m0_sm_timeout to,
m0_time_t  timeout,
int  state,
uint64_t  bitmask 
)

Arms a timer to move a machine into a given state after a given timeout.

If a state transition happens before the timeout expires, the timeout is cancelled, unless the transition is to a state from "bitmask" parameter.

It is possible to arm multiple timeouts against the same state machine.

The m0_sm_timeout instance, supplied to this call can be freed after timeout expires or is cancelled.

Parameters
timeoutabsolute time at which the state transition will take place
statethe state to which the state machine will transition after the timeout.
bitmaska mask of state machine states, transitions which won't cancel the timeout.
Precondition
m0_mutex_is_locked(&mach->sm_grp->s_lock)
sm_state(mach)->sd_allowed & M0_BITS(state)
m0_forall(i, mach->sm_conf->scf_nr_states, ergo(M0_BITS(i) & bitmask, state_get(mach, i)->sd_allowed & M0_BITS(state)))
Postcondition
m0_mutex_is_locked(&mach->sm_grp->s_lock)

Definition at line 674 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timeout_fini()

M0_INTERNAL void m0_sm_timeout_fini ( struct m0_sm_timeout to)

Finaliser that must be called before can be freed.

Definition at line 705 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timeout_init()

M0_INTERNAL void m0_sm_timeout_init ( struct m0_sm_timeout to)

Initialises a timer structure with a given timeout.

Definition at line 667 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timeout_is_armed()

M0_INTERNAL bool m0_sm_timeout_is_armed ( const struct m0_sm_timeout to)

Returns true iff timer associated with the timeout is running.

Definition at line 713 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timer_cancel()

M0_INTERNAL void m0_sm_timer_cancel ( struct m0_sm_timer timer)

Definition at line 610 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timer_fini()

M0_INTERNAL void m0_sm_timer_fini ( struct m0_sm_timer timer)

Definition at line 566 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timer_init()

M0_INTERNAL void m0_sm_timer_init ( struct m0_sm_timer timer)

Definition at line 559 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ m0_sm_timer_is_armed()

M0_INTERNAL bool m0_sm_timer_is_armed ( const struct m0_sm_timer timer)

Definition at line 628 of file sm.c.

Here is the caller graph for this function:

◆ m0_sm_timer_start()

M0_INTERNAL int m0_sm_timer_start ( struct m0_sm_timer timer,
struct m0_sm_group group,
void(*)(struct m0_sm_timer *)  cb,
m0_time_t  deadline 
)

Starts the timer.

When the specified (absolute) deadline expires, an AST is posted in the specified state machine group. When this AST is executed, it calls the user-supplied call-back.

If the deadline is already in the past by the time this is called, the AST is posted as soon as possible.

Definition at line 577 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_addb2_counter_init_add()

static void sm_addb2_counter_init_add ( struct m0_sm sm)
static

Definition at line 880 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_addb2_ctor()

static int sm_addb2_ctor ( struct m0_sm_addb2_stats stats,
const struct m0_sm_conf c 
)
static

Definition at line 817 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_addb2_dtor()

static void sm_addb2_dtor ( struct m0_sm_addb2_stats stats,
const struct m0_sm_conf c 
)
static

Definition at line 837 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_call_ast()

static void sm_call_ast ( struct m0_sm_group grp,
struct m0_sm_ast ast 
)
static

Definition at line 793 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_invariant0()

M0_INTERNAL bool sm_invariant0 ( const struct m0_sm mach)

Weaker form of state machine invariant, that doesn't check that the group lock is held. Used in m0_sm_init() and m0_sm_fini().

Definition at line 260 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_is_locked()

static bool sm_is_locked ( const struct m0_sm mach)
static

Definition at line 232 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_lock()

static void sm_lock ( struct m0_sm mach)
static

Definition at line 222 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_state()

static const struct m0_sm_state_descr* sm_state ( const struct m0_sm mach)
static

Definition at line 251 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_timeout_cancel()

static bool sm_timeout_cancel ( struct m0_clink link)
static

Cancels a timeout, if necessary.

This is called if a state transition happened before the timeout expired.

See also
m0_sm_timeout_arm().

Definition at line 655 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_timer_bottom()

static void sm_timer_bottom ( struct m0_sm_group grp,
struct m0_sm_ast ast 
)
static

AST call-back for a timer.

See also
m0_sm_timer_start().

Definition at line 548 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_timer_top()

static unsigned long sm_timer_top ( unsigned long  data)
static

Timer call-back for a state machine timer.

See also
m0_sm_timer_start().

Definition at line 519 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sm_unlock()

static void sm_unlock ( struct m0_sm mach)
static

Definition at line 227 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ state_get()

static const struct m0_sm_state_descr* state_get ( const struct m0_sm mach,
uint32_t  state 
)
static

Definition at line 244 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ state_is_valid()

static bool state_is_valid ( const struct m0_sm_conf conf,
uint32_t  state 
)
static

Definition at line 237 of file sm.c.

Here is the caller graph for this function:

◆ state_set()

static void state_set ( struct m0_sm mach,
int  state,
int32_t  rc 
)
static

Definition at line 416 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timeout_ast()

static void timeout_ast ( struct m0_sm_timer timer)
static

AST call-back for a timeout.

See also
m0_sm_timeout_arm().

Definition at line 638 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ timer_done()

static void timer_done ( struct m0_sm_timer timer)
static

Definition at line 535 of file sm.c.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ trans_exists()

static bool trans_exists ( const struct m0_sm_conf conf,
uint32_t  src,
uint32_t  tgt 
)
static

Definition at line 718 of file sm.c.

Here is the caller graph for this function:

Variable Documentation

◆ eoq

struct m0_sm_ast eoq
static

An end-of-queue marker.

All fork queues end with this pointer. This marker is used instead of NULL to make (ast->sa_next == NULL) equivalent to "the ast is not in a fork queue".

Compare with lib/queue.c:EOQ.

Definition at line 51 of file sm.c.

◆ m0_sm__conf_init

M0_INTERNAL void(* m0_sm__conf_init) (const struct m0_sm_conf *conf) = NULL

Definition at line 338 of file sm.c.