cnsm.c

/* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this * file for any purpose is hereby granted without fee, provided that * the above copyright notices and this notice appears in all source * code copies, and that none of the names of Open Software * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment * Corporation be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. Neither Open Software Foundation, Inc., Hewlett- * Packard Company, nor Digital Equipment Corporation makes any * representations about the suitability of this software for any * purpose. * *//* *//***** NAME**** cnsm.c**** FACILITY:**** Remote Procedure Call (RPC)**** ABSTRACT:**** The NCA Connection Protocol State Machine Service*****/#include <commonp.h>/* Common declarations for all RPC runtime */#include <com.h>/* Common communications services */#include <comprot.h>/* Common protocol services */#include <cnp.h>/* NCA Connection private declarations */#include <cnsm.h>/***********************************************************************//***++**** ROUTINE NAME: rpc__cn_sm_init**** SCOPE: PRIVATE - declared in cnsm.h**** DESCRIPTION:**** The routine will be used to initialize a state machine control** block. Depending on the type of state machine it will be called** in various places. It basically just fills in the table pointers** given, sets the state to closed and initializes the event list.**** INPUTS:**** state_tbl The state table this state machine is to use.** action_tbl The action routine table this state machine** is to use.** tbl_id The identifier of the particular action table** we are storing in the control block.**** INPUTS/OUTPUTS: none**** OUTPUTS:**** sm The state machine control block which is to** be initialized.**** IMPLICIT INPUTS: none**** IMPLICIT OUTPUTS: none**** FUNCTION VALUE: none**** SIDE EFFECTS: none****--**/
PRIVATE void rpc__cn_sm_init
#ifdef _DCE_PROTO_(
rpc_cn_sm_state_entry_p_t *state_tbl,
rpc_cn_sm_action_fn_p_t action_tbl,
rpc_cn_sm_ctlblk_p_t sm,
unsigned32 tbl_id
)
#else
(state_tbl, pred_tbl, action_tbl, sm)
rpc_cn_sm_state_entry_p_t *state_tbl;
rpc_cn_sm_action_fn_p_t action_tbl;
rpc_cn_sm_ctlblk_p_t sm;
unsigned32 tbl_id;
#endif{
/* * Put the pointers to the given tables into the state machine * control block. */
sm->state_tbl = state_tbl;
sm->action_tbl = action_tbl;
/* * Set the initial state in the state machine control block to * "closed". */
sm->cur_state = RPC_C_SM_CLOSED_STATE;
/* * Store the tbl_id in the controlblock and use it later * to selectively bypass calls to the event evaluation * routine, going directly to the action routines. */
sm->tbl_id = tbl_id;
/* * Initialize the state machine control block event list. */
rpc__cn_sm_init_event_list(sm);
}
/***++**** ROUTINE NAME: rpc__cn_sm_init_event_list**** SCOPE: PRIVATE - declared in cnsm.h**** DESCRIPTION:**** This routine will initialize the event list contained in the** specified state machine control block. This routine is called as** part of initializing the state machine control block.**** INPUTS: none**** INPUTS/OUTPUTS: none**** OUTPUTS:**** sm The state machine control block containing** the event list to be initialized.**** IMPLICIT INPUTS: none**** IMPLICIT OUTPUTS: none**** FUNCTION VALUE: none**** SIDE EFFECTS: none****--**/
PRIVATE void rpc__cn_sm_init_event_list
#ifdef _DCE_PROTO_(
rpc_cn_sm_ctlblk_t *sm
)
#else
(sm)
rpc_cn_sm_ctlblk_t *sm;
#endif{
/* * Set up the event list so that it's empty. This means the state * must be set to "empty" and the head and tail indices must be * zeroed. */
sm->event_list_state = RPC_C_CN_SM_EVENT_LIST_EMPTY;
sm->event_list_hindex = 0;
sm->event_list_tindex = 0;
}
/***++**** ROUTINE NAME: rpc__cn_sm_eval_event**** SCOPE: PRIVATE - declared in cnsm.h**** DESCRIPTION:**** This routine will be used to evaluate an event for the specified** state machine. It handles the main work of running a state** machine. It will look up either action or state transition for** events. The lookup will return either a state or action.** Distinguish between states and actions by numeric range.**** INPUTS:**** event_id The number of the event to be processed.** event_param The special event related parameter which is** to be passed to the predicate and action** routines for the processing of this event.** spc_struct A special parameter which is to be passed to** the predicate and action routines for the** processing of this event and any subsequent** events which are inserted on the event list.**** INPUTS/OUTPUTS:**** sm The state machine control block to be used** in processing this event.**** OUTPUTS: none**** IMPLICIT INPUTS: none**** IMPLICIT OUTPUTS: none**** FUNCTION VALUE: The status returned by the last action** routine invoked.**** SIDE EFFECTS: none****--**/
PRIVATE unsigned32 rpc__cn_sm_eval_event
#ifdef _DCE_PROTO_(
unsigned32 event_id,
pointer_t event_parameter,
pointer_t spc_struct,
rpc_cn_sm_ctlblk_t *sm
)
#else
(event_id, event_parameter, spc_struct, sm)
unsigned32 event_id;
pointer_t event_parameter;
pointer_t spc_struct;
rpc_cn_sm_ctlblk_t *sm;
#endif{
rpc_cn_sm_event_entry_t next_event;
unsigned8 action_index;
boolean more_events;
rpc_cn_sm_state_entry_t *state_entry_p;
/* * Initialize action status to ok. This allows state transitions * which do not invoke action routines to signal normal completion. */
sm->action_status = rpc_s_ok;
/* * Set up the first event to be evaluated using the input args. */
next_event.event_id = event_id;
next_event.event_param = event_parameter;
/* * Process the first event and any events which get added. */
more_events = true;
while (more_events)
{
/* * Pick up the state table entry to the current state. The * value in the state table is going to be either a next * state or an action. If it is an action, we take that * action and within the action routine, update sm->cur_state. * In cases where there is no action but there is a next state, * we can just store the next state. We distinguish between * actions and state by their numeric value. Next states are * always greater than or equal to rpc_c_cn_statebase. * Since states are also used to access an array entry, we need * to subtract the value we added in order to distinguish it * from an action routine, before we can access the array. */
state_entry_p = sm->state_tbl[(sm->cur_state -
RPC_C_CN_STATEBASE)];
/* * Look up the index of the action routine using the current * state and the id of the event being processed. */
action_index = state_entry_p[(next_event.event_id -
RPC_C_CN_STATEBASE )].action;
/* * If there is no action to take, just transition to the next * state which is the value returned from the state table * lookup (state_entry_p). */if (action_index >= RPC_C_CN_STATEBASE)
{
sm->cur_state = action_index;
}
else
{
/* * Call the action routine. The spc_struct and event_param * and sm will be passed to the action routine. Note * that sm is changed within the action routines. Each * action routine will update sm->cur_state. */
sm->cur_event = next_event.event_id;
sm->action_status =
(*(sm->action_tbl[action_index]))
(spc_struct, next_event.event_param, sm);
}
/* * Get the next event, if any, off the event list in the * state machine control block. RPC_CN_SM_GET_NEXT_EVENT * will set more_events to true or false depending on * whether there are more events to process. */
RPC_CN_SM_GET_NEXT_EVENT (sm, &next_event, more_events);
}
return (sm->action_status);
}
/***++**** ROUTINE NAME: rpc__cn_sm_insert_event**** SCOPE: PRIVATE - declared in cnsm.h**** DESCRIPTION:**** This routine inserts a new event entry on the state machine** control block event list. If the list is full the event can't be** inserted and false will be returned.**** INPUTS:**** event The event entry being inserted.**** INPUTS/OUTPUTS:**** sm The state machine control block containing** the event list.**** OUTPUTS:**** IMPLICIT INPUTS: none**** IMPLICIT OUTPUTS: none**** FUNCTION VALUE: none**** SIDE EFFECTS: none****--**/
PRIVATE void rpc__cn_sm_insert_event
#ifdef _DCE_PROTO_(
rpc_cn_sm_event_entry_p_t event,
rpc_cn_sm_ctlblk_t *sm
)
#else
(event, sm)
rpc_cn_sm_event_entry_p_t event;
rpc_cn_sm_ctlblk_t *sm;
#endif{
#ifdef DEBUG/* * Check whether the event list is full. This condition occurs * when the head and tail indices are equal and the state * indicates the list is not empty. */if ((sm->event_list_hindex == sm->event_list_tindex) &&
(sm->event_list_state != RPC_C_CN_SM_EVENT_LIST_EMPTY))
{
/* * rpc_m_eventlist_full * "(%s) Event list full" */
RPC_DCE_SVC_PRINTF ((
DCE_SVC(RPC__SVC_HANDLE, "%s"),
rpc_svc_cn_state,
svc_c_sev_fatal | svc_c_action_abort,
rpc_m_eventlist_full,
"rpc__cn_sm_insert_event" ));
}
#endif/* * There's room on the event list. Add the new entry to the tail * of the list. */
sm->event_list[sm->event_list_tindex].event_id = event->event_id;
sm->event_list[sm->event_list_tindex].event_param = event->event_param;
/* * Add the event to the event list by incrementing the tail * index and checking for wraparound. Also set the state of the * event list to non-empty. */
sm->event_list_tindex = (sm->event_list_tindex + 1) &
(RPC_C_CN_SM_EVENT_LIST_MAX_ENTRIES - 1);
sm->event_list_state = ~RPC_C_CN_SM_EVENT_LIST_EMPTY;
}