Mstdlib-1.24.0
State Machine

Typedefs

typedef struct M_state_machine M_state_machine_t
 
typedef struct M_state_machine_cleanup M_state_machine_cleanup_t
 
typedef void(* M_state_machine_trace_cb) (M_state_machine_trace_t trace, M_uint64 mndescr, const char *mdescr, M_uint64 sndescr, const char *sdescr, const char *fdescr, M_uint64 id, M_state_machine_status_t status, M_bool run_sub, M_uint64 next_id, void *thunk)
 
typedef M_state_machine_status_t(* M_state_machine_state_cb) (void *data, M_uint64 *next)
 
typedef M_state_machine_status_t(* M_state_machine_cleanup_cb) (void *data, M_state_machine_cleanup_reason_t reason, M_uint64 *next)
 
typedef M_bool(* M_state_machine_pre_cb) (void *data, M_state_machine_status_t *status, M_uint64 *next)
 
typedef M_state_machine_status_t(* M_state_machine_post_cb) (void *data, M_state_machine_status_t sub_status, M_uint64 *next)
 

Enumerations

enum  M_state_machine_status_t {
  M_STATE_MACHINE_STATUS_NONE = 0 ,
  M_STATE_MACHINE_STATUS_NEXT ,
  M_STATE_MACHINE_STATUS_PREV ,
  M_STATE_MACHINE_STATUS_CONTINUE ,
  M_STATE_MACHINE_STATUS_ERROR_STATE ,
  M_STATE_MACHINE_STATUS_WAIT ,
  M_STATE_MACHINE_STATUS_PAUSE ,
  M_STATE_MACHINE_STATUS_DONE ,
  M_STATE_MACHINE_STATUS_STOP_CLEANUP ,
  M_STATE_MACHINE_STATUS_ERROR_INVALID ,
  M_STATE_MACHINE_STATUS_ERROR_BAD_ID ,
  M_STATE_MACHINE_STATUS_ERROR_NO_NEXT ,
  M_STATE_MACHINE_STATUS_ERROR_BAD_NEXT ,
  M_STATE_MACHINE_STATUS_ERROR_SELF_NEXT ,
  M_STATE_MACHINE_STATUS_ERROR_NO_PREV ,
  M_STATE_MACHINE_STATUS_ERROR_INF_CONT
}
 
enum  M_state_machine_flags_t {
  M_STATE_MACHINE_NONE = 0 ,
  M_STATE_MACHINE_SINGLE_PREV = 1 << 1 ,
  M_STATE_MACHINE_CONTINUE_LOOP = 1 << 2 ,
  M_STATE_MACHINE_SELF_CALL = 1 << 3 ,
  M_STATE_MACHINE_DONE_CLEANUP = 1 << 4 ,
  M_STATE_MACHINE_ONE_CLEANUP = 1 << 5 ,
  M_STATE_MACHINE_EXPLICIT_NEXT = 1 << 6 ,
  M_STATE_MACHINE_LINEAR_END = 1 << 7 ,
  M_STATE_MACHINE_INTERNOABORT = 1 << 8
}
 
enum  M_state_machine_cleanup_reason_t {
  M_STATE_MACHINE_CLEANUP_REASON_NONE = 0 ,
  M_STATE_MACHINE_CLEANUP_REASON_DONE ,
  M_STATE_MACHINE_CLEANUP_REASON_ERROR ,
  M_STATE_MACHINE_CLEANUP_REASON_RESET ,
  M_STATE_MACHINE_CLEANUP_REASON_CANCEL
}
 
enum  M_state_machine_trace_t {
  M_STATE_MACHINE_TRACE_NONE = 0 ,
  M_STATE_MACHINE_TRACE_MACHINEENTER ,
  M_STATE_MACHINE_TRACE_MACHINEEXIT ,
  M_STATE_MACHINE_TRACE_STATE_START ,
  M_STATE_MACHINE_TRACE_STATE_FINISH ,
  M_STATE_MACHINE_TRACE_PRE_START ,
  M_STATE_MACHINE_TRACE_PRE_FINISH ,
  M_STATE_MACHINE_TRACE_POST_START ,
  M_STATE_MACHINE_TRACE_POST_FINISH ,
  M_STATE_MACHINE_TRACE_CLEANUP
}
 

Functions

M_state_machine_tM_state_machine_create (M_uint64 ndescr, const char *descr, M_uint32 flags)
 
void M_state_machine_destroy (M_state_machine_t *m)
 
M_state_machine_cleanup_tM_state_machine_cleanup_create (M_uint64 ndescr, const char *descr, M_uint32 flags)
 
void M_state_machine_cleanup_destroy (M_state_machine_cleanup_t *m)
 
M_bool M_state_machine_insert_state (M_state_machine_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_state_cb func, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_insert_sub_state_machine (M_state_machine_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, const M_state_machine_t *subm, M_state_machine_pre_cb pre, M_state_machine_post_cb post, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_insert_state_interleaved (M_state_machine_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_pre_cb pre, M_state_machine_post_cb post, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_insert_sub_state_machine_interleaved (M_state_machine_t *m, M_uint64 id, const M_state_machine_t *subm)
 
M_bool M_state_machine_remove_state (M_state_machine_t *m, M_uint64 id)
 
M_bool M_state_machine_has_state (const M_state_machine_t *m, M_uint64 id)
 
const M_list_u64_tM_state_machine_list_states (const M_state_machine_t *m)
 
M_bool M_state_machine_cleanup_insert_state (M_state_machine_cleanup_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_cleanup_cb func, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_cleanup_insert_cleanup_sub_state_machine (M_state_machine_cleanup_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, const M_state_machine_cleanup_t *subm, M_state_machine_pre_cb pre, M_state_machine_post_cb post, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_cleanup_insert_sub_state_machine (M_state_machine_cleanup_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, const M_state_machine_t *subm, M_state_machine_pre_cb pre, M_state_machine_post_cb post, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
 
M_bool M_state_machine_cleanup_remove_state (M_state_machine_cleanup_t *m, M_uint64 id)
 
M_bool M_state_machine_cleanup_has_state (const M_state_machine_cleanup_t *m, M_uint64 id)
 
const M_list_u64_tM_state_machine_cleanup_list_states (const M_state_machine_cleanup_t *m)
 
void M_state_machine_enable_trace (M_state_machine_t *m, M_state_machine_trace_cb cb, void *thunk)
 
void M_state_machine_cleanup_enable_trace (M_state_machine_cleanup_t *m, M_state_machine_trace_cb cb, void *thunk)
 
M_state_machine_status_t M_state_machine_run (M_state_machine_t *m, void *data)
 
void M_state_machine_reset (M_state_machine_t *m, M_state_machine_cleanup_reason_t reason)
 
M_uint64 M_state_machine_ndescr (const M_state_machine_t *m, M_bool recurse)
 
const char * M_state_machine_descr (const M_state_machine_t *m, M_bool recurse)
 
const M_state_machine_tM_state_machine_active_sub (const M_state_machine_t *m, M_bool recurse)
 
M_bool M_state_machine_active_state (const M_state_machine_t *m, M_uint64 *id)
 
M_uint64 M_state_machine_active_state_ndescr (const M_state_machine_t *m, M_bool recurse)
 
const char * M_state_machine_active_state_descr (const M_state_machine_t *m, M_bool recurse)
 
char * M_state_machine_descr_full (const M_state_machine_t *m, M_bool show_id)
 
M_state_machine_tM_state_machine_duplicate (const M_state_machine_t *m) M_MALLOC
 

Detailed Description

Non-linear state machine for running a sequence of states.

Normally the state machine will run using a linear or linear hybrid method. When adding states to the state machine the order is preserved. By default the next state is the next state added. A state can change/set the next state id. Using the next state is simply a convenience for using the state machine in a linear manner. So a state can set an id to transition to or it can rely on the next state in the ordered state list to be called next. This behavior can be disabled and the state machine will run as a pure non-linear state machine where a transition id is required to be set by a state.

States are given an integral id. The id must be unique and is used so a state can specify which state to transition to. No id can use the number zero (0); it is reserved for internal use.

Each state can have an optional cleanup state machine. The cleanup will be called when the error or done status are returned by run. All status that ran (including the one that generated the error) will have their cleanup state machine run. The state must have fully completed before it is eligible for its cleanup to run. A machine that has only returned M_STATE_MACHINE_STATUS_WAIT is not eligible for its cleanup to run. A state that is a sub state machine is eligible for cleanup if it is entered (pre does not return M_FALSE).

Cleanup is run in reverse order that the states were run in. For example states A - E were run and E returns done. Cleanup for states will run E - A. Due to the state machine supporting non-linear sequences it is possible that a cleanup machines will be called multiple times.

Cleanup can be used in multiple ways. They can be resource clean up (particularly useful when the done_cleanup flag is used) that is run when the machine finishes. Or they can be used as error recovery such as performing an action if an error occurs (default use).

Cleanup should be specific to the state and should in some way be based on the state they're associated with. A final cleanup on success could be handled as a final state but should be handled outside of the state machine entirely. Such as being handled as part of cleaning up the void pointer of state data.

Example

typedef enum {
STATE_A = 1,
STATE_B,
STATE_C
} states_t;
static M_state_machine_status_t state_a(void *data, M_uint64 *next)
{
(void)data;
*next = STATE_C;
}
static M_state_machine_status_t state_b(void *data, M_uint64 *next)
{
(void)data;
(void)next;
}
static M_state_machine_status_t state_c(void *data, M_uint64 *next)
{
(void)data;
*next = STATE_B;
}
int main(int argc, char **argv)
{
M_state_machine_insert_state(sm, STATE_A, 0, NULL, state_a, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B, 0, NULL, state_b, NULL, NULL);
M_state_machine_insert_state(sm, STATE_C, 0, NULL, state_c, NULL, NULL);
do {
status = M_state_machine_run(sm, NULL);
} while (status == M_STATE_MACHINE_STATUS_WAIT);
if (status != M_STATE_MACHINE_STATUS_DONE) {
M_printf("state machine failure\n");
} else {
M_printf("state machine success\n");
}
return 0;
}
ssize_t M_printf(const char *fmt,...)
M_state_machine_status_t M_state_machine_run(M_state_machine_t *m, void *data)
M_bool M_state_machine_insert_state(M_state_machine_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_state_cb func, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
M_state_machine_t * M_state_machine_create(M_uint64 ndescr, const char *descr, M_uint32 flags)
M_state_machine_status_t
Definition: m_state_machine.h:565
struct M_state_machine M_state_machine_t
Definition: m_state_machine.h:556
void M_state_machine_destroy(M_state_machine_t *m)
@ M_STATE_MACHINE_NONE
Definition: m_state_machine.h:633
@ M_STATE_MACHINE_STATUS_WAIT
Definition: m_state_machine.h:598
@ M_STATE_MACHINE_STATUS_NEXT
Definition: m_state_machine.h:568
@ M_STATE_MACHINE_STATUS_DONE
Definition: m_state_machine.h:608

Interleaved Example

#include <mstdlib/mstdlib.h>
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
typedef struct {
size_t cnt;
size_t a1_wait_cnt;
size_t a2_wait_cnt;
size_t a3_wait_cnt;
size_t b1_wait_cnt;
size_t b2_wait_cnt;
size_t b3_wait_cnt;
size_t b5_wait_cnt;
size_t c1_wait_cnt;
size_t c2_wait_cnt;
size_t c3_wait_cnt;
} data_obj_t;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void trace(M_state_machine_trace_t trace, M_uint64 mndescr, const char *mdescr, M_uint64 sndescr, const char *sdescr, const char *fdescr, M_uint64 id, M_state_machine_status_t status, M_bool run_sub, M_uint64 next_id, void *thunk)
{
M_printf("STATE: %s\n", fdescr);
M_printf("STATE: %s - WAIT\n", fdescr);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// CSM
typedef enum {
STATE_CL = 1
} state_cl_b_t;
static M_state_machine_status_t state_csm(void *data, M_state_machine_cleanup_reason_t reason, M_uint64 *next)
{
(void)data;
(void)reason;
(void)next;
M_printf("Calling func: %s\n", __func__);
}
static M_state_machine_cleanup_t *create_csm(void)
{
M_state_machine_cleanup_insert_state(csm, STATE_CL, 0, "CL1", state_csm, NULL, NULL);
return csm;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// SM A
typedef enum {
STATE_A1 = 1,
STATE_A2,
STATE_A3
} states_a_t;
static M_state_machine_status_t state_a1(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->a1_wait_cnt < 4) {
obj->a1_wait_cnt++;
}
obj->a1_wait_cnt = 0;
}
static M_state_machine_status_t state_a2(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->a2_wait_cnt < 3) {
obj->a2_wait_cnt++;
}
obj->a2_wait_cnt = 0;
}
static M_state_machine_status_t state_a3(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->a3_wait_cnt < 2) {
obj->a3_wait_cnt++;
}
obj->a3_wait_cnt = 0;
}
static M_state_machine_t *create_sm_a(void)
{
M_state_machine_insert_state(sm, STATE_A1, 0, "A1", state_a1, NULL, NULL);
M_state_machine_insert_state(sm, STATE_A2, 0, "A2", state_a2, NULL, NULL);
M_state_machine_insert_state(sm, STATE_A3, 0, "A3", state_a3, NULL, NULL);
return sm;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// SM B
typedef enum {
STATE_B1 = 1,
STATE_B2,
STATE_B3,
STATE_B4,
STATE_B5,
STATE_B6
} states_b_t;
static M_state_machine_status_t state_b1(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->b1_wait_cnt < 2) {
obj->b1_wait_cnt++;
}
obj->b1_wait_cnt = 0;
}
static M_state_machine_status_t state_b2(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->b2_wait_cnt < 3) {
obj->b2_wait_cnt++;
}
obj->b2_wait_cnt = 0;
}
static M_state_machine_status_t state_b3(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->b3_wait_cnt < 4) {
obj->b3_wait_cnt++;
}
obj->b3_wait_cnt = 0;
}
static M_state_machine_status_t state_b4(void *data, M_uint64 *next)
{
(void)data;
(void)next;
M_printf("Calling func: %s\n", __func__);
}
static M_state_machine_status_t state_b5(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->b5_wait_cnt < 5) {
obj->b5_wait_cnt++;
}
obj->b5_wait_cnt = 0;
}
static M_state_machine_status_t state_b6(void *data, M_uint64 *next)
{
(void)data;
(void)next;
M_printf("Calling func: %s\n", __func__);
}
static M_state_machine_t *create_sm_b(void)
{
csm = create_csm();
M_state_machine_insert_state(sm, STATE_B1, 0, "B1", state_b1, csm, NULL);
M_state_machine_insert_state(sm, STATE_B1, 0, "B1", state_b1, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B2, 0, "B2", state_b2, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B3, 0, "B3", state_b3, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B4, 0, "B4", state_b4, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B5, 0, "B5", state_b5, NULL, NULL);
M_state_machine_insert_state(sm, STATE_B6, 0, "B6", state_b6, NULL, NULL);
return sm;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// SM C
typedef enum {
STATE_C1 = 1,
STATE_C2,
STATE_C3
} states_c_t;
static M_state_machine_status_t state_c1(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->c1_wait_cnt < 4) {
obj->c1_wait_cnt++;
}
obj->c1_wait_cnt = 0;
}
static M_state_machine_status_t state_c2(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->c2_wait_cnt < 0) {
obj->c2_wait_cnt++;
}
obj->c2_wait_cnt = 0;
}
static M_state_machine_status_t state_c3(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
(void)next;
M_printf("Calling func: %s\n", __func__);
if (obj->c3_wait_cnt < 1) {
obj->c3_wait_cnt++;
}
obj->c3_wait_cnt = 0;
}
static M_state_machine_t *create_sm_c(void)
{
csm = create_csm();
M_state_machine_insert_state(sm, STATE_C1, 0, "C1", state_c1, csm, NULL);
M_state_machine_insert_state(sm, STATE_C2, 0, "C2", state_c2, NULL, NULL);
M_state_machine_insert_state(sm, STATE_C3, 0, "C3", state_c3, NULL, NULL);
return sm;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// SM MAIN
typedef enum {
STATE_MA = 1,
STATE_MB, // Interleaved state.
STATE_MC
} states_m_t;
static M_state_machine_status_t state_ma(void *data, M_uint64 *next)
{
M_printf("Calling func: %s\n", __func__);
}
static M_bool inter_pre(void *data, M_state_machine_status_t *status, M_uint64 *next)
{
(void)data;
(void)status;
(void)next;
M_printf("Calling func: %s\n", __func__);
return M_TRUE;
}
static M_state_machine_status_t inter_post(void *data, M_state_machine_status_t sub_status, M_uint64 *next)
{
(void)data;
(void)next;
M_printf("Calling func: %s with sub status %u\n", __func__, sub_status);
if (sub_status != M_STATE_MACHINE_STATUS_DONE)
return sub_status;
}
static M_state_machine_status_t state_mc(void *data, M_uint64 *next)
{
data_obj_t *obj = data;
M_printf("Calling func: %s\n", __func__);
if (obj->cnt < 3) {
*next = STATE_MA;
obj->cnt++;
M_printf("Going back to main cnt: %zu\n", obj->cnt);
}
}
static M_state_machine_t *create_sm_m(void)
{
M_state_machine_insert_state(sm, STATE_MA, 0, "SA", state_ma, NULL, NULL);
M_state_machine_insert_state_interleaved(sm, STATE_MB, 0, "SIB", inter_pre, inter_post, NULL, NULL);
subm = create_sm_a();
subm = create_sm_b();
subm = create_sm_c();
M_state_machine_insert_state(sm, STATE_MC, 0, "SC", state_mc, NULL, NULL);
return sm;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
int main(int argc, char **argv)
{
data_obj_t *obj;
sm = create_sm_m();
obj = M_malloc_zero(sizeof(*obj));
M_state_machine_enable_trace(sm, trace, NULL);
do {
status = M_state_machine_run(sm, obj);
} while (status == M_STATE_MACHINE_STATUS_WAIT);
if (status != M_STATE_MACHINE_STATUS_DONE) {
M_printf("state machine failure\n");
} else {
M_printf("state machine success\n");
}
M_free(obj);
return 0;
}
void * M_malloc_zero(size_t size) M_ALLOC_SIZE(1) M_WARN_UNUSED_RESULT M_MALLOC
void M_free(void *ptr) M_FREE(1)
void M_state_machine_enable_trace(M_state_machine_t *m, M_state_machine_trace_cb cb, void *thunk)
void M_state_machine_cleanup_destroy(M_state_machine_cleanup_t *m)
M_state_machine_cleanup_t * M_state_machine_cleanup_create(M_uint64 ndescr, const char *descr, M_uint32 flags)
M_bool M_state_machine_cleanup_insert_state(M_state_machine_cleanup_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_cleanup_cb func, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
M_state_machine_trace_t
Definition: m_state_machine.h:685
M_state_machine_cleanup_reason_t
Definition: m_state_machine.h:671
M_bool M_state_machine_insert_sub_state_machine_interleaved(M_state_machine_t *m, M_uint64 id, const M_state_machine_t *subm)
struct M_state_machine_cleanup M_state_machine_cleanup_t
Definition: m_state_machine.h:559
M_bool M_state_machine_insert_state_interleaved(M_state_machine_t *m, M_uint64 id, M_uint64 ndescr, const char *descr, M_state_machine_pre_cb pre, M_state_machine_post_cb post, M_state_machine_cleanup_t *cleanup, M_list_u64_t *next_ids)
@ M_STATE_MACHINE_DONE_CLEANUP
Definition: m_state_machine.h:644
@ M_STATE_MACHINE_LINEAR_END
Definition: m_state_machine.h:656
@ M_STATE_MACHINE_INTERNOABORT
Definition: m_state_machine.h:660
@ M_STATE_MACHINE_TRACE_STATE_FINISH
Definition: m_state_machine.h:707
@ M_STATE_MACHINE_TRACE_STATE_START
Definition: m_state_machine.h:698

Typedef Documentation

◆ M_state_machine_t

typedef struct M_state_machine M_state_machine_t

◆ M_state_machine_cleanup_t

typedef struct M_state_machine_cleanup M_state_machine_cleanup_t

◆ M_state_machine_trace_cb

typedef void(* M_state_machine_trace_cb) (M_state_machine_trace_t trace, M_uint64 mndescr, const char *mdescr, M_uint64 sndescr, const char *sdescr, const char *fdescr, M_uint64 id, M_state_machine_status_t status, M_bool run_sub, M_uint64 next_id, void *thunk)

Trace callback.

Parameters
[in]traceType of action traced.
[in]mndescrNumeric state machine description code.
[in]mdescrState machine description.
[in]sndescrNumeric state description code.
[in]sdescrState description.
[in]fdescrFull description of the entire machine flow.
[in]idId of state.
[in]statusReturn status.
[in]run_subWill the sub state machine be run.
[in]next_idThe next id the machine will move to.
[in]thunkThunk passed in when enabling the trace.

◆ M_state_machine_state_cb

typedef M_state_machine_status_t(* M_state_machine_state_cb) (void *data, M_uint64 *next)

State callback.

This is what the state machine calls when entering a given state.

Parameters
[in,out]dataAn opaque data type storing data that should be passed to the cb.
[out]nextThe next id the state machine should transition to. When operating in linear or a hybrid manner this will be set to the next linear state. Changing this will change what state is next.
Returns
The status.

◆ M_state_machine_cleanup_cb

typedef M_state_machine_status_t(* M_state_machine_cleanup_cb) (void *data, M_state_machine_cleanup_reason_t reason, M_uint64 *next)

Cleanup state callback.

This is what a cleanup state machine calls when entering a given cleanup state.

Parameters
[in,out]dataAn opaque data type storing data that should be passed to the cb.
[in]reasonThe reason cleanup is being run.
[out]nextThe next id the state machine should transition to. When operating in linear or a hybrid manner this will be set to the next linear state. Changing this will change what state is next.
Returns
The status.

◆ M_state_machine_pre_cb

typedef M_bool(* M_state_machine_pre_cb) (void *data, M_state_machine_status_t *status, M_uint64 *next)

Sub state machine pre (initialization) callback.

This will be called before starting a sub state machine.

Parameters
[in,out]dataAn opaque data type storing data that should be passed to the cb.
[out]statusUsed when not running the sub state machine. This is the status of the state. Defaults to M_STATE_MACHINE_STATUS_NEXT if not specified.
[out]nextUsed when not running the sub state machine. If set the next id the state machine should transition to. When operating in linear or a hybrid manner this will be set to the next linear state. Changing this will change what state is next.
Returns
M_TRUE if the sub state machine should run. M_FALSE if the sub state machine should not run.

◆ M_state_machine_post_cb

typedef M_state_machine_status_t(* M_state_machine_post_cb) (void *data, M_state_machine_status_t sub_status, M_uint64 *next)

Sub state machine post (de-initialization) callback.

The sub_status argument is the status returned by the sub state machine. Possible status:

  • M_STATE_MACHINE_STATUS_DONE
  • M_STATE_MACHINE_STATUS_ERROR_*

The sub_status will next be M_STATE_MACHINE_STATUS_NEXT or similar. Thus, the sub_status should not be blindly returned from the post function as it will stop processing the parent state machine. If processing needs to continue the sub_status should be checked and M_STATE_MACHINE_STATUS_NEXT or similar should be returned. M_STATE_MACHINE_STATUS_DONE is the only successful sub_status that can be set, so patterns that check against M_STATE_MACHINE_STATUS_DONE should be used. For example:

if (sub_status == M_STATE_MACHINE_STATUS_DONE) {
// Success and continue.
}
...
if (sub_status != M_STATE_MACHINE_STATUS_DONE) {
// Error of some kind. Propagate it up.
return sub_status;
}
...
if (stop_condition) {
// Some kind of external stop condition was encountered.
// Return the sub_status because it will stop processing
// and we should maintain status from the sub state machine.
return sub_status; // Status is error or done.
}
...
Parameters
[in,out]dataAn opaque data type storing data that should be passed to the cb.
[out]sub_statusThe status of the last state in the sub state machine.
[out]nextThe next id the state machine should transition to. When operating in linear or a hybrid manner this will be set to the next linear state. Changing this will change what state is next.
Returns
The status.

Enumeration Type Documentation

◆ M_state_machine_status_t

Status of the state machine while running though states.

Enumerator
M_STATE_MACHINE_STATUS_NONE 

Invalid status.

M_STATE_MACHINE_STATUS_NEXT 

Success continue to the next state. The state was run and should be recorded as well as cleanup added to the cleanup list.

M_STATE_MACHINE_STATUS_PREV 

A recoverable error occurred. Go to the last successful (non-continue) state.

This should be treated as a special case and is primarily a convenience when using the state machine in a linear manner. It should not be used in stead of specifying an id and calling next if it is possible to do so.

This does not back out states. State cleanups will not be called when skipping back over states. Also, the list of cleanups will not be modified to remove cleanups for states that have been called. Further, This can result in a state having it's cleanup registered multiple times as a result of multiple successful calls.

M_STATE_MACHINE_STATUS_CONTINUE 

Success continue to the next state. The state was skipped and should be treated as such. The cleanup for this state will not be added to the cleanup list.

This should not be treated as next without cleanup. It is for signifying that the state was skipped. If you need next without cleanup the state should be registered without a cleanup state machine. Even if that means having two ids for the same state function one with and one without a cleanup registered.

M_STATE_MACHINE_STATUS_ERROR_STATE 

An unrecoverable error occurred within a state. Exit and clean up. The state is responsible for error reporting though the void data pointer passed to the state function.

M_STATE_MACHINE_STATUS_WAIT 

The state is processing in a non-blocking fashion. More calls to run are required to continue the operation. The state that returned WAIT will be called when the state machine is run.

M_STATE_MACHINE_STATUS_PAUSE 

The state is processing in a non-blocking fashion. More calls to run are required to continue the operation. The next state (set explicit or implicitly) will be run when the state machine is run. An error will be returned by run instead of pause if continuing would cause an error. In the same way as with the state returning next. If there is no state to continue to run will return done if doing so is not an error. Such as if linear end flag is set.

M_STATE_MACHINE_STATUS_DONE 

The sequence completed successfully.

M_STATE_MACHINE_STATUS_STOP_CLEANUP 
M_STATE_MACHINE_STATUS_ERROR_INVALID 

The state machine was called with an invalid parameter.

M_STATE_MACHINE_STATUS_ERROR_BAD_ID 

Invalid transition specified. Id not found. Most likely the state specified an id to transition to that doesn't exist.

M_STATE_MACHINE_STATUS_ERROR_NO_NEXT 

Invalid transition specified. An next id was not specified. This can happen when running in a linear manner and the last state in the sequence does not return done. There are no states after the last state so we cannot continue with the sequence.

M_STATE_MACHINE_STATUS_ERROR_BAD_NEXT 

Invalid transition specified. The specified next id is not valid (not listed in the states list of next ids) for the state.

M_STATE_MACHINE_STATUS_ERROR_SELF_NEXT 

Invalid transition specified. The specified next id is the current id. Use the continue_loop flag to disable this check.

M_STATE_MACHINE_STATUS_ERROR_NO_PREV 

Invalid transition specified. There are no previous states to transition to.

M_STATE_MACHINE_STATUS_ERROR_INF_CONT 

A possible infinite continuation loop has been encountered.

◆ M_state_machine_flags_t

Options to control the behavior of the state machine.

Enumerator
M_STATE_MACHINE_NONE 

Normal operation.

M_STATE_MACHINE_SINGLE_PREV 

Do not allow multiple states to return STATUS_PREV in a row. Only one PREV return is allowed between NEXT calls.

M_STATE_MACHINE_CONTINUE_LOOP 

Normally continuations are tracked for the continuation cycle and any continuation that is repeated is treated as an internal error in order to detect and prevent accidental infinite loops.

This option disables this check and allows continuations to call continuations that have been called previously.

M_STATE_MACHINE_SELF_CALL 

Normally states cannot call themselves. This flag also allows states to call themselves.

M_STATE_MACHINE_DONE_CLEANUP 

State cleanups should be called on done.

M_STATE_MACHINE_ONE_CLEANUP 

State cleanup should be called once no matter how many times the state was called.

M_STATE_MACHINE_EXPLICIT_NEXT 

Normally the state machine defaults to using the next state in the order states were added if a state isn't explicits specified by the current state. This requires that a state specify the next (transition) state.

This will force the state machine to function purely as a non-linear state machine. The linear / linear hybrid functionality will be disabled. This option cannot be used in conjunction with linear_end. The linear_end flag will be ignored if this flag is set.

M_STATE_MACHINE_LINEAR_END 

Normally a state machine is done when the done status is returned by a state. This allows the state machine to be considered done if a state does not specify a transition, it returns next or continue and the current state is the last state in the ordered state list.

M_STATE_MACHINE_INTERNOABORT 

Interleaved sub state machines should continue processing until done even when another sub state machine errors. Prevents aborting other interleaved sub state machines from aborting. An error will still be returned as the result of the interleaved state (sent to the post callback) but only after all sub state machines have finished. If multiple sub state machines failed, the error status for the first added will be used.

◆ M_state_machine_cleanup_reason_t

Status of the state machine which caused the cleanup routines to trigger.

Enumerator
M_STATE_MACHINE_CLEANUP_REASON_NONE 

Cleanup should not be run. When calling reset this will not run cleanup.

M_STATE_MACHINE_CLEANUP_REASON_DONE 

State machine finished successfully.

M_STATE_MACHINE_CLEANUP_REASON_ERROR 

State machine stopped due to error.

M_STATE_MACHINE_CLEANUP_REASON_RESET 

State machine should be reset so it can run again. This is a reason why cleanup is being run.

M_STATE_MACHINE_CLEANUP_REASON_CANCEL 

State machine was canceled. This will reset the machine so it can run again but should be considered that it will not be run again. Use reset for restarting instead.

◆ M_state_machine_trace_t

Tracing information.

Enumerator
M_STATE_MACHINE_TRACE_NONE 

Invalid.

M_STATE_MACHINE_TRACE_MACHINEENTER 

About to enter a given state machine (could be sub) Will provide the following information: mndescr mdescr fdescr

M_STATE_MACHINE_TRACE_MACHINEEXIT 

Machine exited. Will provide the following information: mndescr mdescr fdescr status

M_STATE_MACHINE_TRACE_STATE_START 

State is about to run. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id

M_STATE_MACHINE_TRACE_STATE_FINISH 

State finished running. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id next_id status

M_STATE_MACHINE_TRACE_PRE_START 

Pre function will run before entering a sub machine. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id

M_STATE_MACHINE_TRACE_PRE_FINISH 

Pre functoin finished running. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id run_sub status

M_STATE_MACHINE_TRACE_POST_START 

Sub machine finished but before post function runs. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id

M_STATE_MACHINE_TRACE_POST_FINISH 

Sub machine finished running but after post function ran. Will provide the following information: mndescr mdescr sndescr sdescr fdescr id status

M_STATE_MACHINE_TRACE_CLEANUP 

Cleanup function ran. Will provide the following information: mndescr mdescr sndescr sdescr

Function Documentation

◆ M_state_machine_create()

M_state_machine_t * M_state_machine_create ( M_uint64  ndescr,
const char *  descr,
M_uint32  flags 
)

Create a new state machine.

Parameters
[in]ndescrA numeric description of the state machine. Can be 0.
[in]descrA textual description of the state machine. Can be NULL.
[in]flagsM_state_machine_flags_t flags to control the behavior of the state machine.
Returns
The state machine.

◆ M_state_machine_destroy()

void M_state_machine_destroy ( M_state_machine_t m)

Destroy a state machine.

This does not call the cleanup state machines associated with each state. State cleanups are only called when the state machine finishes running.

Parameters
[in]mThe state machine.

◆ M_state_machine_cleanup_create()

M_state_machine_cleanup_t * M_state_machine_cleanup_create ( M_uint64  ndescr,
const char *  descr,
M_uint32  flags 
)

Create a new cleanup state machine.

A cleanup state machine is very similar to a regular state machine and is only called when associated with a regular state machine state's cleanup parameter. This cannot be run directly but supports all options a regular state machine supports for execution.

When run error returns from a cleanup state machine will not be propagated back to the caller. To handle errors it is possible to have a cleanup state machine's state to have an associated cleanup state machine.

Parameters
[in]ndescrA numeric description of the cleanup state machine. Can be 0.
[in]descrA textual description of the cleanup state machine. Can be NULL.
[in]flagsM_state_machine_flags_t flags to control the behavior of the cleanup state machine.
Returns
The cleanup state machine.

◆ M_state_machine_cleanup_destroy()

void M_state_machine_cleanup_destroy ( M_state_machine_cleanup_t m)

Destroy a cleanup state machine.

Parameters
[in]mThe cleanup state machine.

◆ M_state_machine_insert_state()

M_bool M_state_machine_insert_state ( M_state_machine_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
M_state_machine_state_cb  func,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add a state to the state machine.

Parameters
[in,out]mThe state machine.
[in]idThe id associated with this state. Must be unique.
[in]ndescrA numeric description of the state. Can be 0.
[in]descrA textual description of the state. Can be NULL.
[in]funcThe state function to call. Cannot be NULL.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the state was added. Otherwise M_FALSE.

◆ M_state_machine_insert_sub_state_machine()

M_bool M_state_machine_insert_sub_state_machine ( M_state_machine_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
const M_state_machine_t subm,
M_state_machine_pre_cb  pre,
M_state_machine_post_cb  post,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add a state machine as a state to the state machine.

The state machine will duplicate the sub state machine and keep a copy.

The sub state machine will run though all states in the sub state machine. The state machine will return M_STATE_MACHINE_STATUS_WAIT from the sub state machine and resume the sub state machine when started again.

The sub state machine's final status will be passed to the post function if one is given. If a post function is not set, a status of M_STATE_MACHINE_STATUS_DONE will be returned as M_STATE_MACHINE_STATUS_NEXT. This is to prevent a M_STATE_MACHINE_STATUS_DONE from the sub state machine from accidentally stopping the calling state machine. If M_STATE_MACHINE_STATUS_DONE is needed as the result of the sub state machine's run then a post function is necessary.

Parameters
[in,out]mThe state machine.
[in]idThe id associated with this state. Must be unique.
[in]ndescrA numeric description of the state. Can be 0.
[in]descrA textual description of the state. Can be NULL.
[in]submThe state machine that should be called from this one. Cannot be NULL.
[in]preA function to call before the sub state machine is started. Can be NULL.
[in]postA function to call after the sub state machine is finished. Can be NULL.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the sub state machine was added. Otherwise M_FALSE.

◆ M_state_machine_insert_state_interleaved()

M_bool M_state_machine_insert_state_interleaved ( M_state_machine_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
M_state_machine_pre_cb  pre,
M_state_machine_post_cb  post,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add add a state to run interleaved sub state machines.

An interleaved state will have one or more sub state machines added to it. The sub state machines will be run interleaved as one returns wait the next will be started until it returns wait and so forth. Sub state machines process in a non liner order and do not match state counts between one another.

A single state machine that never returns wait will fully run before any others are. Interleaving relies on wait states. Typically, this is used for near concurrent processing for operations that may require waiting on external resources. For example, a system that receives, processes and sends data. A example flow: read -> process -> Interleave write and read -> process... This allows the read buffer to be filled while the write buffer is emptying. With a large amount of data read and write operations may need to wait for OS level network buffers.

States are run interleaved and not concurrently. They are run on the same thread. Locking of thunk resources is not necessary since only one state, regardless of sub state machine, will be running at any given time.

All running sub state machines will stop if an error is returned by any sub state machine. Unless the M_STATE_MACHINE_INTERNOABORT flag is set which will alter this behavior.

Parameters
[in,out]mThe state machine.
[in]idThe id associated with this interleaved state. Must be unique. All interleaved sub state machines will attach to this id.
[in]ndescrA numeric description of the state. Can be 0.
[in]descrA textual description of the state. Can be NULL.
[in]preA function to call before the sub state machines are started. Can be NULL.
[in]postA function to call after the sub state machines are finished. Can be NULL. Called when the last sub state machine is finished or they are aborted due to error. Will have an M_STATE_MACHINE_STATUS_ERROR_* if any of the sub state machines return an error status. If all sub state machines ran successfully will return M_STATE_MACHINE_STATUS_DONE. It is up to the caller to store information in the thunk argument passed to run if information about which (possibly multiple) sub state machines failed.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the interleaved state was added. Otherwise M_FALSE.

◆ M_state_machine_insert_sub_state_machine_interleaved()

M_bool M_state_machine_insert_sub_state_machine_interleaved ( M_state_machine_t m,
M_uint64  id,
const M_state_machine_t subm 
)

Add a state machine as a state to the state machine for interleaved processing.

The state machine will duplicate the sub state machine and keep a copy.

Parameters
[in,out]mThe state machine.
[in]idThe id for the interleaved state as specified by M_state_machine_insert_state_interleaved.
[in]submThe state machine that should be called from this one. Cannot be NULL.
Returns
M_TRUE if the sub state machine was added. Otherwise M_FALSE.

◆ M_state_machine_remove_state()

M_bool M_state_machine_remove_state ( M_state_machine_t m,
M_uint64  id 
)

Remove a state from the state machine.

Parameters
[in,out]mThe state machine.
[in]idThe id of the state.
Returns
M_TRUE if the state was found and removed. Otherwise M_FALSE.

◆ M_state_machine_has_state()

M_bool M_state_machine_has_state ( const M_state_machine_t m,
M_uint64  id 
)

Does the state machine contain the given state id.

Parameters
[in]mThe state machine.
[in]idThe id of the state.
Returns
M_TRUE if the state machine has the state id. Otherwise M_FALSE.

◆ M_state_machine_list_states()

const M_list_u64_t * M_state_machine_list_states ( const M_state_machine_t m)

List all state ids the state machine holds.

Parameters
[in]mThe state machine.
Returns
a List of state ids or NULL if the state machine as no states.

◆ M_state_machine_cleanup_insert_state()

M_bool M_state_machine_cleanup_insert_state ( M_state_machine_cleanup_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
M_state_machine_cleanup_cb  func,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add a cleanup state to a cleanup state machine.

Parameters
[in,out]mThe cleanup state machine.
[in]idThe id associated with this state. Must be unique.
[in]ndescrA numeric description of the state. Can be 0.
[in]descrA textual description of the state. Can be NULL.
[in]funcThe state cleanup function to call. Cannot be NULL.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the state was added. Otherwise M_FALSE.

◆ M_state_machine_cleanup_insert_cleanup_sub_state_machine()

M_bool M_state_machine_cleanup_insert_cleanup_sub_state_machine ( M_state_machine_cleanup_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
const M_state_machine_cleanup_t subm,
M_state_machine_pre_cb  pre,
M_state_machine_post_cb  post,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add a cleanup state machine as a state to the cleanup state machine.

The state machine will duplicate the sub state machine and keep a copy.

The sub state machine will run though all states in the sub state machine. The state machine will return M_STATE_MACHINE_STATUS_WAIT from the sub state machine and resume the sub state machine when started again.

The sub state machine's final status will be passed to the post function if one is given. If a post function is not set, a status of M_STATE_MACHINE_STATUS_DONE will be returned as M_STATE_MACHINE_STATUS_NEXT. This is to prevent a M_STATE_MACHINE_STATUS_DONE from the sub state machine from accidentally stopping the calling state machine. If M_STATE_MACHINE_STATUS_DONE is needed as the result of the sub state machine's run then a post function is necessary.

Parameters
[in,out]mThe cleanup state machine.
[in]idThe id associated with this state. Must be unique.
[in]ndescrA numeric description of the state. Can be 0.
[in]descrA textual description of the state. Can be NULL.
[in]submThe cleanup state machine that should be called from this one. Cannot be NULL.
[in]preA function to call before the sub state machine is started. Can be NULL.
[in]postA function to call after the sub state machine is finished. Can be NULL.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the sub state machine was added. Otherwise M_FALSE.

◆ M_state_machine_cleanup_insert_sub_state_machine()

M_bool M_state_machine_cleanup_insert_sub_state_machine ( M_state_machine_cleanup_t m,
M_uint64  id,
M_uint64  ndescr,
const char *  descr,
const M_state_machine_t subm,
M_state_machine_pre_cb  pre,
M_state_machine_post_cb  post,
M_state_machine_cleanup_t cleanup,
M_list_u64_t next_ids 
)

Add a state machine as a state to the cleanup state machine.

The state machine will duplicate the sub state machine and keep a copy.

The sub state machine will run though all states in the sub state machine. The state machine will return M_STATE_MACHINE_STATUS_WAIT from the sub state machine and resume the sub state machine when started again.

The sub state machine's final status will be passed to the post function if one is given. If a post function is not set, a status of M_STATE_MACHINE_STATUS_DONE will be returned as M_STATE_MACHINE_STATUS_NEXT. This is to prevent a M_STATE_MACHINE_STATUS_DONE from the sub state machine from accidentally stopping the calling state machine. If M_STATE_MACHINE_STATUS_DONE is needed as the result of the sub state machine's run then a post function is necessary.

Parameters
[in,out]mThe cleanup state machine.
[in]idThe id associated with this state. Must be unique.
[in]ndescrA numeric description of the state. Can be NULL.
[in]descrA textual description of the state. Can be NULL.
[in]submThe state machine that should be called from this one. Cannot be NULL.
[in]preA function to call before the sub state machine is started. Can be NULL.
[in]postA function to call after the sub state machine is finished. Can be NULL.
[in]cleanupThe cleanup state machine to call. Can be NULL if no cleanup is necessary for this state.
[in]next_idsA list of valid transitions for this state. Can be NULL to denote all states are valid transitions. If not NULL the state machine takes ownership of next_ids.
Returns
M_TRUE if the sub state machine was added. Otherwise M_FALSE.

◆ M_state_machine_cleanup_remove_state()

M_bool M_state_machine_cleanup_remove_state ( M_state_machine_cleanup_t m,
M_uint64  id 
)

Remove a state from the cleanup state machine.

Parameters
[in,out]mThe state machine.
[in]idThe id of the state.
Returns
M_TRUE if the state was found and removed. Otherwise M_FALSE.

◆ M_state_machine_cleanup_has_state()

M_bool M_state_machine_cleanup_has_state ( const M_state_machine_cleanup_t m,
M_uint64  id 
)

Does the cleanup state machine contain the given state id.

Parameters
[in]mThe cleanup state machine.
[in]idThe id of the state.
Returns
M_TRUE if the state machine has the state id. Otherwise M_FALSE.

◆ M_state_machine_cleanup_list_states()

const M_list_u64_t * M_state_machine_cleanup_list_states ( const M_state_machine_cleanup_t m)

List all state ids the cleanup state machine holds.

Parameters
[in]mThe cleanup state machine.
Returns
a List of state ids or NULL if the state machine as no states.

◆ M_state_machine_enable_trace()

void M_state_machine_enable_trace ( M_state_machine_t m,
M_state_machine_trace_cb  cb,
void *  thunk 
)

Enabling tracing of state machine flow.

Parameters
[in]mThe state machine.
[in]cbTrace callback.
[in]thunkThunk to be passed to callback.

◆ M_state_machine_cleanup_enable_trace()

void M_state_machine_cleanup_enable_trace ( M_state_machine_cleanup_t m,
M_state_machine_trace_cb  cb,
void *  thunk 
)

Enabling tracing of cleanup state machine flow.

Parameters
[in]mThe cleanup state machine.
[in]cbTrace callback.
[in]thunkThunk to be passed to callback.

◆ M_state_machine_run()

M_state_machine_status_t M_state_machine_run ( M_state_machine_t m,
void *  data 
)

Run the state machine.

This may need to be called multiple times. A state can run non-blocking (poll based) where the state can return a wait state. The wait state means it finished processing but has more to do.

On error the cleanup state machine for the state will be called. When returning from a sub state machine which had clean up run the post function which can override and ignore an error can stop the cleanup process. Thus cleanup can be stopped and the state machine can recover from the error that started the process.

Parameters
[in,out]mThe state machine to run.
[in,out]dataState specific data that can be used and or manipulated by each state.
Returns
Result. The done and wait returns are the only successful results (wait requiring additional calls). All other results are error conditions.

◆ M_state_machine_reset()

void M_state_machine_reset ( M_state_machine_t m,
M_state_machine_cleanup_reason_t  reason 
)

Rest a running state machine.

A condition outside of the state machine could determine it needs to restart while it was in a running state. Not specifically running but in the middle of a run; having returned from a wait state for example. This will reset the state machine's internal process state so that it can be started from the beginning again.

This will not run cleanup immediately if requested but instead sets the state machine to start cleanup on next run. The sub state machine post function will not allow overriding the cleanup result and prevents the state machine from stopping cleanup. M_state_machine_run MUST be called. Also, remember that cleanup state machines can call wait so it may be necessary to run multiple times.

Parameters
[in,out]mThe state machine.
[in]reasonWhether state cleanups should run. Cleanup callbacks told cleanup is due to the reason code. Use M_STATE_MACHINE_CLEANUP_REASON_NONE to prevent cleanup.

◆ M_state_machine_ndescr()

M_uint64 M_state_machine_ndescr ( const M_state_machine_t m,
M_bool  recurse 
)

Get the numeric description of the state machine

Parameters
[in]mThe state machine.
[in]recurseRecurs into each running sub state machine and return the description for the one running.
Returns
The ndescr specified creating the state machine.

◆ M_state_machine_descr()

const char * M_state_machine_descr ( const M_state_machine_t m,
M_bool  recurse 
)

Get the description of the state machine

Parameters
[in]mThe state machine.
[in]recurseRecurse into each running sub state machine and return the description for the one running.
Returns
The descr text specified creating the state machine.

◆ M_state_machine_active_sub()

const M_state_machine_t * M_state_machine_active_sub ( const M_state_machine_t m,
M_bool  recurse 
)

Get the active sub state machine that is currently running.

Parameters
[in]mThe state machine.
[in]recurseRecurse into each running sub state machine and return the last one that is running.
Returns
Sub state machine if one is currently running. Otherwise, NULL.

◆ M_state_machine_active_state()

M_bool M_state_machine_active_state ( const M_state_machine_t m,
M_uint64 *  id 
)

Get state of the state machine.

This only returns information about the given state machine. It does not look into sub state machines if one is running.

Parameters
[in]mThe state machine.
[out]idThe id of the state currently being run. Optional pass NULL if only checking whether the state machine is running.
Returns
M_TRUE if the state machine has been started and the id is a valid state id. Otherwise M_FALSE.

◆ M_state_machine_active_state_ndescr()

M_uint64 M_state_machine_active_state_ndescr ( const M_state_machine_t m,
M_bool  recurse 
)

Get the numeric description for the currently running state.

Parameters
[in]mThe state machine.
[in]recurseRecurse into each running sub state machine and return the description for the one running.
Returns
The ndescr specified when adding the state to the state machine.

◆ M_state_machine_active_state_descr()

const char * M_state_machine_active_state_descr ( const M_state_machine_t m,
M_bool  recurse 
)

Get the description text for the currently running state.

Parameters
[in]mThe state machine.
[in]recurseRecurse into each running sub state machine and return the description for the one running.
Returns
The descr text specified when adding the state to the state machine.

◆ M_state_machine_descr_full()

char * M_state_machine_descr_full ( const M_state_machine_t m,
M_bool  show_id 
)

Get a textual representation of state machine and it's current state.

Parameters
[in]mThe state machine.
[in]show_idM_TRUE if the numeric representation of state ids should be included.
Returns
A compound description of every machine and state.

◆ M_state_machine_duplicate()

M_state_machine_t * M_state_machine_duplicate ( const M_state_machine_t m)

Duplicate an existing state machine.

Parameters
[in]mState machine to duplicate.
Returns
New state machine.