4.3.6 Working with the Node Call Stack

An event sent to the event handler of an instruction meta-class or instruction class set has an associated reference to a node call stack containing information about nodes that received control but have not yet returned it. A node can occur in multiple stack frames if calls to it are recursive. The field stack_sz_max of qsmm_desc_s structure specifies a limit on the number of frames in the stack. The function qsmm_get_stack_sz_max returns the limit. The following function returns the current number of frames in the stack.

Function: int qsmm_get_mehcall_stack_sz (qsmm_mehcall_t mehcall)

This function returns the current number of frames in a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. A returned value is always non-negative.

A system stack frame is system part of a frame of node call stack. Each system stack frame contains the following information:

Use the following functions to fetch the aforementioned pieces of information from system part of a node call stack frame at specified depth.

Function: int qsmm_get_mehcall_stack_node (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *node_p)

This function fetches the identifier of a called node from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event.

If node_p is not NULL, the function sets *node_p to a fetched node identifier. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

Function: int qsmm_get_mehcall_stack_state (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *state_p)

This function fetches the index of a node state from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. The environment state identification engine has identified the node state.

If state_p is not NULL, the function sets *state_p to a fetched node state or 0 if state is yet unknown (this is the case when the event handler of an instruction class set called this function on processing an event QSMM_EVT_NODE_ENTER). The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

Function: int qsmm_get_mehcall_stack_instr_class (qsmm_mehcall_t mehcall, int depth, qsmm_sig_t *instr_class_p)

This function fetches the index of the instruction class of the last invoked instruction from system part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event. The instruction emitting engine has selected that instruction class.

If instr_class_p is not NULL, the function sets *instr_class_p to a fetched instruction class index or QSMM_SIG_INVALID if a called node has not yet invoked any instruction since creating the stack frame. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

See Registering Instruction Classes, for the means of obtaining information about an instruction class specified by its index.

A user stack frame is user part of a frame of node call stack. A user stack frame contains application-specific information associated with a called node for handling instruction invocations—execution context of the node.

A user stack frame is typically an instance of a structure declared in an application program. The purpose of functions described below is to query or set the size of user stack frame. You should set the size of user stack frame before creating a model instance by the function qsmm_engine_create.

Function: size_t qsmm_get_stack_frame_sz (qsmm_t model)

This function returns the size (in bytes) of user part of each frame in the node call stack of a multinode model. If the model does not use the user part, the function returns 0.

Function: int qsmm_set_stack_frame_sz (qsmm_t model, size_t sz)

This function sets the size of user part of each frame in the node call stack of a multinode model to sz bytes. Size 0 means that the model does not use the user part.

The function returns a non-negative value on success or negative error code QSMM_ERR_UNTIMELY if a model instance already exists.

The function qsmm_create initializes to 0 the size of user stack frame.

On calling a node, the function qsmm_node_call_default creates a new frame in the node call stack and initializes user part of the frame with zero bytes. The new frame becomes the current stack frame. The function qsmm_get_mehcall_stack_sz returns the number of used frames in the node call stack.

After creating a current stack frame, qsmm_node_call_default sends an event QSMM_EVT_NODE_ENTER to the instruction class set of a called node. The event handler of that instruction class set can process the event to perform application-specific initialization of the stack frame. For example, the event handler may allocate dynamic arrays or copy the parameters of calling the node to the frame. A pointer to the parameters is an argument of qsmm_node_call_default function, and it passes the pointer to the event handler via mehcall->param_p, where mehcall is an event handler argument.

While executing a node, qsmm_node_call_default sends events QSMM_EVT_ACTIVATE to instruction meta-classes of instructions selected for invocation by the instruction emitting engine. The event handler of an instruction meta-class can call the function qsmm_set_mehcall_return with a non-zero flag to return control from the node. The event handler can also call the function qsmm_set_continue with zero flag or the macro QSMM_TERMINATE to return control from all nodes in the node call stack.

On returning control from a node, qsmm_node_call_default sends an event QSMM_EVT_NODE_LEAVE to the instruction class set of the node. The event handler of that instruction class set can use the content of a current stack frame to compute the results of node invocation and return them via a memory block addressed by a pointer mehcall->param_p passed as an argument to qsmm_node_call_default. If necessary, the event handler performs application-specific uninitialization of the stack frame—for example, frees allocated dynamic arrays.

After sending the event QSMM_EVT_NODE_LEAVE, qsmm_node_call_default discards the current stack frame and exits. If after discarding the stack frame the node call stack is not empty, the previous frame in the stack becomes the current frame.

Use the following function to get a pointer to user part of a frame in the node call stack.

Function: int qsmm_get_mehcall_stack_frame (qsmm_mehcall_t mehcall, int depth, void **frame_pp)

This function retrieves a pointer to user part of a frame of a node call stack referenced in an event sent to the event handler of an instruction meta-class or instruction class set, where mehcall is an argument of that event handler passing information about the event.

If frame_pp is not NULL, the function sets *frame_pp equal to the pointer. A program can access a memory block with size in bytes returned by the function qsmm_get_stack_frame_sz addressed by the pointer. The argument depth specifies stack frame depth. Depth 0 corresponds to the current stack frame, depth 1 corresponds to the previous stack frame, and so on.

The function returns a non-negative value on success or a negative error code on failure. Currently, the function can return the following error codes.

QSMM_ERR_NOUSTACK

The model does not have user part in the frames of node call stack. Use the function qsmm_set_stack_frame_sz to specify positive user part size before creating the model instance.

QSMM_ERR_UNTIMELY

The node call stack is empty.

QSMM_ERR_INVAL

The argument depth is negative or greater than or equal to the number of frames in the node call stack returned by the function qsmm_get_mehcall_stack_sz.

If the structure stack_frame_s holds a user stack frame, use the following call to set its size:

qsmm_set_stack_frame_sz(qsmm,sizeof(struct stack_frame_s));

To get a pointer to a current stack frame, use these lines in an event handler function:

struct stack_frame_s *stack_frame_p=0;
qsmm_get_mehcall_stack_frame(mehcall,0,(void **) &stack_frame_p);