spot/iface/nips/nips_vm/instr_step.c
Guillaume Sadegh bc5f13bb4e NIPS VM added to the SPOT distribution.
2008-05-29  Guillaume SADEGH  <sadegh@lrde.epita.fr>

	* iface/nips/nips.cc, iface/nips/nips.hh, iface/nips/common.cc,
	iface/nips/common.hh, iface/nips/Makefile.am: TGBA implementation
	with the NIPS library.
	* iface/nips/emptiness_check.cc: Emptiness check on a Promela
	interface.
	* iface/nips/dottynips.cc: Dot printer on the NIPS interface.
	* iface/nips/compile.sh: Add. Wrapper around nips compiler to
	compile Promela to NIPS bytecode.
	* iface/nips/nips_vm,iface/nips/nips_vm/bytecode.h,
	iface/nips/nips_vm/ChangeLog, iface/nips/nips_vm/COPYING,
	iface/nips/nips_vm/hashtab.c, iface/nips/nips_vm/hashtab.h,
	iface/nips/nips_vm/INSTALL, iface/nips/nips_vm/instr.c,
	iface/nips/nips_vm/instr.h, iface/nips/nips_vm/instr_step.c,
	iface/nips/nips_vm/instr_step.h,
	iface/nips/nips_vm/instr_tools.c,
	iface/nips/nips_vm/instr_tools.h,
	iface/nips/nips_vm/instr_wrap.c,
	iface/nips/nips_vm/instr_wrap.h,
	iface/nips/nips_vm/interactive.c,
	iface/nips/nips_vm/interactive.h, iface/nips/nips_vm/main.c,
	iface/nips/nips_vm/Makefile, iface/nips/nips_vm/Makefile.am,
	iface/nips/nips_vm/nips_asm_help.pl,
	iface/nips/nips_vm/nips_asm_instr.pl,
	iface/nips/nips_vm/nips_asm.pl,
	iface/nips/nips_vm/nips_disasm.pl, iface/nips/nips_vm/nipsvm.c,
	iface/nips/nips_vm/nipsvm.h, iface/nips/nips_vm/README,
	iface/nips/nips_vm/rt_err.c, iface/nips/nips_vm/rt_err.h,
	iface/nips/nips_vm/search.c, iface/nips/nips_vm/search.h,
	iface/nips/nips_vm/split.c, iface/nips/nips_vm/split.h,
	iface/nips/nips_vm/state.c, iface/nips/nips_vm/state.h,
	iface/nips/nips_vm/state_inline.h,
	iface/nips/nips_vm/state_parts.c,
	iface/nips/nips_vm/state_parts.h, iface/nips/nips_vm/timeval.h,
	iface/nips/nips_vm/tools.h: NIPS VM added to the SPOT
	distribution.
	* configure.ac, iface/Makefile.am: Build system updated for the
	NIPS front-end.
2008-05-30 13:22:00 +02:00

674 lines
32 KiB
C

/* NIPS VM - New Implementation of Promela Semantics Virtual Machine
* Copyright (C) 2005: Stefan Schuermans <stefan@schuermans.info>
* Michael Weber <michaelw@i2.informatik.rwth-aachen.de>
* Lehrstuhl fuer Informatik II, RWTH Aachen
* Copyleft: GNU public license - http://www.gnu.org/copyleft/gpl.html
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "bytecode.h"
#include "instr.h"
#include "instr_step.h"
#include "state.h"
#include "tools.h"
// #define DEBUG_INVIS // print invisible states
// default maximum values (i.e. buffer sizes) for successor state generation
#define INSTR_DEF_STACK_MAX 64 // number of entries in the stack during execution of a step
// type is uint8_t because stack pointer is an uint8_t
#ifdef SMALLSTACK // (reduce sizes for windows, because default stack size is only 1MB)
# warning Building with reduced stack size demands.
# define INSTR_DEF_STATE_MEM 65536 // size of memory for temporary states within a step
# define INSTR_DEF_ENAB_STATE_MEM 8192 // size of memory for temporary states within a step in ENAB instruction
# define INSTR_DEF_INVIS_MEM 8192 // size of memory to store invisible states for further execution
#else
# define INSTR_DEF_STATE_MEM 262144 // size of memory for temporary states within a step
# define INSTR_DEF_ENAB_STATE_MEM 32768 // size of memory for temporary states within a step in ENAB instruction
# define INSTR_DEF_INVIS_MEM 32768 // size of memory to store invisible states for further execution
#endif
#define INSTR_DEF_PATH_MAX 256 // maximum number of states on stack during execution of a step
// maximum number of possible nondeterministic paths within a step
#define INSTR_DEF_INVIS_MAX 256 // maximum number of invisible states that can be stored
#define INSTR_DEF_SUCC_MAX 256 // maximum number of possible successor states during execution of a step
// maximum number of executable nondeterministic paths within a step
// type for numbers of successor states (of system and total)
typedef struct t_instr_succ_cnts
{
unsigned int sys; // successor count of system
unsigned int total; // total successor cnt
} st_instr_succ_cnts;
// type to save parameters of 1st part while executing 2nd part of sync. comm.
typedef struct t_instr_prm_save_sync
{
uint8_t label; // label returned by 1st part
t_flag_reg flag_reg; // flag register value returned by 1st part
st_instr_output *p_output; // output done by 1st part
} st_instr_prm_save_sync;
// type to save parameters of system while executing monitor process
typedef struct t_instr_prm_save_monitor
{
st_instr_prm_save_sync * p_prm_1st; // saved settings from 1st part of sync. comm.
uint8_t label; // label returned by step of normal system
t_flag_reg flag_reg; // flag register value returned by normal system
st_instr_output *p_output; // output done by normal system
} st_instr_prm_save_monitor;
// type for internal successor callback function
typedef et_ic_status (*instr_int_succ_cb_t)( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
t_pid pid, // pid of process that executed
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
unsigned int succ_cb_flags, // flags accumulated so far
st_instr_succ_context *p_succ_ctx, // context for successor state generation
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
void *p_int_ctx ); // private context
// execute a step in a process
// - callbacks in context are called for every event (e.g. errors)
// - returns instruction callback status
static et_ic_status instr_proc_step( st_global_state_header *p_glob, // state to start with
st_process_header *p_proc, // process to execute
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
t_pid monitor_last, // pid of process that did last step (0 if not executing monitor)
unsigned int succ_cb_flags, // flags already accumulated for successor callback
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
void *p_int_ctx, // private context for int_succ_cb
char **pp_invis_buf, unsigned long *p_invis_buf_len, // buffer for invisible states
st_instr_tmp_succ **pp_invis_tmp_succ, unsigned int *p_invis_tmp_succ_cnt, // array for invisible states
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts,
unsigned int *p_state_cnt ) // number of resulting states
{
// buffer for temporary states
char tmp_buf[p_succ_ctx->state_mem];
char *p_tmp_buf = tmp_buf;
unsigned long tmp_buf_len = sizeof( tmp_buf );
// activate process
st_process_active_header *p_proc_act;
st_global_state_header *p_glob_act = global_state_copy_activate( p_glob, p_proc,
p_succ_ctx->stack_max, flag_reg,
&p_tmp_buf, &tmp_buf_len,
&p_proc_act );
if( p_glob_act == NULL )
return p_succ_ctx->err_cb( IE_STATE_MEM, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
p_succ_ctx->priv_context );
// reset monitor accept flag in process header
p_proc_act->proc.flags &= ~PROCESS_FLAGS_MONITOR_ACCEPT;
// set up context to execute instructions
st_instr_context ctx;
st_instr_context_state states[p_succ_ctx->path_max]; // create stack of states to process
states[0].p_glob = p_glob_act;
states[0].p_output = NULL;
states[0].max_step_cnt = (unsigned int)-1; // process this state in any case
ctx.p_states = states;
ctx.state_cnt_max = count( states );
ctx.state_cnt = 1;
ctx.step_cnt = 0; // no step completed yet
ctx.pp_buf = &p_tmp_buf; // fill in pointers for buffer with memory for new temporary states
ctx.p_buf_len = &tmp_buf_len;
ctx.init_flag_reg = flag_reg;
ctx.timeout = timeout;
ctx.last_pid = monitor_last;
ctx.p_succ_ctx = p_succ_ctx;
// execute instructions until all paths are done
st_instr_tmp_succ tmp_succs[p_succ_ctx->succ_max];
unsigned int tmp_succ_cnt = 0;
if( instr_exec_paths( &ctx, 0, // do not stop on first state found
tmp_succs, count( tmp_succs ), &tmp_succ_cnt ) == IC_STOP )
return IC_STOP;
// process all completed states
unsigned int i;
for( i = 0; i < tmp_succ_cnt; i++ )
{
(*p_state_cnt)++;
// invisible state
if( tmp_succs[i].invisible && // state marked as invisible
! tmp_succs[i].sync_comm && // no synchronous communication in progress (sync. comm. forces visibility)
tmp_succs[i].p_output == NULL ) // no output done (outout forces visibility)
{
// put invisible state into buffer for invisible states
st_global_state_header * p_glb = global_state_copy( tmp_succs[i].p_glob, // copy state
pp_invis_buf, p_invis_buf_len );
if( p_glb == NULL )
return p_succ_ctx->err_cb( IE_INVIS_MEM, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
p_succ_ctx->priv_context );
if( *p_invis_tmp_succ_cnt == 0 ) // put copy of state into array
return p_succ_ctx->err_cb( IE_INVIS_CNT, be2h_pid( p_proc->pid ), be2h_pc( p_proc->pc ),
p_succ_ctx->priv_context );
**pp_invis_tmp_succ = tmp_succs[i];
(**pp_invis_tmp_succ).p_glob = p_glb;
(*pp_invis_tmp_succ)++;
(*p_invis_tmp_succ_cnt)--;
}
// visible state
else
{
// report state to caller
if( int_succ_cb( &tmp_succs[i], // successor state
be2h_pid( p_proc->pid ), // pid of process that executed
flag_reg, // initial value for flag register of process
timeout, // boolean flag if timeout
succ_cb_flags, // flags accumulated so far
p_succ_ctx, p_succ_cnts,
p_int_ctx ) == IC_STOP )
return IC_STOP;
}
} // for( i ...
return IC_CONTINUE;
}
// execute steps in a process
// - callbacks in context are called for every event (e.g. errors)
// - continues execution for invisible states are reached
// - returns instruction callback status
static et_ic_status instr_proc_steps( st_global_state_header *p_glob, // state to start with
st_process_header *p_proc, // process to execute
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
t_pid monitor_last, // pid of process that did last step (0 if not executing monitor)
unsigned int succ_cb_flags, // flags already accumulated for successor callback
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
void *p_int_ctx, // private context for int_succ_cb
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
{
// buffers for invisible states
char invis_bufs[2][p_succ_ctx->invis_mem];
st_instr_tmp_succ invis_tmp_succs[2][p_succ_ctx->invis_max];
int invis_buf_idx = 0; // active buffer
// save pid of process to execute
t_pid exec_pid = be2h_pid( p_proc->pid );
// initialize buffer for invisible states
char *p_invis_buf = invis_bufs[invis_buf_idx];
unsigned long invis_buf_len = sizeof( invis_bufs[invis_buf_idx] );
st_instr_tmp_succ *p_invis_tmp_succs = invis_tmp_succs[invis_buf_idx];
unsigned int invis_tmp_succ_cnt = count( invis_tmp_succs[invis_buf_idx] );
// process initial state
unsigned int state_cnt = 0;
if( instr_proc_step( p_glob, p_proc,
flag_reg, timeout, monitor_last,
succ_cb_flags, int_succ_cb, p_int_ctx,
&p_invis_buf, &invis_buf_len,
&p_invis_tmp_succs, &invis_tmp_succ_cnt,
p_succ_ctx, p_succ_cnts, &state_cnt ) == IC_STOP )
return IC_STOP;
// as long as there are states in buffer
for( ; ; )
{
// get pointer to and number of states in buffer
st_instr_tmp_succ *p_tmp_succs = invis_tmp_succs[invis_buf_idx];
unsigned int tmp_succ_cnt = count( invis_tmp_succs[invis_buf_idx] ) - invis_tmp_succ_cnt;
// no more states ---> exit loop
if( tmp_succ_cnt == 0 )
break;
// initialize buffer for new invisible states to use other buffer
p_invis_buf = invis_bufs[1 - invis_buf_idx];
invis_buf_len = sizeof( invis_bufs[1 - invis_buf_idx] );
p_invis_tmp_succs = invis_tmp_succs[1 - invis_buf_idx];
invis_tmp_succ_cnt = count( invis_tmp_succs[1 - invis_buf_idx] );
// process all states in buffer
for( ; tmp_succ_cnt > 0 ; tmp_succ_cnt--, p_tmp_succs++ )
{
#ifdef DEBUG_INVIS
printf( "DEBUG (invisible state): " );
global_state_print( p_tmp_succs->p_glob );
#endif
// get process to execute
st_process_header *p_prc = global_state_get_process( p_tmp_succs->p_glob, exec_pid );
if( p_prc != NULL )
{
unsigned int state_cnt = 0;
// if this process became the monitor or ceased to be the monitor
// while executing an invisible step
// then the next step is not executable according to the formal model
// so force this behaviour in this implementation
if( (p_glob->monitor_pid == p_proc->pid) == (p_tmp_succs->p_glob->monitor_pid == p_prc->pid) )
{
// process state
if( instr_proc_step( p_tmp_succs->p_glob, p_prc,
flag_reg, timeout, monitor_last,
succ_cb_flags, int_succ_cb, p_int_ctx,
&p_invis_buf, &invis_buf_len,
&p_invis_tmp_succs, &invis_tmp_succ_cnt,
p_succ_ctx, p_succ_cnts, &state_cnt ) == IC_STOP )
return IC_STOP;
}
// no resulting states -> report original state to caller
if( state_cnt == 0 )
{
if( int_succ_cb( p_tmp_succs, // successor state
exec_pid, // pid of process that executed
flag_reg, // initial value for flag register of process
timeout, // boolean flag if timeout
succ_cb_flags, // flags accumulated so far
p_succ_ctx, p_succ_cnts,
p_int_ctx ) == IC_STOP )
return IC_STOP;
}
}
} // for( ; tmp_succ_cnt > 0; ...
// swap buffers
invis_buf_idx = 1 - invis_buf_idx;
} // for( ; ; )
return IC_CONTINUE;
}
// execute a system step (and monitor step afterwards)
// - callbacks in context are called for every event (e.g. a successor state)
// - returns instruction callback status
static et_ic_status instr_sys_step( st_global_state_header *p_glob, // state to start with
t_flag_reg flag_reg, // initial value for flag register
unsigned int succ_cb_flags, // flags already accumulated for successor callback
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
void *p_int_ctx, // private context for int_succ_cb
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
{
// get enabled processes
st_process_header *procs[PID_MAX]; // there cannot be more than PID_MAX processes
unsigned int proc_cnt = global_state_get_enabled_processes( p_glob, procs, count( procs ) );
if( proc_cnt == (unsigned int)-1 ) // too many enabled processes
return p_succ_ctx->err_cb( IE_EN_PROC_CNT, 0, 0, p_succ_ctx->priv_context );
// execute a step in every enabled process / in the process running exclusively
unsigned int sys_succ_cnt_start = p_succ_cnts->sys;
int timeout;
for( timeout = 0; timeout <= 1; timeout++ ) // first try timeout = 0, then try timeout = 1
{
unsigned int i;
// a process is running exclusively (and it is not the monitor)
if( p_glob->excl_pid != h2be_pid( 0 ) && p_glob->excl_pid != p_glob->monitor_pid )
{
for( i = 0; i < proc_cnt; i++ ) // search this process
if( procs[i]->pid == p_glob->excl_pid )
break;
if( i < proc_cnt ) // found this process
{
if( instr_proc_steps( p_glob, procs[i],
flag_reg, timeout,
0, // executing normal system (not monitor)
succ_cb_flags, int_succ_cb, p_int_ctx,
p_succ_ctx, p_succ_cnts ) == IC_STOP ) // execute this process
return IC_STOP; // some callback requested stop
if( p_succ_cnts->sys > sys_succ_cnt_start ) // process can do a step
return IC_CONTINUE; // ignore other processes
}
}
// execute every enabled process (except monitor)
for( i = 0; i < proc_cnt; i++ )
if( procs[i]->pid != p_glob->monitor_pid )
if( instr_proc_steps( p_glob, procs[i],
flag_reg, timeout,
0, // executing normal system (not monitor)
succ_cb_flags, int_succ_cb, p_int_ctx,
p_succ_ctx, p_succ_cnts ) == IC_STOP )
return IC_STOP; // some callback requested stop
if( p_succ_cnts->sys > sys_succ_cnt_start ) // at least one successor state
return IC_CONTINUE; // do not try again with timeout set
// set timeout flag
succ_cb_flags |= INSTR_SUCC_CB_FLAG_TIMEOUT;
}
return IC_CONTINUE;
}
// execute a monitor step
// - callbacks in context are called for every event (e.g. a successor state)
// - returns instruction callback status
static et_ic_status instr_monitor_step( st_global_state_header *p_glob, // state to start with
uint8_t last_pid, // pid of process that executed last step
unsigned int succ_cb_flags, // flags already accumulated for successor callback
instr_int_succ_cb_t int_succ_cb, // internal successor callback function
void *p_int_ctx, // private context for int_succ_cb
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
{
// get monitor process if available
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
st_process_header *p_monitor = NULL;
if( monitor_pid != 0 )
p_monitor = global_state_get_process( p_glob, monitor_pid );
// monitor process is not available or terminated
if( p_monitor == NULL ||
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
return IC_CONTINUE;
// monitor process exists
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_EXIST;
// execute a step in the monitor process
unsigned int succ_cnt_start = p_succ_cnts->total;
int timeout;
for( timeout = 0; timeout <= 1; timeout++ ) // first try timeout = 0, then try timeout = 1
{
// execute monitor process
if( instr_proc_steps( p_glob, p_monitor,
0, timeout, // monitor starts always with flag_reg = 0
last_pid, // executing monitor
succ_cb_flags, int_succ_cb, p_int_ctx,
p_succ_ctx, p_succ_cnts ) == IC_STOP )
return IC_STOP; // some callback requested stop
if( p_succ_cnts->total > succ_cnt_start ) // at least one successor state
return IC_CONTINUE; // do not try again with timeout set
}
// when we get here, there was no successor state with timeout = 0 and none with timeout = 1
// ---> monitor process is blocked
// ---> no successor state
return IC_CONTINUE;
}
// internal successor callback function for monitor successor states
et_ic_status instr_monitor_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
t_pid pid, // pid of process that executed
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
unsigned int succ_cb_flags, // flags accumulated so far
st_instr_succ_context *p_succ_ctx, // context for successor state generation
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
void *vp_prm_sys ) // private context: saved settings of system
{
st_instr_prm_save_monitor *p_prm_sys = (st_instr_prm_save_monitor *)vp_prm_sys;
// synchronous communication is still going on
if( p_succ->sync_comm )
// synchronous communication in monitor is not allowed -> invalid state
return IC_CONTINUE;
// monitor executed a step
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_EXEC;
// set flags if monitor is in accepting state
st_process_header *p_monitor = global_state_get_process( p_succ->p_glob, pid );
if( p_monitor != NULL &&
bytecode_flags( p_succ_ctx->bytecode, be2h_pc( p_monitor->pc ) ) & BC_FLAG_ACCEPT )
{
p_monitor->flags |= PROCESS_FLAGS_MONITOR_ACCEPT; // set flag in process header of monitor process
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT; // set flag for successor callback
}
// set flag if monitor is terminated
if( p_monitor == NULL ||
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
succ_cb_flags |= INSTR_SUCC_CB_FLAG_MONITOR_TERM; // set flag for successor callback
// count state and report it to user
p_succ_cnts->total++;
st_instr_succ_output succ_out = // assemble structure with output
{
.p_out_sys1st = p_prm_sys->p_prm_1st->p_output, // output of system during 1st part of sync. comm.
.p_out_sys = p_prm_sys->p_output, // output of system
.p_out_monitor = p_succ->p_output // output of monitor
};
return p_succ_ctx->succ_cb( p_succ->p_glob, // report resulting state
p_prm_sys->p_prm_1st->label, p_prm_sys->label, // pass on saved settings of system
p_prm_sys->p_prm_1st->flag_reg, p_prm_sys->flag_reg,
succ_cb_flags, // pass on calulated flags
&succ_out,
p_succ_ctx->priv_context );
// keep compiler happy
flag_reg = 0;
timeout = 0;
}
// execute monitor on system successor state
static et_ic_status instr_exec_monitor( st_instr_tmp_succ *p_sys_succ, // successor state of system (with label, flag_reg, ...)
st_instr_prm_save_sync *p_prm_1st, // saved parameters of 1st part of sync. comm. of system
uint8_t last_pid, // pid of process that executed last step
unsigned int succ_cb_flags, // flags already accumulated for successor callback
st_instr_succ_context *p_succ_ctx, st_instr_succ_cnts *p_succ_cnts )
{
// count system's successor state
// - monitor is executed on every successor state of system
// - so system's successor states can be counted here
p_succ_cnts->sys++;
// save parameters returned by normal system
st_instr_prm_save_monitor prm_sys =
{
.p_prm_1st = p_prm_1st, // saved settings from 1st part of sync. comm.
.label = p_sys_succ->label, // label returned by normal system
.flag_reg = p_sys_succ->flag_reg, // flag register value returned by normal system
.p_output = p_sys_succ->p_output, // output done by normal system
};
// there is a monitor process (or at least a pid of some former monitor process)
if( p_sys_succ->p_glob->monitor_pid != h2be_pid( 0 ) )
{
// execute a monitor step
if( instr_monitor_step( p_sys_succ->p_glob, last_pid, succ_cb_flags,
instr_monitor_succ, (void *)&prm_sys, // monitor callback with saved settings of system as context
p_succ_ctx, p_succ_cnts ) == IC_STOP )
return IC_STOP; // some callback requested stop
return IC_CONTINUE;
}
// when we get here, there is no monitor process
// count original system successor state and report it to user
p_succ_cnts->total++;
st_instr_succ_output succ_out = // assemble structure with output
{
.p_out_sys1st = p_prm_1st->p_output, // output of system during 1st part of sync. comm.
.p_out_sys = p_sys_succ->p_output, // output of system
.p_out_monitor = NULL // no output of monitor
};
return p_succ_ctx->succ_cb( p_sys_succ->p_glob, // report system state
p_prm_1st->label, p_sys_succ->label, // pass on settings of system
p_prm_1st->flag_reg, p_sys_succ->flag_reg,
succ_cb_flags, // pass on flags of system
&succ_out,
p_succ_ctx->priv_context );
}
// internal successor callback function for 2nd part of synchronous communication
et_ic_status instr_sync_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
t_pid pid, // pid of process that executed
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
unsigned int succ_cb_flags, // flags accumulated so far
st_instr_succ_context *p_succ_ctx, // context for successor state generation
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
void *vp_prm_1st ) // private context: saved settings of 1st part of sync. comm.
{
st_instr_prm_save_sync *p_prm_1st = (st_instr_prm_save_sync *)vp_prm_1st;
// synchronous communication is still going on
if( p_succ->sync_comm )
// this is not a valid state
return IC_CONTINUE;
// execute monitor
return instr_exec_monitor( p_succ, // start from system successor state
p_prm_1st, // with saved setting from 1st part of sync. comm.
pid, // tell monitor process which process did the last step
succ_cb_flags, // pass on flags
p_succ_ctx, p_succ_cnts );
// keep compiler happy
flag_reg = 0;
timeout = 0;
}
// internal successor callback function for system successor states
et_ic_status instr_sys_succ( st_instr_tmp_succ * p_succ, // successor state (with label, flag_reg, ...)
t_pid pid, // pid of process that executed
t_flag_reg flag_reg, // initial value for flag register of process
int timeout, // boolean flag if timeout
unsigned int succ_cb_flags, // flags accumulated so far
st_instr_succ_context *p_succ_ctx, // context for successor state generation
st_instr_succ_cnts *p_succ_cnts, // successor state statistics
void *p_unused ) // private context
{
// no synchronous communication is going on
if( ! p_succ->sync_comm )
{
// create some dummy parameters to pass on
st_instr_prm_save_sync dummy_1st = { .label = 0, .flag_reg = 0, .p_output = NULL };
// execute monitor
return instr_exec_monitor( p_succ, // start from system successor state
&dummy_1st, // with saved setting from 1st part of sync. comm.
pid, // tell monitor process which process did the last step
succ_cb_flags, // pass on flags
p_succ_ctx, p_succ_cnts );
}
// save parameters of 1st part for 2nd part
st_instr_prm_save_sync prm_1st =
{
.label = p_succ->label, // label returned by 1st part
.flag_reg = p_succ->flag_reg, // flag register value returned by 1st part
.p_output = p_succ->p_output, // output done by 1st part
};
// get enabled processes
st_process_header *procs[PID_MAX]; // there cannot be more than PID_MAX processes
unsigned int proc_cnt = global_state_get_enabled_processes( p_succ->p_glob, procs, count( procs ) );
if( proc_cnt == (unsigned int)-1 ) // too many enabled processes
return p_succ_ctx->err_cb( IE_EN_PROC_CNT, 0, 0, p_succ_ctx->priv_context );
// let possible receivers receive message synchronously
unsigned int i;
for( i = 0; i < proc_cnt; i++ ) // execute every enabled process
if( procs[i]->pid != p_succ->p_glob->monitor_pid && // except monitor and sender
procs[i]->pid != h2be_pid( pid ) )
if( instr_proc_steps( p_succ->p_glob, procs[i],
flag_reg, timeout, // start with same flag_reg value and timeout setting as 1st part
0, // executing normal system (not monitor)
succ_cb_flags | INSTR_SUCC_CB_FLAG_SYNC, // add flag for synchronous communication
instr_sync_succ, (void *)&prm_1st, // sync. comm. callback with saved settings of 1st part as context
p_succ_ctx, p_succ_cnts ) == IC_STOP )
return IC_STOP; // some callback requested stop
return IC_CONTINUE;
// keep compiler happy
p_unused = NULL;
}
// *** functions visible from outside ***
// initialize context with default maximum values
// only fills in maximum values and bytecode
// does not touch pointers to callback functions
void instr_succ_context_default( st_instr_succ_context *succ_ctx, st_bytecode *bytecode ) // extern
{
succ_ctx->stack_max = INSTR_DEF_STACK_MAX;
succ_ctx->state_mem = INSTR_DEF_STATE_MEM;
succ_ctx->enab_state_mem = INSTR_DEF_ENAB_STATE_MEM;
succ_ctx->invis_mem = INSTR_DEF_INVIS_MEM;
succ_ctx->path_max = INSTR_DEF_PATH_MAX;
succ_ctx->invis_max = INSTR_DEF_INVIS_MAX;
succ_ctx->succ_max = INSTR_DEF_SUCC_MAX;
succ_ctx->bytecode = bytecode;
}
// generate successor states
// callbacks in context are called for every event (e.g. a successor state)
// returns number of successor states that were reported to successor callback
unsigned int instr_succ( st_global_state_header *p_glob, // state to start with
t_flag_reg flag_reg, // value to put into flag register
st_instr_succ_context *succ_ctx ) // extern
{
// get monitor process in original state
t_pid monitor_pid = be2h_pid( p_glob->monitor_pid );
st_process_header *p_monitor = NULL;
// there is a monitor process (or at least a pid of some former monitor process)
if( monitor_pid != 0 )
{
// get monitor process
p_monitor = global_state_get_process( p_glob, monitor_pid );
// monitor not available or terminated
if( p_monitor == NULL ||
(p_monitor->flags & PROCESS_FLAGS_MODE) == PROCESS_FLAGS_MODE_TERMINATED )
{
// report original state as successor state to user
st_instr_succ_output succ_out = // structure with output: none
{
.p_out_sys1st = NULL, // output of system during 1st part of sync. comm.
.p_out_sys = NULL, // output of system
.p_out_monitor = NULL // output of monitor
};
succ_ctx->succ_cb( p_glob, // report original state
0, 0, 0, 0,
INSTR_SUCC_CB_FLAG_MONITOR_EXIST | INSTR_SUCC_CB_FLAG_MONITOR_TERM,
&succ_out,
succ_ctx->priv_context );
return 1;
}
}
// execute a step in system (and monitor step afterwards)
st_instr_succ_cnts succ_cnts = { .sys = 0, .total = 0 };
instr_sys_step( p_glob, flag_reg,
0, // no successor callback flags yet
instr_sys_succ, NULL, // system successor callback and context
succ_ctx, &succ_cnts );
// done if at least one successor state of system
if( succ_cnts.sys > 0 )
return succ_cnts.total;
// when we get here, the system is blocked
// extension of finite paths only if monitor is present.
if (monitor_pid == 0)
return 0;
// report original state as successor state to user
st_instr_succ_output succ_out = // structure with output: none
{
.p_out_sys1st = NULL, // output of system during 1st part of sync. comm.
.p_out_sys = NULL, // output of system
.p_out_monitor = NULL // output of monitor
};
succ_ctx->succ_cb( p_glob, // report original state
0, 0, 0, 0,
INSTR_SUCC_CB_FLAG_SYS_BLOCK |
(p_monitor != NULL ? INSTR_SUCC_CB_FLAG_MONITOR_EXIST : 0) |
(p_monitor != NULL && (p_monitor->flags & PROCESS_FLAGS_MONITOR_ACCEPT) ? INSTR_SUCC_CB_FLAG_MONITOR_ACCEPT : 0),
&succ_out,
succ_ctx->priv_context );
return 1;
}