sys-get-eattr.sm/.c文件记录了很小的一个状态机,只有三个状态。以此为例,说明状态机定义文件(.sm)、状态机源代码(.c)的格式和语义。其中,.c文件是.sm文件经common/statecomp组件编译后的产物,两者基本结构大体相同,.sm文件采用更便利开发人员的表达方式,而.c文件是符合C语言语法的表达方式,供状态机执行逻辑直接使用。
.sm主要分为三部分,各部分之间使用“%%”分隔:
- 声明部分
包括所有的头文件引用和需要声明的函数。
根据文档规定,所有动作函数均需要在此述首先声明(state actions must be declared here before the state machine),但实际的.sm文件通常不作声明,因为编译器可以直接根据第2部分的状态机描述自动添加动作函数的声明。另外,第3部分中所有需要在定义前使用的函数都应在此处声明,否则编译后的.c文件不符合C语言规定。 - 状态机描述部分
依次写明各个状态(state),首状态为起始状态。每个状态包括:
(1) 一个动作(action),进入该状态后首先执行该动作。对应动作可以是调用特定函数,也可以是跳转到其他状态机。
(2) 若干转移(transtition),每个转移由标志值和跳转到的状态两部分组成。其中标志值由上述动作函数设定,并根据此值选择对应的转移,进入下一个状态。 - 函数定义部分
包括第2部分提到的动作函数、状态机为使用者提供的接口函数,以及其他自定义函数。动作函数的返回值决定状态机执行状况,如果是SM_ACTION_DEFERED,状态机会等待结果;如果是SM_ACTION_COMPLETE,状态机会继续运行,即开始根据标志值转入下一个状态;如果是SM_ACTION_TERMINATE,状态机则会终止。
下面以sys-get-eattr.sm为例,说明上述各个部分:
- 声明部分
这里只声明了一个函数。因为在第3部分,该函数定义位于最后,而之前的函数中存在对它的引用,所以必须在引用前声明,只能安排在此部分。 - 状态机描述部分
很显然,声明了三个状态setup_msgpair、xfer_msgpair和cleanup。以状态setup_msgpair为例,后面几行表达的语义是,进入状态后执行动作函数get_eattr_setup_msgpair;函数返回后,如果标志值为success(即整型的0),则转入状态xfer_msgpair;如果标志值为default(即整型值-1),则转入状态cleanup。
注意状态xfer_msgpair的动作是“jump”,意思是跳转到另一个嵌套的状态机,这里是跳转到pvfs2_msgpairarray_sm。
下图描述了该状态机: - 函数定义部分
一共定义了6个函数:
PVFS_error PVFS_isys_geteattr_list
PVFS_error PVFS_sys_geteattr_list
PVFS_error PVFS_sys_geteattr
static PINT_sm_action get_eattr_setup_msgpair
static PINT_sm_action get_eattr_cleanup
static int get_eattr_comp_fn
其中第4个和第5个(上段代码的39行~60行)是第2部分描述的动作函数;第3个函数为接口函数,供外部程序调用该状态机,它使用了第1个和第2个函数;第6个函数在上段代码的第45行被引用,且在其定义之前,所以该函数在第1部分进行了声明。
这个sys-get-eattr.sm文件是为方便开发人员描述状态机设计的,编译后生成符合C语言语法的sys-get-eattr.c文件,该文件与状态机控制逻辑配合执行实际操作。因此可以与sys-get-eattr.c对照阅读以加深对状态机的理解,参见sys-get-eattr.c状态机代码 。