CHECK_FUNCTION_EXISTS(vasprintf HAVE_VASPRINTF)
CHECK_FUNCTION_EXISTS(makecontext HAVE_MAKECONTEXT)
CHECK_FUNCTION_EXISTS(mmap HAVE_MMAP)
+CHECK_FUNCTION_EXISTS(process_vm_readv HAVE_PROCESS_VM_READV)
#Check if __thread is defined
execute_process(
)
set(MC_SRC
+ src/mc/mc_address_space.h
+ src/mc/mc_address_space.c
src/mc/mc_forward.h
+ src/mc/mc_process.h
+ src/mc/mc_process.c
+ src/mc/mc_unw.h
+ src/mc/mc_unw.c
+ src/mc/mc_unw_vmread.c
src/mc/mc_mmalloc.h
src/mc/mc_model_checker.h
+ src/mc/mc_model_checker.c
src/mc/mc_object_info.h
+ src/mc/mc_object_info.c
src/mc/mc_checkpoint.c
src/mc/mc_snapshot.h
src/mc/mc_snapshot.c
src/mc/mc_page_store.cpp
src/mc/mc_page_snapshot.cpp
src/mc/mc_comm_pattern.h
+ src/mc/mc_comm_pattern.c
src/mc/mc_comm_determinism.c
src/mc/mc_compare.cpp
src/mc/mc_diff.c
src/mc/mc_visited.c
src/mc/mc_memory_map.h
src/mc/memory_map.c
+ src/mc/mc_client.c
+ src/mc/mc_client_api.c
+ src/mc/mc_client.h
+ src/mc/mc_protocol.h
+ src/mc/mc_protocol.c
+ src/mc/mc_server.cpp
+ src/mc/mc_server.h
+ src/mc/mc_smx.h
+ src/mc/mc_smx.c
)
+set(MC_SIMGRID_MC_SRC
+ src/mc/simgrid_mc.cpp)
+
set(headers_to_install
include/msg/msg.h
include/msg/datatypes.h
${LUA_SRC}
${MC_SRC_BASE}
${MC_SRC}
+ ${MC_SIMGRID_MC_SRC}
${MSG_SRC}
${NS3_SRC}
${RNGSTREAM_SRC}
set(warnCFLAGS "")
set(optCFLAGS "")
+include(CheckCXXCompilerFlag)
+
+if(NOT __VISUALC__ AND NOT __BORLANDC__)
+ CHECK_CXX_COMPILER_FLAG("-std=c++11" HAVE_CXX11)
+ CHECK_CXX_COMPILER_FLAG("-std=c++0x" HAVE_CXX0X)
+ if(HAVE_CXX11)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+ elseif(HAVE_CXX0X)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
+ else()
+ message(STATUS "Missing support for C++11.")
+ endif()
+endif()
+
if(NOT __VISUALC__ AND NOT __BORLANDC__)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}-std=gnu99 -g3")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-g3")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 -g3")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3")
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -g")
else()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}/Zi")
set(optCFLAGS "-O0 ")
# But you can still optimize this:
foreach(s
- # src/xbt/mmalloc/mm.c
- # src/xbt/snprintf.c src/xbt/log.c
- # src/xbt/dynar.c
- # src/xbt/set.c src/xbt/setset.c
- # src/xbt/backtrace_linux.c
- src/mc/mc_dwarf_expression.c src/mc/mc_dwarf.c src/mc/mc_member.c
- src/mc/mc_snapshot.c src/mc/mc_page_store.cpp src/mc/mc_page_snapshot.cpp
- src/mc/mc_compare.cpp src/mc/mc_diff.c
- src/mc/mc_dwarf.c src/mc/mc_dwarf_attrnames.h src/mc/mc_dwarf_expression.c src/mc/mc_dwarf_tagnames.h
- src/mc/mc_set.cpp)
+ src/xbt/mmalloc/mm.c
+ src/xbt/log.c src/xbt/xbt_log_appender_file.c
+ src/xbt/xbt_log_layout_format.c src/xbt/xbt_log_layout_simple.c
+ src/xbt/dict.c src/xbt/dict_elm.c src/xbt/dict_multi.c src/xbt/dict_cursor.c
+ src/xbt/set.c src/xbt/setset.c
+ src/xbt/dynar.c src/xbt/fifo.c src/xbt/heap.c src/xbt/swag.c
+ src/xbt/str.c src/xbt/strbuff.c src/xbt/snprintf.c
+ src/xbt/queue.c
+ src/xbt/xbt_os_time.c src/xbt/xbt_os_thread.c
+ src/xbt/sha.c
+ src/xbt/matrix.c
+ src/xbt/backtrace_linux.c
+ ${MC_SRC_BASE} ${MC_SRC})
set (mcCFLAGS "-O3 -funroll-loops -fno-strict-aliasing")
if(CMAKE_COMPILER_IS_GNUCC)
set (mcCFLAGS "${mcCFLAGS} -finline-functions")
add_dependencies(simgrid maintainer_files)
+if(enable_model-checking)
+ add_executable(simgrid-mc ${MC_SIMGRID_MC_SRC})
+ target_link_libraries(simgrid-mc simgrid)
+ set_target_properties(simgrid-mc
+ PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
+endif()
+
# Compute the dependencies of SimGrid
#####################################
set(SIMGRID_DEP "-lm")
# The availability of libunwind was checked in CompleteInFiles.cmake
# (that includes FindLibunwind.cmake), so simply load it now.
- SET(SIMGRID_DEP "${SIMGRID_DEP} -lunwind")
+ SET(SIMGRID_DEP "${SIMGRID_DEP} -lunwind -lunwind-ptrace")
# Same for libdw
SET(SIMGRID_DEP "${SIMGRID_DEP} -ldw")
message("HAVE_ASPRINTF ...............: ${HAVE_ASPRINTF}")
message("HAVE_VASPRINTF ..............: ${HAVE_VASPRINTF}")
message("HAVE_MMAP ...................: ${HAVE_MMAP}")
+ message("HAVE_PROCESS_VM_READV .......: ${HAVE_PROCESS_VM_READV}")
message("HAVE_THREAD_LOCAL_STORAGE ...: ${HAVE_THREAD_LOCAL_STORAGE}")
message("HAVE_MMALLOC ................: ${HAVE_MMALLOC}")
message("")
/* Define to 1 if mmap is available */
#cmakedefine HAVE_MMAP @HAVE_MMAP@
+/* Define to 1 if process_vm_readv is available */
+#cmakedefine HAVE_PROCESS_VM_READV @HAVE_PROCESS_VM_READV@
+
/* Define to 1 if you have the `getdtablesize' function. */
#cmakedefine HAVE_GETDTABLESIZE @HAVE_GETDTABLESIZE@
/* which is incorrect because the message ordering is non-deterministic */
/******************************************************************************/
-#include <msg/msg.h>
+#include <simgrid/msg.h>
#include <simgrid/modelchecker.h>
#define N 3
! expect signal SIGABRT
! timeout 20
-$ ${bindir:=.}/bugged1 --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/stack_size:256
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged1 --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --log=xbt_cfg.thresh:warning --cfg=contexts/stack_size:256
> [ 0.000000] (0:@) Check a safety property
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@HostB) Sent!
> [ 0.000000] (3:client@HostC) Sent!
> [ 0.000000] (1:server@HostA) OK
> [ 0.000000] (2:client@HostB) Sent!
> [ 0.000000] (3:client@HostC) Sent!
> [ 0.000000] (2:client@HostB) Sent!
-> [ 0.000000] (1:server@HostA) **************************
-> [ 0.000000] (1:server@HostA) *** PROPERTY NOT VALID ***
-> [ 0.000000] (1:server@HostA) **************************
-> [ 0.000000] (1:server@HostA) Counter-example execution trace:
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(2)HostB (client)] iSend(src=(2)HostB (client), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] Wait(comm=(verbose only) [(2)HostB (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(2)HostB (client)] Wait(comm=(verbose only) [(2)HostB (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) [(4)HostD (client)] iSend(src=(4)HostD (client), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] Wait(comm=(verbose only) [(4)HostD (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) Expanded states = 22
-> [ 0.000000] (1:server@HostA) Visited states = 56
-> [ 0.000000] (1:server@HostA) Executed transitions = 52
-
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) *** PROPERTY NOT VALID ***
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) Counter-example execution trace:
+> [ 0.000000] (0:@) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(2)HostB (client)] iSend(src=(2)HostB (client), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(1)HostA (server)] Wait(comm=(verbose only) [(2)HostB (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(2)HostB (client)] Wait(comm=(verbose only) [(2)HostB (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) [(4)HostD (client)] iSend(src=(4)HostD (client), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(1)HostA (server)] Wait(comm=(verbose only) [(4)HostD (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) Expanded states = 22
+> [ 0.000000] (0:@) Visited states = 56
+> [ 0.000000] (0:@) Executed transitions = 52
int r=0;
int cs=0;
-int predR(){
- return r;
-}
-
-int predCS(){
- return cs;
-}
-
#ifdef GARBAGE_STACK
/** Do not use a clean stack */
static void garbage_stack(void) {
int coordinator(int argc, char *argv[])
{
-
int CS_used = 0;
msg_task_t task = NULL, answer = NULL;
xbt_dynar_t requests = xbt_dynar_new(sizeof(char *), NULL);
int main(int argc, char *argv[])
{
-
MSG_init(&argc, argv);
-
char **options = &argv[1];
- MSG_config("model-check/property","promela_bugged1_liveness");
- MC_automaton_new_propositional_symbol("r", &predR);
- MC_automaton_new_propositional_symbol("cs", &predCS);
+ MC_automaton_new_propositional_symbol_pointer("r", &r);
+ MC_automaton_new_propositional_symbol_pointer("cs", &cs);
const char* platform_file = options[0];
const char* application_file = options[1];
-
+
MSG_create_environment(platform_file);
+
MSG_function_register("coordinator", coordinator);
MSG_function_register("client", raw_client);
MSG_launch_application(application_file);
+
MSG_main();
return 0;
! expect signal SIGABRT
! timeout 20
-$ ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness.xml --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack_size:256
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness.xml --log=xbt_cfg.thresh:warning --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack_size:256 --cfg=model-check/property:promela_bugged1_liveness
> [ 0.000000] (0:@) Check the liveness property promela_bugged1_liveness
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@Boivin) Ask the request
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (2:client@Boivin) Propositions changed : r=1, cs=0
> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediatly
-> [ 0.000000] (0:@) Pair 22 already reached (equal to pair 10) !
+> [ 0.000000] (0:@) Pair 23 already reached (equal to pair 11) !
> [ 0.000000] (0:@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> [ 0.000000] (0:@) | ACCEPTANCE CYCLE |
> [ 0.000000] (0:@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> [ 0.000000] (0:@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
> [ 0.000000] (0:@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
> [ 0.000000] (0:@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [ 0.000000] (0:@) Expanded pairs = 22
-> [ 0.000000] (0:@) Visited pairs = 20
-> [ 0.000000] (0:@) Executed transitions = 20
-> [ 0.000000] (0:@) Counter-example depth : 21
-
+> [ 0.000000] (0:@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) Expanded pairs = 23
+> [ 0.000000] (0:@) Visited pairs = 21
+> [ 0.000000] (0:@) Executed transitions = 21
+> [ 0.000000] (0:@) Counter-example depth : 22
! expect signal SIGABRT
! timeout 60
-$ ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness.xml --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack_size:256 --cfg=model-check/sparse-checkpoint:yes
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/sparse-checkpoint' to 'yes'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness.xml --log=xbt_cfg.thresh:warning --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=contexts/stack_size:256 --cfg=model-check/sparse-checkpoint:yes --cfg=model-check/property:promela_bugged1_liveness
> [ 0.000000] (0:@) Check the liveness property promela_bugged1_liveness
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@Boivin) Ask the request
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (2:client@Boivin) Propositions changed : r=1, cs=0
> [ 0.000000] (1:coordinator@Tremblay) CS release. resource now idle
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediatly
-> [ 0.000000] (0:@) Pair 22 already reached (equal to pair 10) !
+> [ 0.000000] (0:@) Pair 23 already reached (equal to pair 11) !
> [ 0.000000] (0:@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> [ 0.000000] (0:@) | ACCEPTANCE CYCLE |
> [ 0.000000] (0:@) *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
> [ 0.000000] (0:@) [(3)Fafard (client)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
> [ 0.000000] (0:@) [(3)Fafard (client)] iSend(src=(3)Fafard (client), buff=(verbose only), size=(verbose only))
> [ 0.000000] (0:@) [(1)Tremblay (coordinator)] Wait(comm=(verbose only) [(3)Fafard (client)-> (1)Tremblay (coordinator)])
-> [ 0.000000] (0:@) Expanded pairs = 22
-> [ 0.000000] (0:@) Visited pairs = 20
-> [ 0.000000] (0:@) Executed transitions = 20
-> [ 0.000000] (0:@) Counter-example depth : 21
+> [ 0.000000] (0:@) [(1)Tremblay (coordinator)] iSend(src=(1)Tremblay (coordinator), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) Expanded pairs = 23
+> [ 0.000000] (0:@) Visited pairs = 21
+> [ 0.000000] (0:@) Executed transitions = 21
+> [ 0.000000] (0:@) Counter-example depth : 22
! expect signal SIGABRT
! timeout 90
-$ ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness_visited.xml --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack_size:256
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/visited' to '100'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness_visited.xml --log=xbt_cfg.thresh:warning --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack_size:256 --cfg=model-check/property:promela_bugged1_liveness
> [ 0.000000] (0:@) Check the liveness property promela_bugged1_liveness
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@Boivin) Ask the request
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediatly
> [ 0.000000] (0:@) Visited pairs = 201
> [ 0.000000] (0:@) Executed transitions = 207
> [ 0.000000] (0:@) Counter-example depth : 51
-
! expect signal SIGABRT
! timeout 90
-$ ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness_visited.xml --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack_size:256 --cfg=model-check/sparse-checkpoint:yes
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/visited' to '100'
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/sparse-checkpoint' to 'yes'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged1_liveness ${srcdir:=.}/../../platforms/platform.xml ${srcdir:=.}/deploy_bugged1_liveness_visited.xml --log=xbt_cfg.thresh:warning --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/factory:ucontext --cfg=model-check/visited:100 --cfg=contexts/stack_size:256 --cfg=model-check/sparse-checkpoint:yes --cfg=model-check/property:promela_bugged1_liveness
> [ 0.000000] (0:@) Check the liveness property promela_bugged1_liveness
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@Boivin) Ask the request
> [ 0.000000] (3:client@Fafard) Ask the request
> [ 0.000000] (1:coordinator@Tremblay) CS idle. Grant immediatly
/* which is incorrect because the message ordering is non-deterministic */
/******************************************************************************/
-#include <msg/msg.h>
+#include <simgrid/msg.h>
#include <simgrid/modelchecker.h>
#define N 3
! expect signal SIGABRT
! timeout 20
-$ ${bindir:=.}/bugged2 --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=contexts/stack_size:256
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/bugged2 --cfg=model-check:1 "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --log=xbt_cfg.thresh:warning --cfg=contexts/stack_size:256
> [ 0.000000] (0:@) Check a safety property
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
> [ 0.000000] (2:client@HostB) Send 1!
> [ 0.000000] (3:client@HostC) Send 2!
> [ 0.000000] (1:server@HostA) Received 1
> [ 0.000000] (1:server@HostA) Received 2
> [ 0.000000] (3:client@HostC) Send 2!
> [ 0.000000] (1:server@HostA) Received 2
-> [ 0.000000] (1:server@HostA) **************************
-> [ 0.000000] (1:server@HostA) *** PROPERTY NOT VALID ***
-> [ 0.000000] (1:server@HostA) **************************
-> [ 0.000000] (1:server@HostA) Counter-example execution trace:
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) [(3)HostC (client)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
-> [ 0.000000] (1:server@HostA) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
-> [ 0.000000] (1:server@HostA) Expanded states = 461
-> [ 0.000000] (1:server@HostA) Visited states = 2271
-> [ 0.000000] (1:server@HostA) Executed transitions = 2117
-
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) *** PROPERTY NOT VALID ***
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) Counter-example execution trace:
+> [ 0.000000] (0:@) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) [(3)HostC (client)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) [(1)HostA (server)] iRecv(dst=(1)HostA (server), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(3)HostC (client)] iSend(src=(3)HostC (client), buff=(verbose only), size=(verbose only))
+> [ 0.000000] (0:@) [(1)HostA (server)] Wait(comm=(verbose only) [(3)HostC (client)-> (1)HostA (server)])
+> [ 0.000000] (0:@) Expanded states = 461
+> [ 0.000000] (0:@) Visited states = 2271
+> [ 0.000000] (0:@) Executed transitions = 2117
int cs = 0;
-int predCS(){
- return cs;
-}
-
-
int coordinator(int argc, char **argv);
int client(int argc, char **argv);
MSG_init(&argc, argv);
- MSG_config("model-check/property","promela_bugged2_liveness");
- MC_automaton_new_propositional_symbol("cs", &predCS);
+ MC_automaton_new_propositional_symbol_pointer("cs", &cs);
MSG_create_environment("../msg_platform.xml");
MSG_function_register("coordinator", coordinator);
/* same buffer for reception (task1). */
/******************************************************************************/
-#include <msg/msg.h>
+#include <simgrid/msg.h>
#include <simgrid/modelchecker.h>
XBT_LOG_NEW_DEFAULT_CATEGORY(bugged3, "this example");
/* --cfg=model-check/max_depth:) is reached. */
/******************************************************************************/
-#include <msg/msg.h>
+#include <simgrid/msg.h>
#include <simgrid/modelchecker.h>
#define N 2
int r, cs;
-static int predR(){
- return r;
-}
-
-static int predCS(){
- return cs;
-}
-
-
int main(int argc, char **argv){
int err, size, rank;
exit(1);
}
- MC_automaton_new_propositional_symbol("r", &predR);
- MC_automaton_new_propositional_symbol("cs", &predCS);
+ MC_automaton_new_propositional_symbol_pointer("r", &r);
+ MC_automaton_new_propositional_symbol_pointer("cs", &cs);
MC_ignore(&(status.count), sizeof(status.count));
--- /dev/null
+#! ./tesh
+
+! timeout 60
+$ ../../../smpi_script/bin/smpirun -wrapper ${bindir:=.}/../../../bin/simgrid-mc -hostfile ${srcdir:=.}/hostfile_non_deterministic -platform ${srcdir:=.}/../../platforms/cluster.xml --log=xbt_cfg.thresh:warning --cfg=model-check:1 --cfg=model-check/communications_determinism:1 --cfg=smpi/send_is_detached_thres:0 --cfg=smpi/running_power:1e9 ./smpi_non_deterministic
+> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
+> [0.000000] [mc_global/INFO] Check communication determinism
+> [0.000000] [mc_comm_determinism/INFO] The communications pattern of the process 1 is different! (Different communication : 1)
+> [0.000000] [mc_comm_determinism/INFO] ****************************************************
+> [0.000000] [mc_comm_determinism/INFO] ***** Non-deterministic communications pattern *****
+> [0.000000] [mc_comm_determinism/INFO] ****************************************************
+> [0.000000] [mc_comm_determinism/INFO] ** Initial communications pattern (per process): **
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 1:
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org <- (2) node-2.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org -> (2) node-2.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org <- (3) node-3.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org -> (3) node-3.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 2:
+> [0.000000] [mc_comm_determinism/INFO] [(2) node-2.acme.org -> (1) node-1.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(2) node-2.acme.org <- (1) node-1.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 3:
+> [0.000000] [mc_comm_determinism/INFO] [(3) node-3.acme.org -> (1) node-1.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(3) node-3.acme.org <- (1) node-1.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] ** Communications pattern counter-example (per process): **
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 1:
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org <- (3) node-3.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org -> (3) node-3.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org <- (2) node-2.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] [(1) node-1.acme.org -> (2) node-2.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 2:
+> [0.000000] [mc_comm_determinism/INFO] [(2) node-2.acme.org -> (1) node-1.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(2) node-2.acme.org <- (1) node-1.acme.org] iRecv
+> [0.000000] [mc_comm_determinism/INFO] Communications from the process 3:
+> [0.000000] [mc_comm_determinism/INFO] [(3) node-3.acme.org -> (1) node-1.acme.org] iSend
+> [0.000000] [mc_comm_determinism/INFO] [(3) node-3.acme.org <- (1) node-1.acme.org] iRecv
+> [0.000000] [mc_global/INFO] Expanded states = 16037
+> [0.000000] [mc_global/INFO] Visited states = 80801
+> [0.000000] [mc_global/INFO] Executed transitions = 76048
+> [0.000000] [mc_global/INFO] Communication-deterministic : No
#! ./tesh
! timeout 60
-$ ../../../smpi_script/bin/smpirun -hostfile ${srcdir:=.}/hostfile_only_send_deterministic -platform ${srcdir:=.}/../../platforms/cluster.xml --cfg=model-check:1 --cfg=model-check/communications_determinism:1 --cfg=smpi/send_is_detached_thres:0 --cfg=smpi/running_power:1e9 ./smpi_only_send_deterministic
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check/communications_determinism' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/send_is_detached_thres' to '0'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
+$ ../../../smpi_script/bin/smpirun -wrapper "${bindir:=.}/../../../bin/simgrid-mc" --log=xbt_cfg.thresh:warning -hostfile ${srcdir:=.}/hostfile_only_send_deterministic -platform ${srcdir:=.}/../../platforms/cluster.xml --cfg=model-check:1 --cfg=model-check/communications_determinism:1 --cfg=smpi/send_is_detached_thres:0 --cfg=smpi/running_power:1e9 ./smpi_only_send_deterministic
> [0.000000] [mc_global/INFO] Check communication determinism
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
+> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] ******************************************************
> [0.000000] [mc_global/INFO] **** Only-send-deterministic communication pattern ****
> [0.000000] [mc_global/INFO] ******************************************************
> [0.000000] [mc_global/INFO] Executed transitions = 3360
> [0.000000] [mc_global/INFO] Send-deterministic : Yes
> [0.000000] [mc_global/INFO] Recv-deterministic : No
-
-
SG_BEGIN_DECL()
+/** Replay path (if any) in string representation
+ *
+ * This is a path as generated by `MC_record_stack_to_string()`.
+ */
+XBT_PUBLIC_DATA(char*) MC_record_path;
+
+/** Whether the replay mode is enabled */
+static inline bool MC_record_replay_is_active(void) {
+ return MC_record_path;
+}
+
XBT_PUBLIC(int) MC_random(int min, int max);
#ifdef HAVE_MC
#define MC_visited_reduction() _sg_mc_visited
XBT_PUBLIC(void) MC_assert(int);
-XBT_PUBLIC(void) MC_automaton_new_propositional_symbol(const char* id, void* fct);
+XBT_PUBLIC(void) MC_automaton_new_propositional_symbol(const char* id, int(*fct)(void));
+XBT_PUBLIC(void) MC_automaton_new_propositional_symbol_pointer(const char *id, int* value);
+XBT_PUBLIC(void) MC_automaton_new_propositional_symbol_callback(const char* id,
+ xbt_automaton_propositional_symbol_callback_type callback,
+ void* data, xbt_automaton_propositional_symbol_free_function_type free_function);
XBT_PUBLIC(void *) MC_snapshot(void);
XBT_PUBLIC(int) MC_compare_snapshots(void *s1, void *s2);
XBT_PUBLIC(void) MC_cut(void);
#define MC_assert(a) xbt_assert(a)
#define MC_automaton_new_propositional_symbol(a, b) ((void)0)
+#define MC_automaton_new_propositional_symbol_pointer(a, b) ((void)0)
+#define MC_automaton_new_propositional_symbol_callback(id,callback,data,free_function) \
+ if(free_function) free_function(data);
#define MC_snapshot() ((void*)0)
#define MC_compare_snapshots(a, b) 0
#define MC_cut() ((void)0)
#endif
-/** Replay path (if any) in string representation
- *
- * This is a path as generated by `MC_record_stack_to_string()`.
- */
-XBT_PUBLIC_DATA(char*) MC_record_path;
-
-/** Whether the replay mode is enabled */
-static inline bool MC_record_replay_is_active(void) {
- return MC_record_path;
-}
-
SG_END_DECL()
#endif /* SIMGRID_MODELCHECKER_H */
typedef struct xbt_automaton_transition* xbt_automaton_transition_t;
-typedef struct xbt_automaton_propositional_symbol{
- char* pred;
- void* function;
-} s_xbt_automaton_propositional_symbol;
-
+typedef struct xbt_automaton_propositional_symbol s_xbt_automaton_propositional_symbol;
typedef struct xbt_automaton_propositional_symbol* xbt_automaton_propositional_symbol_t;
+typedef int (*xbt_automaton_propositional_symbol_callback_type)(void*);
+typedef void (*xbt_automaton_propositional_symbol_free_function_type)(void*);
XBT_PUBLIC(xbt_automaton_t) xbt_automaton_new(void);
XBT_PUBLIC(void) xbt_automaton_exp_label_display(xbt_automaton_exp_label_t l);
-XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new(xbt_automaton_t a, const char* id, void* fct);
+// xbt_automaton_propositional_symbol constructors:
+XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new(xbt_automaton_t a, const char* id, int(*fct)(void));
+XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new_pointer(xbt_automaton_t a, const char* id, int* value);
+XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new_callback(
+ xbt_automaton_t a, const char* id,
+ xbt_automaton_propositional_symbol_callback_type callback,
+ void* data, xbt_automaton_propositional_symbol_free_function_type free_function);
+
+// xbt_automaton_propositional_symbol accessors:
+XBT_PUBLIC(xbt_automaton_propositional_symbol_callback_type) xbt_automaton_propositional_symbol_get_callback(xbt_automaton_propositional_symbol_t symbol);
+XBT_PUBLIC(void*) xbt_automaton_propositional_symbol_get_data(xbt_automaton_propositional_symbol_t symbol);
+XBT_PUBLIC(const char*) xbt_automaton_propositional_symbol_get_name(xbt_automaton_propositional_symbol_t symbol);
+
+// xbt_automaton_propositional_symbol methods!
+XBT_PUBLIC(int) xbt_automaton_propositional_symbol_evaluate(xbt_automaton_propositional_symbol_t symbol);
XBT_PUBLIC(xbt_automaton_state_t) xbt_automaton_get_current_state(xbt_automaton_t a);
_xbt_dynar_cursor_get(_dynar,_cursor,&_data) ; \
(_cursor)++ )
+#define xbt_dynar_foreach_ptr(_dynar,_cursor,_ptr) \
+ for (_xbt_dynar_cursor_first(_dynar,&(_cursor)) ; \
+ (_ptr = _cursor < _dynar->used ? xbt_dynar_get_ptr(_dynar,_cursor) : NULL) ; \
+ (_cursor)++ )
+
/** @} */
SG_END_DECL()
{ \
xbt_running_ctx_t *__xbt_ex_ctx_ptr = __xbt_running_ctx_fetch(); \
int __ex_cleanup = 0; \
- __ex_mctx_t *__ex_mctx_en; \
__ex_mctx_t __ex_mctx_me; \
- __ex_mctx_en = __xbt_ex_ctx_ptr->ctx_mctx; \
+ __ex_mctx_t * __ex_mctx_en = __xbt_ex_ctx_ptr->ctx_mctx; \
__xbt_ex_ctx_ptr->ctx_mctx = &__ex_mctx_me; \
if (__ex_mctx_save(&__ex_mctx_me)) { \
if (1)
*
* The heap structure itself is an opaque object that shouldnt be messed with.
*/
+typedef struct mdesc s_xbt_mheap_t;
typedef struct mdesc *xbt_mheap_t;
/* Allocate SIZE bytes of memory (and memset it to 0). */
XBT_PUBLIC( xbt_mheap_t ) mmalloc_get_default_md(void);
/* To change the heap used when using the legacy version malloc/free/realloc and such */
-void mmalloc_set_current_heap(xbt_mheap_t new_heap);
+xbt_mheap_t mmalloc_set_current_heap(xbt_mheap_t new_heap);
xbt_mheap_t mmalloc_get_current_heap(void);
struct s_mc_snapshot;
int mmalloc_compare_heap(struct s_mc_snapshot* snapshot1, struct s_mc_snapshot* snapshot2);
int mmalloc_linear_compare_heap(xbt_mheap_t heap1, xbt_mheap_t heap2);
int init_heap_information(xbt_mheap_t heap1, xbt_mheap_t heap2, xbt_dynar_t to_ignore1, xbt_dynar_t to_ignore2);
-int compare_heap_area(int process_index, void *area1, void* area2, struct s_mc_snapshot* snapshot1, struct s_mc_snapshot* snapshot2, xbt_dynar_t previous, struct s_dw_type *type, int pointer_level);
+int compare_heap_area(int process_index, const void *area1, const void* area2, struct s_mc_snapshot* snapshot1, struct s_mc_snapshot* snapshot2, xbt_dynar_t previous, struct s_dw_type *type, int pointer_level);
void reset_heap_information(void);
size_t mmalloc_get_bytes_used(xbt_mheap_t);
ssize_t mmalloc_get_busy_size(xbt_mheap_t, void *ptr);
+void* malloc_no_memset(size_t n);
+
SG_END_DECL()
#endif
#ifndef MC_DATATYPE_H
#define MC_DATATYPE_H
-#define UNW_LOCAL_ONLY
-
#include "xbt/misc.h"
#include "xbt/swag.h"
#include "xbt/fifo.h"
typedef struct s_stack_region{
void *address;
- char *process_name;
void *context;
size_t size;
int block;
extern int _sg_mc_send_determinism;
extern int _sg_mc_safety;
extern int _sg_mc_liveness;
+extern int _sg_mc_snapshot_fds;
extern int _sg_mc_termination;
extern xbt_dynar_t mc_heap_comparison_ignore;
extern xbt_dynar_t stacks_areas;
-extern void *maestro_stack_start;
-extern void *maestro_stack_end;
/********************************* Global *************************************/
void _mc_cfg_cb_reduce(const char *name, int pos);
void _mc_cfg_cb_property(const char *name, int pos);
void _mc_cfg_cb_timeout(const char *name, int pos);
void _mc_cfg_cb_hash(const char *name, int pos);
+void _mc_cfg_cb_snapshot_fds(const char *name, int pos);
void _mc_cfg_cb_max_depth(const char *name, int pos);
void _mc_cfg_cb_visited(const char *name, int pos);
void _mc_cfg_cb_dot_output(const char *name, int pos);
/********************************* Memory *************************************/
XBT_PUBLIC(void) MC_memory_init(void); /* Initialize the memory subsystem */
XBT_PUBLIC(void) MC_memory_exit(void);
+XBT_PUBLIC(void) MC_memory_init_server(void);
SG_END_DECL()
--- /dev/null
+/* Copyright (c) 2008-2014. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "mc_address_space.h"
--- /dev/null
+/* Copyright (c) 2008-2014. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_ADDRESS_SPACE_H
+#define MC_ADDRESS_SPACE_H
+
+#include <stdint.h>
+
+#include "mc_forward.h"
+
+// ***** Data types
+
+typedef enum e_adress_space_read_flags {
+ MC_ADDRESS_SPACE_READ_FLAGS_NONE = 0,
+
+ /** Avoid a copy for when the data is available in the current process.
+ *
+ * In this case, the return value of a MC_address_space_read might
+ * be different from the provided buffer.
+ */
+ MC_ADDRESS_SPACE_READ_FLAGS_LAZY = 1
+} e_adress_space_read_flags_t;
+
+/** Process index used when no process is available
+ *
+ * The expected behaviour is that if a process index is needed it will fail.
+ * */
+#define MC_PROCESS_INDEX_MISSING -1
+
+#define MC_PROCESS_INDEX_DISABLED -2
+
+/** Process index when any process is suitable
+ *
+ * We could use a special negative value in the future.
+ */
+#define MC_PROCESS_INDEX_ANY 0
+
+// ***** Class definition
+
+typedef struct s_mc_address_space s_mc_address_space_t, *mc_address_space_t;
+typedef struct s_mc_address_space_class s_mc_address_space_class_t, *mc_address_space_class_t;
+
+/** Abstract base class for an address space
+ *
+ * This is the base class for all virtual address spaces (process, snapshot).
+ * It uses dynamic dispatch based on a vtable (`address_space_class`).
+ */
+struct s_mc_address_space {
+ const s_mc_address_space_class_t* address_space_class;
+};
+
+/** Class object (vtable) for the virtual address spaces
+ */
+struct s_mc_address_space_class {
+ const void* (*read)(
+ mc_address_space_t address_space, e_adress_space_read_flags_t flags,
+ void* target, const void* addr, size_t size,
+ int process_index);
+ mc_process_t (*get_process)(mc_address_space_t address_space);
+};
+
+// ***** Virtual/non-final methods
+
+/** Read data from the given address space
+ *
+ * Dynamic dispatch.
+ */
+static inline __attribute__((always_inline))
+const void* MC_address_space_read(
+ mc_address_space_t address_space, e_adress_space_read_flags_t flags,
+ void* target, const void* addr, size_t size,
+ int process_index)
+{
+ return address_space->address_space_class->read(
+ address_space, flags, target, addr, size,
+ process_index);
+}
+
+static inline __attribute__((always_inline))
+const void* MC_address_space_get_process(mc_address_space_t address_space)
+{
+ return address_space->address_space_class->get_process(address_space);
+}
+
+
+#endif
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <assert.h>
+
#include <simgrid/simix.h>
#include "mc_base.h"
#include "../simix/smx_private.h"
#include "mc_record.h"
+#ifdef HAVE_MC
+#include "mc_process.h"
+#include "mc_model_checker.h"
+#include "mc_protocol.h"
+#include "mc_smx.h"
+#include "mc_server.h"
+#endif
+
XBT_LOG_NEW_CATEGORY(mc, "All MC categories");
-/**
- * \brief Schedules all the process that are ready to run
- */
void MC_wait_for_requests(void)
{
+#ifdef HAVE_MC
+ if (mc_mode == MC_MODE_SERVER) {
+ MC_server_wait_client(&mc_model_checker->process);
+ return;
+ }
+#endif
+
smx_process_t process;
smx_simcall_t req;
unsigned int iter;
{
unsigned int index = 0;
smx_synchro_t act = 0;
- smx_mutex_t mutex = NULL;
+#ifdef HAVE_MC
+ s_smx_synchro_t temp_synchro;
+#endif
switch (req->call) {
case SIMCALL_NONE:
case SIMCALL_COMM_WAIT:
/* FIXME: check also that src and dst processes are not suspended */
act = simcall_comm_wait__get__comm(req);
+
+#ifdef HAVE_MC
+ // Fetch from MCed memory:
+ if (!MC_process_is_self(&mc_model_checker->process)) {
+ MC_process_read(&mc_model_checker->process, MC_PROCESS_NO_FLAG,
+ &temp_synchro, act, sizeof(temp_synchro),
+ MC_PROCESS_INDEX_ANY);
+ act = &temp_synchro;
+ }
+#endif
+
if (simcall_comm_wait__get__timeout(req) >= 0) {
/* If it has a timeout it will be always be enabled, because even if the
* communication is not ready, it can timeout and won't block. */
}
return (act->comm.src_proc && act->comm.dst_proc);
- case SIMCALL_COMM_WAITANY:
- /* Check if it has at least one communication ready */
- xbt_dynar_foreach(simcall_comm_waitany__get__comms(req), index, act)
+ case SIMCALL_COMM_WAITANY: {
+#ifdef HAVE_MC
+ // Read dynar:
+ s_xbt_dynar_t comms;
+ MC_process_read_simple(&mc_model_checker->process,
+ &comms, simcall_comm_waitany__get__comms(req), sizeof(comms));
+ // Read dynar buffer:
+ assert(comms.elmsize == sizeof(act));
+ size_t buffer_size = comms.elmsize * comms.used;
+ char buffer[buffer_size];
+ MC_process_read_simple(&mc_model_checker->process,
+ buffer, comms.data, sizeof(buffer));
+#endif
+
+#ifdef HAVE_MC
+ for (index = 0; index < comms.used; ++index) {
+ memcpy(&act, buffer + comms.elmsize * index, sizeof(act));
+#else
+ xbt_dynar_foreach(simcall_comm_waitany__get__comms(req), index, act) {
+#endif
+
+#ifdef HAVE_MC
+ // Fetch from MCed memory:
+ if (!MC_process_is_self(&mc_model_checker->process)) {
+ MC_process_read(&mc_model_checker->process, MC_PROCESS_NO_FLAG,
+ &temp_synchro, act, sizeof(temp_synchro),
+ MC_PROCESS_INDEX_ANY);
+ act = &temp_synchro;
+ }
+#endif
+
if (act->comm.src_proc && act->comm.dst_proc)
return TRUE;
+ }
return FALSE;
+ }
- case SIMCALL_MUTEX_LOCK:
- mutex = simcall_mutex_lock__get__mutex(req);
+ case SIMCALL_MUTEX_LOCK: {
+ smx_mutex_t mutex = simcall_mutex_lock__get__mutex(req);
+#ifdef HAVE_MC
+ s_smx_mutex_t temp_mutex;
+ if (!MC_process_is_self(&mc_model_checker->process)) {
+ MC_process_read(&mc_model_checker->process, MC_PROCESS_NO_FLAG,
+ &temp_mutex, mutex, sizeof(temp_mutex),
+ MC_PROCESS_INDEX_ANY);
+ mutex = &temp_mutex;
+ }
+#endif
if(mutex->owner == NULL)
return TRUE;
else
- return (mutex->owner->pid == req->issuer->pid);
+#ifdef HAVE_MC
+ // TODO, *(mutex->owner) :/
+ return MC_smx_resolve_process(mutex->owner)->pid ==
+ MC_smx_resolve_process(req->issuer)->pid;
+#else
+ return mutex->owner->pid == req->issuer->pid;
+#endif
+ }
default:
/* The rest of the requests are always enabled */
SG_BEGIN_DECL()
+/** Check if the given simcall can be resolved
+ *
+ * \return `TRUE` or `FALSE`
+ */
int MC_request_is_enabled(smx_simcall_t req);
+
+/** Check if the given simcall is visible
+ *
+ * \return `TRUE` or `FALSE`
+ */
int MC_request_is_visible(smx_simcall_t req);
+
+/** Execute everything which is invisible
+ *
+ * Execute all the processes that are ready to run and all invisible simcalls
+ * iteratively until there doesn't remain any. At this point, the function
+ * returns to the caller which can handle the visible (and ready) simcalls.
+ */
void MC_wait_for_requests(void);
extern double *mc_time;
* under the terms of the license (GNU LGPL) which comes with this package. */
#define _GNU_SOURCE
-#define UNW_LOCAL_ONLY
#include <unistd.h>
#include "../simix/smx_private.h"
-#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <libelf.h>
#include "mc_snapshot.h"
#include "mc_object_info.h"
#include "mc_mmu.h"
+#include "mc_unw.h"
+#include "mc_protocol.h"
+#include "mc_smx.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_checkpoint, mc,
"Logging specific to mc_checkpoint");
-char *libsimgrid_path;
-
/************************************ Free functions **************************************/
/*****************************************************************************************/
if (s) {
xbt_dynar_free(&(s->local_variables));
xbt_dynar_free(&(s->stack_frames));
+ mc_unw_destroy_context(s->context);
+ xbt_free(s->context);
xbt_free(s);
}
}
static void MC_snapshot_stack_free_voidp(void *s)
{
- MC_snapshot_stack_free((mc_snapshot_stack_t) * (void **) s);
+ mc_snapshot_stack_t stack = (mc_snapshot_stack_t) * (void **) s;
+ MC_snapshot_stack_free(stack);
}
static void local_variable_free(local_variable_t v)
local_variable_free((local_variable_t) * (void **) v);
}
-void MC_region_destroy(mc_mem_region_t reg)
+void MC_region_destroy(mc_mem_region_t region)
{
- if (!reg)
+ if (!region)
return;
-
- //munmap(reg->data, reg->size);
- xbt_free(reg->data);
- if (reg->page_numbers) {
- mc_free_page_snapshot_region(reg->page_numbers, mc_page_count(reg->size));
+ switch(region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ break;
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ xbt_free(region->flat.data);
+ break;
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ mc_free_page_snapshot_region(region->chunked.page_numbers, mc_page_count(region->size));
+ xbt_free(region->chunked.page_numbers);
+ break;
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ size_t regions_count = region->privatized.regions_count;
+ for (size_t i=0; i!=regions_count; ++i) {
+ MC_region_destroy(region->privatized.regions[i]);
+ }
+ free(region->privatized.regions);
+ break;
+ }
}
- xbt_free(reg);
+ xbt_free(region);
}
void MC_free_snapshot(mc_snapshot_t snapshot)
{
- unsigned int i;
- for (i = 0; i < NB_REGIONS; i++) {
- MC_region_destroy(snapshot->regions[i]);
+ for (size_t i = 0; i < snapshot->snapshot_regions_count; i++) {
+ MC_region_destroy(snapshot->snapshot_regions[i]);
}
-
+ xbt_free(snapshot->snapshot_regions);
xbt_free(snapshot->stack_sizes);
xbt_dynar_free(&(snapshot->stacks));
xbt_dynar_free(&(snapshot->to_ignore));
xbt_dynar_free(&snapshot->ignored_data);
-
- if (snapshot->privatization_regions) {
- size_t n = xbt_dynar_length(snapshot->enabled_processes);
- for (i = 0; i != n; ++i) {
- MC_region_destroy(snapshot->privatization_regions[i]);
- }
- xbt_free(snapshot->privatization_regions);
- }
-
xbt_free(snapshot);
}
/******************************* Snapshot regions ********************************/
/*********************************************************************************/
-static mc_mem_region_t mc_region_new_dense(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+static mc_mem_region_t mc_region_new_dense(
+ mc_region_type_t region_type,
+ void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
{
- mc_mem_region_t new_reg = xbt_new(s_mc_mem_region_t, 1);
- new_reg->start_addr = start_addr;
- new_reg->permanent_addr = permanent_addr;
- new_reg->data = NULL;
- new_reg->size = size;
- new_reg->page_numbers = NULL;
- new_reg->data = xbt_malloc(size);
- memcpy(new_reg->data, permanent_addr, size);
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_FLAT;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
+ region->flat.data = xbt_malloc(size);
+ MC_process_read(&mc_model_checker->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ region->flat.data, permanent_addr, size,
+ MC_PROCESS_INDEX_DISABLED);
XBT_DEBUG("New region : type : %d, data : %p (real addr %p), size : %zu",
- type, new_reg->data, permanent_addr, size);
- return new_reg;
-
+ region_type, region->flat.data, permanent_addr, size);
+ return region;
}
/** @brief Take a snapshot of a given region
* @param size Size of the data*
* @param ref_reg Reference corresponding region
*/
-static mc_mem_region_t MC_region_new(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+static mc_mem_region_t MC_region_new(mc_region_type_t type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
{
if (_sg_mc_sparse_checkpoint) {
return mc_region_new_sparse(type, start_addr, permanent_addr, size, ref_reg);
* @param reg Target region
* @param reg_reg Current region (if not NULL), used for lazy per page restoration
*/
-static void MC_region_restore(mc_mem_region_t reg, mc_mem_region_t ref_reg)
+static void MC_region_restore(mc_mem_region_t region, mc_mem_region_t ref_region)
{
- /*FIXME: check if start_addr is still mapped, if it is not, then map it
- before copying the data */
- if (!reg->page_numbers) {
- memcpy(reg->permanent_addr, reg->data, reg->size);
- } else {
- mc_region_restore_sparse(reg, ref_reg);
+ switch(region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+ break;
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ MC_process_write(&mc_model_checker->process, region->flat.data,
+ region->permanent_addr, region->size);
+ break;
+
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ mc_region_restore_sparse(&mc_model_checker->process, region, ref_region);
+ break;
+
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ bool has_ref_regions = ref_region &&
+ ref_region->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED;
+ size_t process_count = region->privatized.regions_count;
+ for (size_t i = 0; i < process_count; i++) {
+ MC_region_restore(region->privatized.regions[i],
+ has_ref_regions ? ref_region->privatized.regions[i] : NULL);
+ }
+ break;
+ }
}
- return;
}
-static void MC_snapshot_add_region(mc_snapshot_t snapshot, int type,
- void *start_addr, void* permanent_addr, size_t size)
+static mc_mem_region_t MC_region_new_privatized(
+ mc_region_type_t region_type, void *start_addr, void* permanent_addr, size_t size,
+ mc_mem_region_t ref_reg)
+{
+ size_t process_count = MC_smpi_process_count();
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_PRIVATIZED;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
+ region->privatized.regions_count = process_count;
+ region->privatized.regions = xbt_new(mc_mem_region_t, process_count);
+
+ // Read smpi_privatisation_regions from MCed:
+ smpi_privatisation_region_t remote_smpi_privatisation_regions;
+ MC_process_read_variable(&mc_model_checker->process,
+ "smpi_privatisation_regions",
+ &remote_smpi_privatisation_regions, sizeof(remote_smpi_privatisation_regions));
+ s_smpi_privatisation_region_t privatisation_regions[process_count];
+ MC_process_read_simple(&mc_model_checker->process, &privatisation_regions,
+ remote_smpi_privatisation_regions, sizeof(privatisation_regions));
+
+ for (size_t i = 0; i < process_count; i++) {
+ mc_mem_region_t ref_subreg = NULL;
+ if (ref_reg && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED)
+ ref_subreg = ref_reg->privatized.regions[i];
+ region->privatized.regions[i] =
+ MC_region_new(region_type, start_addr,
+ privatisation_regions[i].address, size,
+ ref_subreg);
+ }
+
+ return region;
+}
+static void MC_snapshot_add_region(int index, mc_snapshot_t snapshot, mc_region_type_t type,
+ mc_object_info_t object_info,
+ void *start_addr, void* permanent_addr, size_t size)
{
- mc_mem_region_t ref_reg =
- mc_model_checker->parent_snapshot ? mc_model_checker->parent_snapshot->regions[type] : NULL;
- mc_mem_region_t new_reg = MC_region_new(type, start_addr, permanent_addr, size, ref_reg);
- snapshot->regions[type] = new_reg;
+ if (type == MC_REGION_TYPE_DATA)
+ xbt_assert(object_info, "Missing object info for object.");
+ else if (type == MC_REGION_TYPE_HEAP)
+ xbt_assert(!object_info, "Unexpected object info for heap region.");
+
+ mc_mem_region_t ref_reg = NULL;
+ if (mc_model_checker->parent_snapshot)
+ ref_reg = mc_model_checker->parent_snapshot->snapshot_regions[index];
+
+ mc_mem_region_t region;
+ const bool privatization_aware = MC_object_info_is_privatized(object_info);
+ if (privatization_aware && MC_smpi_process_count())
+ region = MC_region_new_privatized(type, start_addr, permanent_addr, size, ref_reg);
+ else
+ region = MC_region_new(type, start_addr, permanent_addr, size, ref_reg);
+
+ region->object_info = object_info;
+ snapshot->snapshot_regions[index] = region;
return;
}
-static void MC_get_memory_regions(mc_snapshot_t snapshot)
+static void MC_get_memory_regions(mc_process_t process, mc_snapshot_t snapshot)
{
+ const size_t n = process->object_infos_size;
+ snapshot->snapshot_regions_count = n + 1;
+ snapshot->snapshot_regions = xbt_new0(mc_mem_region_t, n + 1);
+
+ for (size_t i = 0; i!=n; ++i) {
+ mc_object_info_t object_info = process->object_infos[i];
+ MC_snapshot_add_region(i, snapshot, MC_REGION_TYPE_DATA, object_info,
+ object_info->start_rw, object_info->start_rw,
+ object_info->end_rw - object_info->start_rw);
+ }
- void *start_heap = std_heap->base;
- void *end_heap = std_heap->breakval;
- MC_snapshot_add_region(snapshot, 0, start_heap, start_heap,
- (char *) end_heap - (char *) start_heap);
- snapshot->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
- snapshot->privatization_regions = NULL;
+ xbt_mheap_t heap = MC_process_get_heap(process);
+ void *start_heap = heap->base;
+ void *end_heap = heap->breakval;
- MC_snapshot_add_region(snapshot, 1,
- mc_libsimgrid_info->start_rw, mc_libsimgrid_info->start_rw,
- mc_libsimgrid_info->end_rw - mc_libsimgrid_info->start_rw);
+ MC_snapshot_add_region(n, snapshot, MC_REGION_TYPE_HEAP, NULL,
+ start_heap, start_heap,
+ (char *) end_heap - (char *) start_heap);
+ snapshot->heap_bytes_used = mmalloc_get_bytes_used_remote(
+ heap->heaplimit,
+ MC_process_get_malloc_info(process));
#ifdef HAVE_SMPI
- size_t i;
- if (smpi_privatize_global_variables && smpi_process_count()) {
- // Snapshot the global variable of the application separately for each
- // simulated process:
- snapshot->privatization_regions =
- xbt_new(mc_mem_region_t, smpi_process_count());
- for (i = 0; i < smpi_process_count(); i++) {
- mc_mem_region_t ref_reg =
- mc_model_checker->parent_snapshot ? mc_model_checker->parent_snapshot->privatization_regions[i] : NULL;
- snapshot->privatization_regions[i] =
- MC_region_new(-1, mc_binary_info->start_rw, smpi_privatisation_regions[i].address, size_data_exe, ref_reg);
- }
- snapshot->privatization_index = smpi_loaded_page;
- snapshot->regions[2] = NULL;
+ if (smpi_privatize_global_variables && MC_smpi_process_count()) {
+ // snapshot->privatization_index = smpi_loaded_page
+ MC_process_read_variable(&mc_model_checker->process,
+ "smpi_loaded_page", &snapshot->privatization_index,
+ sizeof(snapshot->privatization_index));
} else
#endif
{
- MC_snapshot_add_region(snapshot, 2,
- mc_binary_info->start_rw, mc_binary_info->start_rw,
- mc_binary_info->end_rw - mc_binary_info->start_rw);
- snapshot->privatization_regions = NULL;
- snapshot->privatization_index = -1;
+ snapshot->privatization_index = MC_PROCESS_INDEX_MISSING;
}
}
-/** @brief Finds the range of the different memory segments and binary paths */
-void MC_init_memory_map_info()
-{
-
- unsigned int i = 0;
- s_map_region_t reg;
- memory_map_t maps = MC_get_memory_map();
-
- maestro_stack_start = NULL;
- maestro_stack_end = NULL;
- libsimgrid_path = NULL;
-
- while (i < maps->mapsize) {
- reg = maps->regions[i];
- if (maps->regions[i].pathname == NULL) {
- // Nothing to do
- } else if ((reg.prot & PROT_WRITE)
- && !memcmp(maps->regions[i].pathname, "[stack]", 7)) {
- maestro_stack_start = reg.start_addr;
- maestro_stack_end = reg.end_addr;
- } else if ((reg.prot & PROT_READ) && (reg.prot & PROT_EXEC)
- && !memcmp(basename(maps->regions[i].pathname), "libsimgrid",
- 10)) {
- if (libsimgrid_path == NULL)
- libsimgrid_path = strdup(maps->regions[i].pathname);
- }
- i++;
- }
-
- xbt_assert(maestro_stack_start, "maestro_stack_start");
- xbt_assert(maestro_stack_end, "maestro_stack_end");
- xbt_assert(libsimgrid_path, "libsimgrid_path&");
-
- MC_free_memory_map(maps);
-
-}
-
/** \brief Fills the position of the segments (executable, read-only, read/write).
*
- * TODO, use dl_iterate_phdr to be more robust
+ * `dl_iterate_phdr` would be more robust but would not work in cross-process.
* */
void MC_find_object_address(memory_map_t maps, mc_object_info_t result)
{
-
unsigned int i = 0;
s_map_region_t reg;
const char *name = basename(result->file_name);
i++;
}
+ result->start = result->start_rw;
+ if ((const void*) result->start_ro > result->start)
+ result->start = result->start_ro;
+ if ((const void*) result->start_exec > result->start)
+ result->start = result->start_exec;
+
+ result->end = result->end_rw;
+ if (result->end_ro && (const void*) result->end_ro < result->end)
+ result->end = result->end_ro;
+ if (result->end_exec && (const void*) result->end_exec > result->end)
+ result->end = result->end_exec;
+
xbt_assert(result->file_name);
xbt_assert(result->start_rw);
xbt_assert(result->start_exec);
static void mc_fill_local_variables_values(mc_stack_frame_t stack_frame,
dw_frame_t scope, int process_index, xbt_dynar_t result)
{
+ mc_process_t process = &mc_model_checker->process;
+
void *ip = (void *) stack_frame->ip;
if (ip < scope->low_pc || ip >= scope->high_pc)
return;
continue;
int region_type;
- if ((long) stack_frame->ip > (long) mc_libsimgrid_info->start_exec)
+ // FIXME, get rid of `region_type`
+ if ((long) stack_frame->ip > (long) process->libsimgrid_info->start_exec)
region_type = 1;
else
region_type = 2;
new_var->address = current_variable->address;
} else if (current_variable->locations.size != 0) {
s_mc_location_t location;
- mc_dwarf_resolve_locations(&location, ¤t_variable->locations,
- current_variable->object_info,
- &(stack_frame->unw_cursor),
- (void *) stack_frame->frame_base,
- NULL, process_index);
+ mc_dwarf_resolve_locations(
+ &location, ¤t_variable->locations,
+ current_variable->object_info,
+ &(stack_frame->unw_cursor),
+ (void *) stack_frame->frame_base,
+ (mc_address_space_t) &mc_model_checker->process, process_index);
switch(mc_get_location_type(&location)) {
case MC_LOCATION_TYPE_ADDRESS:
}
}
-static xbt_dynar_t MC_unwind_stack_frames(void *stack_context)
+static xbt_dynar_t MC_unwind_stack_frames(mc_unw_context_t stack_context)
{
+ mc_process_t process = &mc_model_checker->process;
xbt_dynar_t result =
xbt_dynar_new(sizeof(mc_stack_frame_t), MC_stack_frame_free_voipd);
unw_cursor_t c;
// TODO, check condition check (unw_init_local==0 means end of frame)
- if (unw_init_local(&c, (unw_context_t *) stack_context) != 0) {
+ if (mc_unw_init_cursor(&c, stack_context) != 0) {
xbt_die("Could not initialize stack unwinding");
// TODO, use real addresses in frame_t instead of fixing it here
- dw_frame_t frame = MC_find_function_by_ip((void *) ip);
+ dw_frame_t frame = MC_process_find_function(process, (void *) ip);
stack_frame->frame = frame;
if (frame) {
&& !strcmp(frame->name, "smx_ctx_sysv_wrapper"))
break;
- int ret = ret = unw_step(&c);
+ int ret = unw_step(&c);
if (ret == 0) {
xbt_die("Unexpected end of stack.");
} else if (ret < 0) {
- xbt_die("Error while unwinding stack.");
+ xbt_die("Error while unwinding stack");
}
}
unsigned int cursor = 0;
stack_region_t current_stack;
+ // FIXME, cross-process support (stack_areas)
xbt_dynar_foreach(stacks_areas, cursor, current_stack) {
mc_snapshot_stack_t st = xbt_new(s_mc_snapshot_stack_t, 1);
- st->stack_frames = MC_unwind_stack_frames(current_stack->context);
+
+ // Read the context from remote process:
+ unw_context_t context;
+ MC_process_read_simple(&mc_model_checker->process,
+ &context, (unw_context_t*) current_stack->context, sizeof(context));
+
+ st->context = xbt_new0(s_mc_unw_context_t, 1);
+ if (mc_unw_init_context(st->context, &mc_model_checker->process,
+ &context) < 0) {
+ xbt_die("Could not initialise the libunwind context.");
+ }
+
+ st->stack_frames = MC_unwind_stack_frames(st->context);
st->local_variables = MC_get_local_variables_values(st->stack_frames, current_stack->process_index);
st->process_index = current_stack->process_index;
static void MC_snapshot_handle_ignore(mc_snapshot_t snapshot)
{
+ xbt_assert(snapshot->process);
snapshot->ignored_data = xbt_dynar_new(sizeof(s_mc_snapshot_ignored_data_t), mc_free_snapshot_ignored_data_pvoid);
// Copy the memory:
unsigned int cursor = 0;
mc_checkpoint_ignore_region_t region;
- xbt_dynar_foreach (mc_checkpoint_ignore, cursor, region) {
+ xbt_dynar_foreach (mc_model_checker->process.checkpoint_ignore, cursor, region) {
s_mc_snapshot_ignored_data_t ignored_data;
ignored_data.start = region->addr;
ignored_data.size = region->size;
ignored_data.data = malloc(region->size);
- memcpy(ignored_data.data, region->addr, region->size);
+ // TODO, we should do this once per privatization segment:
+ MC_process_read(snapshot->process,
+ MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ ignored_data.data, region->addr, region->size, MC_PROCESS_INDEX_DISABLED);
xbt_dynar_push(snapshot->ignored_data, &ignored_data);
}
// Zero the memory:
- xbt_dynar_foreach (mc_checkpoint_ignore, cursor, region) {
- memset(region->addr, 0, region->size);
+ xbt_dynar_foreach (mc_model_checker->process.checkpoint_ignore, cursor, region) {
+ MC_process_clear_memory(snapshot->process, region->addr, region->size);
}
}
unsigned int cursor = 0;
s_mc_snapshot_ignored_data_t ignored_data;
xbt_dynar_foreach (snapshot->ignored_data, cursor, ignored_data) {
- memcpy(ignored_data.start, ignored_data.data, ignored_data.size);
+ MC_process_write(snapshot->process,
+ ignored_data.data, ignored_data.start, ignored_data.size);
}
}
return false;
}
-static void MC_get_current_fd(mc_snapshot_t snapshot){
+static void MC_get_current_fd(mc_snapshot_t snapshot)
+{
snapshot->total_fd = 0;
const size_t fd_dir_path_size = 20;
char fd_dir_path[fd_dir_path_size];
if (snprintf(fd_dir_path, fd_dir_path_size,
- "/proc/%lli/fd", (long long int) getpid()) > fd_dir_path_size)
+ "/proc/%lli/fd", (long long int) snapshot->process->pid) > fd_dir_path_size)
xbt_die("Unexpected buffer is too small for fd_dir_path");
- DIR* fd_dir = opendir (fd_dir_path);
+ DIR* fd_dir = opendir(fd_dir_path);
if (fd_dir == NULL)
xbt_die("Cannot open directory '/proc/self/fd'\n");
const size_t source_size = 25;
char source[25];
- if (snprintf(source, source_size, "/proc/self/fd/%s", fd_number->d_name) > source_size)
+ if (snprintf(source, source_size, "/proc/%lli/fd/%s",
+ (long long int) snapshot->process->pid, fd_number->d_name) > source_size)
xbt_die("Unexpected buffer is too small for fd %s", fd_number->d_name);
const size_t link_size = 200;
closedir (fd_dir);
}
+static s_mc_address_space_class_t mc_snapshot_class = {
+ .read = (void*) &MC_snapshot_read
+};
+
mc_snapshot_t MC_take_snapshot(int num_state)
{
+ XBT_DEBUG("Taking snapshot %i", num_state);
+ mc_process_t mc_process = &mc_model_checker->process;
mc_snapshot_t snapshot = xbt_new0(s_mc_snapshot_t, 1);
+ snapshot->process = mc_process;
+ snapshot->num_state = num_state;
+ snapshot->address_space.address_space_class = &mc_snapshot_class;
+
snapshot->enabled_processes = xbt_dynar_new(sizeof(int), NULL);
+
smx_process_t process;
- xbt_swag_foreach(process, simix_global->process_list) {
- xbt_dynar_push_as(snapshot->enabled_processes, int, (int)process->pid);
- }
+ MC_EACH_SIMIX_PROCESS(process,
+ xbt_dynar_push_as(snapshot->enabled_processes, int, (int)process->pid));
MC_snapshot_handle_ignore(snapshot);
- MC_get_current_fd(snapshot);
+ if (_sg_mc_snapshot_fds)
+ MC_get_current_fd(snapshot);
+
+ const bool use_soft_dirty = _sg_mc_sparse_checkpoint
+ && _sg_mc_soft_dirty
+ && MC_process_is_self(mc_process);
/* Save the std heap and the writable mapped pages of libsimgrid and binary */
- MC_get_memory_regions(snapshot);
- if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
+ MC_get_memory_regions(mc_process, snapshot);
+ if (use_soft_dirty)
mc_softdirty_reset();
- }
snapshot->to_ignore = MC_take_snapshot_ignore();
}
MC_snapshot_ignore_restore(snapshot);
- if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
+ if (use_soft_dirty)
mc_model_checker->parent_snapshot = snapshot;
- }
return snapshot;
}
-void MC_restore_snapshot(mc_snapshot_t snapshot)
+static inline
+void MC_restore_snapshot_regions(mc_snapshot_t snapshot)
{
mc_snapshot_t parent_snapshot = mc_model_checker->parent_snapshot;
- int new_fd;
- unsigned int i;
- for (i = 0; i < NB_REGIONS; i++) {
+ const size_t n = snapshot->snapshot_regions_count;
+ for (size_t i = 0; i < n; i++) {
// For privatized, variables we decided it was not necessary to take the snapshot:
- if (snapshot->regions[i])
- MC_region_restore(snapshot->regions[i],
- parent_snapshot ? parent_snapshot->regions[i] : NULL);
+ if (snapshot->snapshot_regions[i])
+ MC_region_restore(snapshot->snapshot_regions[i],
+ parent_snapshot ? parent_snapshot->snapshot_regions[i] : NULL);
}
#ifdef HAVE_SMPI
- if (snapshot->privatization_regions) {
- // Restore the global variables of the application separately for each
- // simulated process:
- for (i = 0; i < smpi_process_count(); i++) {
- if (snapshot->privatization_regions[i]) {
- MC_region_restore(snapshot->privatization_regions[i],
- parent_snapshot ? parent_snapshot->privatization_regions[i] : NULL);
- }
- }
- }
+ // TODO, send a message to implement this in the MCed process
if(snapshot->privatization_index >= 0) {
// We just rewrote the global variables.
// The privatisation segment SMPI thinks
smpi_really_switch_data_segment(snapshot->privatization_index);
}
#endif
+}
+
+static inline
+void MC_restore_snapshot_fds(mc_snapshot_t snapshot)
+{
+ if (mc_mode == MC_MODE_SERVER)
+ xbt_die("FD snapshot not implemented in client/server mode.");
+ int new_fd;
+ size_t i;
for(i=0; i < snapshot->total_fd; i++){
new_fd = open(snapshot->current_fd[i]->filename, snapshot->current_fd[i]->flags);
};
lseek(snapshot->current_fd[i]->number, snapshot->current_fd[i]->current_position, SEEK_SET);
}
+}
+
+void MC_restore_snapshot(mc_snapshot_t snapshot)
+{
+ XBT_DEBUG("Restore snapshot %i", snapshot->num_state);
+
+ const bool use_soft_dirty = _sg_mc_sparse_checkpoint
+ && _sg_mc_soft_dirty
+ && MC_process_is_self(&mc_model_checker->process);
- if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
+ MC_restore_snapshot_regions(snapshot);
+ if (_sg_mc_snapshot_fds)
+ MC_restore_snapshot_fds(snapshot);
+ if (use_soft_dirty) {
mc_softdirty_reset();
}
-
MC_snapshot_ignore_restore(snapshot);
- if (_sg_mc_sparse_checkpoint && _sg_mc_soft_dirty) {
+ if (use_soft_dirty) {
mc_model_checker->parent_snapshot = snapshot;
}
+ mc_model_checker->process.cache_flags = 0;
}
mc_snapshot_t simcall_HANDLER_mc_snapshot(smx_simcall_t simcall)
{
return MC_take_snapshot(1);
}
-
-void *MC_snapshot(void)
-{
- return simcall_mc_snapshot();
-}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <error.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <xbt/log.h>
+#include <xbt/sysdep.h>
+#include <xbt/mmalloc.h>
+
+#include "mc_protocol.h"
+#include "mc_client.h"
+
+// We won't need those once the separation MCer/MCed is complete:
+#include "mc_mmalloc.h"
+#include "mc_ignore.h"
+#include "mc_model_checker.h"
+#include "mc_private.h" // MC_deadlock_check()
+#include "mc_smx.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_client, mc, "MC client logic");
+
+mc_client_t mc_client;
+
+void MC_client_init(void)
+{
+ if (mc_client) {
+ XBT_WARN("MC_client_init called more than once.");
+ return;
+ }
+
+ char* fd_env = getenv(MC_ENV_SOCKET_FD);
+ if (!fd_env)
+ xbt_die("MC socket not found");
+
+ int fd = atoi(fd_env);
+ XBT_DEBUG("Model-checked application found socket FD %i", fd);
+
+ int type;
+ socklen_t socklen = sizeof(type);
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &socklen) != 0)
+ xbt_die("Could not check socket type");
+ if (type != SOCK_DGRAM)
+ xbt_die("Unexpected socket type %i", type);
+ XBT_DEBUG("Model-checked application found expected socket type");
+
+ mc_client = xbt_new0(s_mc_client_t, 1);
+ mc_client->fd = fd;
+ mc_client->active = 1;
+}
+
+void MC_client_hello(void)
+{
+ if (MC_protocol_hello(mc_client->fd) != 0)
+ xbt_die("Could not say hello the MC server");
+}
+
+void MC_client_send_message(void* message, size_t size)
+{
+ if (MC_protocol_send(mc_client->fd, message, size))
+ xbt_die("Could not send message %i", (int) ((mc_message_t)message)->type);
+}
+
+void MC_client_send_simple_message(int type)
+{
+ if (MC_protocol_send_simple_message(mc_client->fd, type))
+ xbt_die("Could not send message %i", type);
+}
+
+void MC_client_handle_messages(void)
+{
+ while (1) {
+ XBT_DEBUG("Waiting messages from model-checker");
+
+ char message_buffer[MC_MESSAGE_LENGTH];
+ size_t s;
+ if ((s = MC_receive_message(mc_client->fd, &message_buffer, sizeof(message_buffer), 0)) == -1)
+ xbt_die("Could not receive commands from the model-checker");
+
+ s_mc_message_t message;
+ if (s < sizeof(message))
+ xbt_die("Received message is too small");
+ memcpy(&message, message_buffer, sizeof(message));
+ switch (message.type) {
+
+ case MC_MESSAGE_DEADLOCK_CHECK:
+ {
+ int result = MC_deadlock_check();
+ s_mc_int_message_t answer;
+ answer.type = MC_MESSAGE_DEADLOCK_CHECK_REPLY;
+ answer.value = result;
+ if (MC_protocol_send(mc_client->fd, &answer, sizeof(answer)))
+ xbt_die("Could not send response");
+ }
+ break;
+
+ case MC_MESSAGE_CONTINUE:
+ return;
+
+ case MC_MESSAGE_SIMCALL_HANDLE:
+ {
+ s_mc_simcall_handle_message_t message;
+ if (s != sizeof(message))
+ xbt_die("Unexpected size for SIMCALL_HANDLE");
+ memcpy(&message, message_buffer, sizeof(message));
+ smx_process_t process = SIMIX_process_from_PID(message.pid);
+ if (!process)
+ xbt_die("Invalid pid %lu", (unsigned long) message.pid);
+ SIMIX_simcall_handle(&process->simcall, message.value);
+ MC_protocol_send_simple_message(mc_client->fd, MC_MESSAGE_WAITING);
+ }
+ break;
+
+ default:
+ xbt_die("%s received unexpected message %s (%i)",
+ MC_mode_name(mc_mode),
+ MC_message_type_name(message.type),
+ message.type
+ );
+ }
+ }
+}
+
+void MC_client_main_loop(void)
+{
+ while (1) {
+ MC_protocol_send_simple_message(mc_client->fd, MC_MESSAGE_WAITING);
+ MC_client_handle_messages();
+ MC_wait_for_requests();
+ }
+}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_CLIENT_H
+#define MC_CLIENT_H
+
+#include <xbt/misc.h>
+
+SG_BEGIN_DECL()
+
+typedef struct s_mc_client {
+ int active;
+ int fd;
+} s_mc_client_t, *mc_client_t;
+
+extern mc_client_t mc_client;
+
+void MC_client_init(void);
+void MC_client_hello(void);
+void MC_client_handle_messages(void);
+void MC_client_send_message(void* message, size_t size);
+void MC_client_send_simple_message(int type);
+
+#ifdef HAVE_MC
+void MC_ignore(void* addr, size_t size);
+#endif
+
+void MC_client_main_loop(void);
+
+SG_END_DECL()
+
+#endif
--- /dev/null
+/* Copyright (c) 2008-2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <xbt/log.h>
+#include <xbt/fifo.h>
+#include <xbt/sysdep.h>
+#include <simgrid/modelchecker.h>
+
+#include "mc_record.h"
+#include "mc_private.h"
+#include "mc_mmalloc.h"
+#include "mc_model_checker.h"
+#include "mc_ignore.h"
+#include "mc_protocol.h"
+#include "mc_client.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_client_api, mc,
+ "Public API for the model-checked application");
+
+void MC_assert(int prop)
+{
+ if (MC_is_active() && !prop) {
+ if (mc_mode == MC_MODE_STANDALONE) {
+ MC_report_assertion_error();
+ } else {
+ MC_client_send_simple_message(MC_MESSAGE_ASSERTION_FAILED);
+ MC_client_handle_messages();
+ }
+ }
+}
+
+// TODO, MC_automaton_new_propositional_symbol
+
+void *MC_snapshot(void)
+{
+ return simcall_mc_snapshot();
+}
+
+int simcall_HANDLER_mc_compare_snapshots(smx_simcall_t simcall,
+ mc_snapshot_t s1, mc_snapshot_t s2)
+{
+ return snapshot_compare(s1, s2);
+}
+
+int MC_compare_snapshots(void *s1, void *s2)
+{
+ return simcall_mc_compare_snapshots(s1, s2);
+}
+
+void MC_cut(void)
+{
+ user_max_depth_reached = 1;
+}
+
+void MC_ignore(void* addr, size_t size)
+{
+ if (mc_mode == MC_MODE_CLIENT) {
+ s_mc_ignore_memory_message_t message;
+ message.type = MC_MESSAGE_IGNORE_MEMORY;
+ message.addr = addr;
+ message.size = size;
+ MC_client_send_message(&message, sizeof(message));
+ }
+
+ // TODO, remove this once the migration has been completed
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ MC_process_ignore_memory(&mc_model_checker->process, addr, size);
+ mmalloc_set_current_heap(heap);
+}
#include "mc_safety.h"
#include "mc_private.h"
#include "mc_record.h"
+#include "mc_smx.h"
+#include "mc_client.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_determinism, mc,
"Logging specific to MC communication determinism detection");
/********** Static functions ***********/
-static void comm_pattern_free(mc_comm_pattern_t p)
-{
- xbt_free(p->rdv);
- xbt_free(p->data);
- xbt_free(p);
- p = NULL;
-}
-
-static void list_comm_pattern_free(mc_list_comm_pattern_t l)
-{
- xbt_dynar_free(&(l->list));
- xbt_free(l);
- l = NULL;
-}
-
static e_mc_comm_pattern_difference_t compare_comm_pattern(mc_comm_pattern_t comm1, mc_comm_pattern_t comm2) {
if(comm1->type != comm2->type)
return TYPE_DIFF;
return res;
}
-static void update_comm_pattern(mc_comm_pattern_t comm_pattern, smx_synchro_t comm)
+static void update_comm_pattern(mc_comm_pattern_t comm_pattern, smx_synchro_t comm_addr)
{
- void *addr_pointed;
- comm_pattern->src_proc = comm->comm.src_proc->pid;
- comm_pattern->dst_proc = comm->comm.dst_proc->pid;
- comm_pattern->src_host = simcall_host_get_name(comm->comm.src_proc->smx_host);
- comm_pattern->dst_host = simcall_host_get_name(comm->comm.dst_proc->smx_host);
- if (comm_pattern->data_size == -1 && comm->comm.src_buff != NULL) {
- comm_pattern->data_size = *(comm->comm.dst_buff_size);
+ s_smx_synchro_t comm;
+ MC_process_read_simple(&mc_model_checker->process,
+ &comm, comm_addr, sizeof(comm));
+
+ smx_process_t src_proc = MC_smx_resolve_process(comm.comm.src_proc);
+ smx_process_t dst_proc = MC_smx_resolve_process(comm.comm.dst_proc);
+ comm_pattern->src_proc = src_proc->pid;
+ comm_pattern->dst_proc = dst_proc->pid;
+ comm_pattern->src_host = MC_smx_process_get_host_name(src_proc);
+ comm_pattern->dst_host = MC_smx_process_get_host_name(dst_proc);
+ if (comm_pattern->data_size == -1 && comm.comm.src_buff != NULL) {
+ size_t buff_size;
+ MC_process_read_simple(&mc_model_checker->process,
+ &buff_size, comm.comm.dst_buff_size, sizeof(buff_size));
+ comm_pattern->data_size = buff_size;
comm_pattern->data = xbt_malloc0(comm_pattern->data_size);
- addr_pointed = *(void **) comm->comm.src_buff;
- if (addr_pointed > (void*) std_heap && addr_pointed < std_heap->breakval)
- memcpy(comm_pattern->data, addr_pointed, comm_pattern->data_size);
- else
- memcpy(comm_pattern->data, comm->comm.src_buff, comm_pattern->data_size);
+ MC_process_read_simple(&mc_model_checker->process,
+ comm_pattern->data, comm.comm.src_buff, comm_pattern->data_size);
}
}
static void deterministic_comm_pattern(int process, mc_comm_pattern_t comm, int backtracking) {
- mc_list_comm_pattern_t list_comm_pattern = (mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, process, mc_list_comm_pattern_t);
+ mc_list_comm_pattern_t list =
+ xbt_dynar_get_as(initial_communications_pattern, process, mc_list_comm_pattern_t);
if(!backtracking){
- mc_comm_pattern_t initial_comm = xbt_dynar_get_as(list_comm_pattern->list, list_comm_pattern->index_comm, mc_comm_pattern_t);
- e_mc_comm_pattern_difference_t diff;
-
- if((diff = compare_comm_pattern(initial_comm, comm)) != NONE_DIFF){
+ mc_comm_pattern_t initial_comm =
+ xbt_dynar_get_as(list->list, list->index_comm, mc_comm_pattern_t);
+ e_mc_comm_pattern_difference_t diff =
+ compare_comm_pattern(initial_comm, comm);
+
+ if (diff != NONE_DIFF) {
if (comm->type == SIMIX_COMM_SEND){
initial_global_state->send_deterministic = 0;
if(initial_global_state->send_diff != NULL)
xbt_free(initial_global_state->send_diff);
- initial_global_state->send_diff = print_determinism_result(diff, process, comm, list_comm_pattern->index_comm + 1);
+ initial_global_state->send_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
}else{
initial_global_state->recv_deterministic = 0;
if(initial_global_state->recv_diff != NULL)
xbt_free(initial_global_state->recv_diff);
- initial_global_state->recv_diff = print_determinism_result(diff, process, comm, list_comm_pattern->index_comm + 1);
+ initial_global_state->recv_diff = print_determinism_result(diff, process, comm, list->index_comm + 1);
}
if(_sg_mc_send_determinism && !initial_global_state->send_deterministic){
XBT_INFO("*********************************************************");
}
}
- comm_pattern_free(comm);
+ MC_comm_pattern_free(comm);
}
/********** Non Static functions ***********/
-void comm_pattern_free_voidp(void *p) {
- comm_pattern_free((mc_comm_pattern_t) * (void **) p);
-}
-
-void list_comm_pattern_free_voidp(void *p) {
- list_comm_pattern_free((mc_list_comm_pattern_t) * (void **) p);
-}
-
-void get_comm_pattern(xbt_dynar_t list, smx_simcall_t request, e_mc_call_type_t call_type, int backtracking)
+void MC_get_comm_pattern(xbt_dynar_t list, smx_simcall_t request, e_mc_call_type_t call_type, int backtracking)
{
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(request);
+ mc_list_comm_pattern_t initial_pattern = xbt_dynar_get_as(
+ initial_communications_pattern, issuer->pid, mc_list_comm_pattern_t);
+ xbt_dynar_t incomplete_pattern = xbt_dynar_get_as(
+ incomplete_communications_pattern, issuer->pid, xbt_dynar_t);
- mc_comm_pattern_t pattern = NULL;
- pattern = xbt_new0(s_mc_comm_pattern_t, 1);
+ mc_comm_pattern_t pattern = xbt_new0(s_mc_comm_pattern_t, 1);
pattern->data_size = -1;
pattern->data = NULL;
-
- void *addr_pointed;
-
+ pattern->index =
+ initial_pattern->index_comm + xbt_dynar_length(incomplete_pattern);
+
if (call_type == MC_CALL_TYPE_SEND) {
/* Create comm pattern */
pattern->type = SIMIX_COMM_SEND;
- pattern->comm = simcall_comm_isend__get__result(request);
- pattern->rdv = (pattern->comm->comm.rdv != NULL) ? strdup(pattern->comm->comm.rdv->name) : strdup(pattern->comm->comm.rdv_cpy->name);
- pattern->src_proc = pattern->comm->comm.src_proc->pid;
- pattern->src_host = simcall_host_get_name(request->issuer->smx_host);
- pattern->tag = ((MPI_Request)simcall_comm_isend__get__data(request))->tag;
- if(pattern->comm->comm.src_buff != NULL){
- pattern->data_size = pattern->comm->comm.src_buff_size;
+ pattern->comm_addr = simcall_comm_isend__get__result(request);
+
+ s_smx_synchro_t synchro;
+ MC_process_read_simple(&mc_model_checker->process,
+ &synchro, pattern->comm_addr, sizeof(synchro));
+
+ char* remote_name;
+ MC_process_read_simple(&mc_model_checker->process, &remote_name,
+ synchro.comm.rdv ? &synchro.comm.rdv->name : &synchro.comm.rdv_cpy->name,
+ sizeof(remote_name));
+ pattern->rdv =
+ MC_process_read_string(&mc_model_checker->process, remote_name);
+ pattern->src_proc = MC_smx_resolve_process(synchro.comm.src_proc)->pid;
+ pattern->src_host = MC_smx_process_get_host_name(issuer);
+
+ struct s_smpi_mpi_request mpi_request;
+ MC_process_read_simple(&mc_model_checker->process,
+ &mpi_request, (MPI_Request) simcall_comm_isend__get__data(request),
+ sizeof(mpi_request));
+ pattern->tag = mpi_request.tag;
+
+ if(synchro.comm.src_buff != NULL){
+ pattern->data_size = synchro.comm.src_buff_size;
pattern->data = xbt_malloc0(pattern->data_size);
- addr_pointed = *(void **) pattern->comm->comm.src_buff;
- if (addr_pointed > (void*) std_heap && addr_pointed < std_heap->breakval)
- memcpy(pattern->data, addr_pointed, pattern->data_size);
- else
- memcpy(pattern->data, pattern->comm->comm.src_buff, pattern->data_size);
+ MC_process_read_simple(&mc_model_checker->process,
+ pattern->data, synchro.comm.src_buff, pattern->data_size);
}
- if(((MPI_Request)simcall_comm_isend__get__data(request))->detached){
+ if(mpi_request.detached){
if (!initial_global_state->initial_communications_pattern_done) {
/* Store comm pattern */
- xbt_dynar_push(((mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t))->list, &pattern);
+ xbt_dynar_push(
+ xbt_dynar_get_as(
+ initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t
+ )->list,
+ &pattern);
} else {
/* Evaluate comm determinism */
deterministic_comm_pattern(pattern->src_proc, pattern, backtracking);
- ((mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t))->index_comm++;
+ xbt_dynar_get_as(
+ initial_communications_pattern, pattern->src_proc, mc_list_comm_pattern_t
+ )->index_comm++;
}
return;
}
} else if (call_type == MC_CALL_TYPE_RECV) {
pattern->type = SIMIX_COMM_RECEIVE;
- pattern->comm = simcall_comm_irecv__get__result(request);
- pattern->tag = ((MPI_Request)simcall_comm_irecv__get__data(request))->tag;
- pattern->rdv = (pattern->comm->comm.rdv != NULL) ? strdup(pattern->comm->comm.rdv->name) : strdup(pattern->comm->comm.rdv_cpy->name);
- pattern->dst_proc = pattern->comm->comm.dst_proc->pid;
- pattern->dst_host = simcall_host_get_name(request->issuer->smx_host);
+ pattern->comm_addr = simcall_comm_irecv__get__result(request);
+
+ struct s_smpi_mpi_request mpi_request;
+ MC_process_read_simple(&mc_model_checker->process,
+ &mpi_request, (MPI_Request) simcall_comm_irecv__get__data(request),
+ sizeof(mpi_request));
+ pattern->tag = mpi_request.tag;
+
+ s_smx_synchro_t synchro;
+ MC_process_read_simple(&mc_model_checker->process,
+ &synchro, pattern->comm_addr, sizeof(synchro));
+
+ char* remote_name;
+ MC_process_read_simple(&mc_model_checker->process, &remote_name,
+ synchro.comm.rdv ? &synchro.comm.rdv->name : &synchro.comm.rdv_cpy->name,
+ sizeof(remote_name));
+ pattern->rdv =
+ MC_process_read_string(&mc_model_checker->process, remote_name);
+ pattern->dst_proc = MC_smx_resolve_process(synchro.comm.dst_proc)->pid;
+ pattern->dst_host = MC_smx_process_get_host_name(issuer);
} else {
xbt_die("Unexpected call_type %i", (int) call_type);
}
- xbt_dynar_push((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, request->issuer->pid, xbt_dynar_t), &pattern);
+ xbt_dynar_push(
+ xbt_dynar_get_as(incomplete_communications_pattern, issuer->pid, xbt_dynar_t),
+ &pattern);
- XBT_DEBUG("Insert incomplete comm pattern %p for process %lu", pattern, request->issuer->pid);
+ XBT_DEBUG("Insert incomplete comm pattern %p for process %lu", pattern, issuer->pid);
}
-void complete_comm_pattern(xbt_dynar_t list, smx_synchro_t comm, unsigned int issuer, int backtracking) {
-
+void MC_complete_comm_pattern(xbt_dynar_t list, smx_synchro_t comm_addr, unsigned int issuer, int backtracking) {
mc_comm_pattern_t current_comm_pattern;
unsigned int cursor = 0;
mc_comm_pattern_t comm_pattern;
int completed = 0;
/* Complete comm pattern */
- xbt_dynar_foreach((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, current_comm_pattern) {
- if (current_comm_pattern-> comm == comm) {
- update_comm_pattern(current_comm_pattern, comm);
+ xbt_dynar_foreach(xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, current_comm_pattern) {
+ if (current_comm_pattern->comm_addr == comm_addr) {
+ update_comm_pattern(current_comm_pattern, comm_addr);
completed = 1;
- xbt_dynar_remove_at((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t), cursor, &comm_pattern);
+ xbt_dynar_remove_at(
+ xbt_dynar_get_as(incomplete_communications_pattern, issuer, xbt_dynar_t),
+ cursor, &comm_pattern);
XBT_DEBUG("Remove incomplete comm pattern for process %u at cursor %u", issuer, cursor);
break;
}
if(!completed)
xbt_die("Corresponding communication not found!");
+ mc_list_comm_pattern_t pattern = xbt_dynar_get_as(
+ initial_communications_pattern, issuer, mc_list_comm_pattern_t);
+
if (!initial_global_state->initial_communications_pattern_done) {
/* Store comm pattern */
- xbt_dynar_push(((mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, issuer, mc_list_comm_pattern_t))->list, &comm_pattern);
+ xbt_dynar_push(pattern->list, &comm_pattern);
} else {
/* Evaluate comm determinism */
deterministic_comm_pattern(issuer, comm_pattern, backtracking);
- ((mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, issuer, mc_list_comm_pattern_t))->index_comm++;
+ pattern->index_comm++;
}
}
/************************ Main algorithm ************************/
-void MC_pre_modelcheck_comm_determinism(void)
-{
+static void MC_modelcheck_comm_determinism_main(void);
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
+static void MC_pre_modelcheck_comm_determinism(void)
+{
+ MC_SET_MC_HEAP;
mc_state_t initial_state = NULL;
smx_process_t process;
int i;
-
- if (!mc_mem_set)
- MC_SET_MC_HEAP;
+ const int maxpid = MC_smx_get_maxpid();
if (_sg_mc_visited > 0)
visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
- initial_communications_pattern = xbt_dynar_new(sizeof(mc_list_comm_pattern_t), list_comm_pattern_free_voidp);
- for (i=0; i<simix_process_maxpid; i++){
+ // Create initial_communications_pattern elements:
+ initial_communications_pattern = xbt_dynar_new(sizeof(mc_list_comm_pattern_t), MC_list_comm_pattern_free_voidp);
+ for (i=0; i < maxpid; i++){
mc_list_comm_pattern_t process_list_pattern = xbt_new0(s_mc_list_comm_pattern_t, 1);
- process_list_pattern->list = xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp);
+ process_list_pattern->list = xbt_dynar_new(sizeof(mc_comm_pattern_t), MC_comm_pattern_free_voidp);
process_list_pattern->index_comm = 0;
xbt_dynar_insert_at(initial_communications_pattern, i, &process_list_pattern);
}
+
+ // Create incomplete_communications_pattern elements:
incomplete_communications_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
- for (i=0; i<simix_process_maxpid; i++){
+ for (i=0; i < maxpid; i++){
xbt_dynar_t process_pattern = xbt_dynar_new(sizeof(mc_comm_pattern_t), NULL);
xbt_dynar_insert_at(incomplete_communications_pattern, i, &process_pattern);
}
MC_SET_MC_HEAP;
/* Get an enabled process and insert it in the interleave set of the initial state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(initial_state, process);
}
- }
+ );
xbt_fifo_unshift(mc_stack, initial_state);
}
-void MC_modelcheck_comm_determinism(void)
+static void MC_modelcheck_comm_determinism_main(void)
{
char *req_str = NULL;
&& (req = MC_state_get_request(state, &value))
&& (visited_state == NULL)) {
- req_str = MC_request_to_string(req, value);
- XBT_DEBUG("Execute: %s", req_str);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
+ XBT_DEBUG("Execute: %s", req_str);
xbt_free(req_str);
if (dot_output != NULL) {
/* TODO : handle test and testany simcalls */
e_mc_call_type_t call = MC_CALL_TYPE_NONE;
if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
- call = mc_get_call_type(req);
+ call = MC_get_call_type(req);
}
/* Answer the request */
- SIMIX_simcall_handle(req, value); /* After this call req is no longer useful */
+ MC_simcall_handle(req, value); /* After this call req is no longer useful */
MC_SET_MC_HEAP;
if(!initial_global_state->initial_communications_pattern_done)
- handle_comm_pattern(call, req, value, initial_communications_pattern, 0);
+ MC_handle_comm_pattern(call, req, value, initial_communications_pattern, 0);
else
- handle_comm_pattern(call, req, value, NULL, 0);
+ MC_handle_comm_pattern(call, req, value, NULL, 0);
MC_SET_STD_HEAP;
/* Wait for requests (schedules processes) */
if ((visited_state = is_visited_state(next_state)) == NULL) {
/* Get enabled processes and insert them in the interleave set of the next state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(next_state, process);
}
- }
+ );
if (dot_output != NULL)
fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
MC_print_statistics(mc_stats);
MC_SET_STD_HEAP;
- return;
+ exit(0);
+}
+
+void MC_modelcheck_comm_determinism(void)
+{
+ if (mc_mode == MC_MODE_CLIENT) {
+ // This will move somehwere else:
+ MC_client_handle_messages();
+ }
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+
+ /* Create exploration stack */
+ mc_stack = xbt_fifo_new();
+
+ MC_SET_STD_HEAP;
+
+ MC_pre_modelcheck_comm_determinism();
+
+ MC_SET_MC_HEAP;
+ initial_global_state = xbt_new0(s_mc_global_t, 1);
+ initial_global_state->snapshot = MC_take_snapshot(0);
+ initial_global_state->initial_communications_pattern_done = 0;
+ initial_global_state->recv_deterministic = 1;
+ initial_global_state->send_deterministic = 1;
+ initial_global_state->recv_diff = NULL;
+ initial_global_state->send_diff = NULL;
+
+ MC_SET_STD_HEAP;
+
+ MC_modelcheck_comm_determinism_main();
+
+ mmalloc_set_current_heap(heap);
}
--- /dev/null
+/* Copyright (c) 2007-2014. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <string.h>
+
+#include <xbt/sysdep.h>
+#include <xbt/dynar.h>
+
+#include "mc_comm_pattern.h"
+#include "mc_smx.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_comm_pattern, mc,
+ "Logging specific to MC communication patterns");
+
+mc_comm_pattern_t MC_comm_pattern_dup(mc_comm_pattern_t comm)
+{
+ mc_comm_pattern_t res = xbt_new0(s_mc_comm_pattern_t, 1);
+ res->index = comm->index;
+ res->type = comm->type;
+ res->comm_addr = comm->comm_addr;
+ res->rdv = strdup(comm->rdv);
+ res->data_size = -1;
+ res->data = NULL;
+ if (comm->type == SIMIX_COMM_SEND) {
+ res->src_proc = comm->src_proc;
+ res->src_host = comm->src_host;
+ if (comm->data != NULL) {
+ res->data_size = comm->data_size;
+ res->data = xbt_malloc0(comm->data_size);
+ memcpy(res->data, comm->data, comm->data_size);
+ }
+ } else {
+ res->dst_proc = comm->dst_proc;
+ res->dst_host = comm->dst_host;
+ }
+ return res;
+}
+
+xbt_dynar_t MC_comm_patterns_dup(xbt_dynar_t patterns)
+{
+ xbt_dynar_t res = xbt_dynar_new(sizeof(mc_comm_pattern_t), MC_comm_pattern_free_voidp);
+
+ mc_comm_pattern_t comm;
+ unsigned int cursor;
+ xbt_dynar_foreach(patterns, cursor, comm) {
+ mc_comm_pattern_t copy_comm = MC_comm_pattern_dup(comm);
+ xbt_dynar_push(res, ©_comm);
+ }
+
+ return res;
+}
+
+static void MC_patterns_copy(xbt_dynar_t dest, xbt_dynar_t source)
+{
+ xbt_dynar_reset(dest);
+
+ unsigned int cursor;
+ mc_comm_pattern_t comm;
+ xbt_dynar_foreach(source, cursor, comm) {
+ mc_comm_pattern_t copy_comm = MC_comm_pattern_dup(comm);
+ xbt_dynar_push(dest, ©_comm);
+ }
+}
+
+void MC_restore_communications_pattern(mc_state_t state)
+{
+ mc_list_comm_pattern_t list_process_comm;
+ unsigned int cursor;
+
+ xbt_dynar_foreach(initial_communications_pattern, cursor, list_process_comm){
+ list_process_comm->index_comm = (int)xbt_dynar_get_as(state->index_comm, cursor, int);
+ }
+
+ for (int i = 0; i < MC_smx_get_maxpid(); i++) {
+ MC_patterns_copy(
+ xbt_dynar_get_as(incomplete_communications_pattern, i, xbt_dynar_t),
+ xbt_dynar_get_as(state->incomplete_comm_pattern, i, xbt_dynar_t)
+ );
+ }
+}
+
+void MC_state_copy_incomplete_communications_pattern(mc_state_t state)
+{
+ state->incomplete_comm_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
+
+ int i;
+ for (i=0; i < MC_smx_get_maxpid(); i++) {
+ xbt_dynar_t comms = xbt_dynar_get_as(incomplete_communications_pattern, i, xbt_dynar_t);
+ xbt_dynar_t copy = MC_comm_patterns_dup(comms);
+ xbt_dynar_insert_at(state->incomplete_comm_pattern, i, ©);
+ }
+}
+
+void MC_state_copy_index_communications_pattern(mc_state_t state)
+{
+ state->index_comm = xbt_dynar_new(sizeof(unsigned int), NULL);
+ mc_list_comm_pattern_t list_process_comm;
+ unsigned int cursor;
+ xbt_dynar_foreach(initial_communications_pattern, cursor, list_process_comm){
+ xbt_dynar_push_as(state->index_comm, unsigned int, list_process_comm->index_comm);
+ }
+}
+
+void MC_handle_comm_pattern(
+ e_mc_call_type_t call_type, smx_simcall_t req,
+ int value, xbt_dynar_t pattern, int backtracking)
+{
+
+ switch(call_type) {
+ case MC_CALL_TYPE_NONE:
+ break;
+ case MC_CALL_TYPE_SEND:
+ case MC_CALL_TYPE_RECV:
+ MC_get_comm_pattern(pattern, req, call_type, backtracking);
+ break;
+ case MC_CALL_TYPE_WAIT:
+ case MC_CALL_TYPE_WAITANY:
+ {
+ smx_synchro_t comm_addr = NULL;
+ if (call_type == MC_CALL_TYPE_WAIT)
+ comm_addr = simcall_comm_wait__get__comm(req);
+ else
+ // comm_addr = REMOTE(xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value, smx_synchro_t)):
+ MC_process_read_dynar_element(&mc_model_checker->process, &comm_addr,
+ simcall_comm_waitany__get__comms(req), value, sizeof(comm_addr));
+ MC_complete_comm_pattern(pattern, comm_addr,
+ MC_smx_simcall_get_issuer(req)->pid, backtracking);
+ }
+ break;
+ default:
+ xbt_die("Unexpected call type %i", (int)call_type);
+ }
+
+}
+
+void MC_comm_pattern_free(mc_comm_pattern_t p)
+{
+ xbt_free(p->rdv);
+ xbt_free(p->data);
+ xbt_free(p);
+ p = NULL;
+}
+
+static void MC_list_comm_pattern_free(mc_list_comm_pattern_t l)
+{
+ xbt_dynar_free(&(l->list));
+ xbt_free(l);
+ l = NULL;
+}
+
+void MC_comm_pattern_free_voidp(void *p)
+{
+ MC_comm_pattern_free((mc_comm_pattern_t) * (void **) p);
+}
+
+void MC_list_comm_pattern_free_voidp(void *p)
+{
+ MC_list_comm_pattern_free((mc_list_comm_pattern_t) * (void **) p);
+}
#include "../smpi/private.h"
#include <smpi/smpi.h>
+#include "mc_state.h"
+
#ifndef MC_COMM_PATTERN_H
#define MC_COMM_PATTERN_H
typedef struct s_mc_comm_pattern{
int num;
- smx_synchro_t comm;
+ smx_synchro_t comm_addr;
e_smx_comm_type_t type;
unsigned long src_proc;
unsigned long dst_proc;
xbt_dynar_t list;
}s_mc_list_comm_pattern_t, *mc_list_comm_pattern_t;
+/**
+ * Type: `xbt_dynar_t<mc_list_comm_pattenr_t>`
+ */
extern xbt_dynar_t initial_communications_pattern;
+
+/**
+ * Type: `xbt_dynar_t<xbt_dynar_t<mc_comm_pattern_t>>`
+ */
extern xbt_dynar_t incomplete_communications_pattern;
typedef enum {
DATA_DIFF,
} e_mc_comm_pattern_difference_t;
-static inline e_mc_call_type_t mc_get_call_type(smx_simcall_t req)
+static inline e_mc_call_type_t MC_get_call_type(smx_simcall_t req)
{
switch(req->call) {
case SIMCALL_COMM_ISEND:
}
}
-void get_comm_pattern(xbt_dynar_t communications_pattern, smx_simcall_t request, e_mc_call_type_t call_type, int backtracking);
-void handle_comm_pattern(e_mc_call_type_t call_type, smx_simcall_t request, int value, xbt_dynar_t current_pattern, int backtracking);
-void comm_pattern_free_voidp(void *p);
-void list_comm_pattern_free_voidp(void *p);
-void complete_comm_pattern(xbt_dynar_t list, smx_synchro_t comm, unsigned int issuer, int backtracking);
-void MC_pre_modelcheck_comm_determinism(void);
+void MC_get_comm_pattern(xbt_dynar_t communications_pattern, smx_simcall_t request, e_mc_call_type_t call_type, int backtracking);
+void MC_handle_comm_pattern(e_mc_call_type_t call_type, smx_simcall_t request, int value, xbt_dynar_t current_pattern, int backtracking);
+void MC_comm_pattern_free_voidp(void *p);
+void MC_list_comm_pattern_free_voidp(void *p);
+void MC_complete_comm_pattern(xbt_dynar_t list, smx_synchro_t comm_addr, unsigned int issuer, int backtracking);
void MC_modelcheck_comm_determinism(void);
+void MC_restore_communications_pattern(mc_state_t state);
+
+mc_comm_pattern_t MC_comm_pattern_dup(mc_comm_pattern_t comm);
+xbt_dynar_t MC_comm_patterns_dup(xbt_dynar_t state);
+
+void MC_state_copy_incomplete_communications_pattern(mc_state_t state);
+void MC_state_copy_index_communications_pattern(mc_state_t state);
+
+void MC_comm_pattern_free(mc_comm_pattern_t p);
+
SG_END_DECL()
#endif
#include "mc_safety.h"
#include "mc_liveness.h"
#include "mc_private.h"
+#include "mc_smx.h"
#ifdef HAVE_SMPI
#include "smpi/private.h"
static void stack_region_free(stack_region_t s)
{
if (s) {
- xbt_free(s->process_name);
xbt_free(s);
}
}
void* real_area2, mc_snapshot_t snapshot2, mc_mem_region_t region2,
dw_type_t type, int pointer_level)
{
+ mc_process_t process = &mc_model_checker->process;
+
unsigned int cursor = 0;
dw_type_t member, subtype, subsubtype;
int elm_size, i, res;
case DW_TAG_enumeration_type:
case DW_TAG_union_type:
{
- return mc_snapshot_region_memcmp(
+ return MC_snapshot_region_memcmp(
real_area1, region1, real_area2, region2,
type->byte_size) != 0;
}
case DW_TAG_reference_type:
case DW_TAG_rvalue_reference_type:
{
- void* addr_pointed1 = mc_snapshot_read_pointer_region(real_area1, region1);
- void* addr_pointed2 = mc_snapshot_read_pointer_region(real_area2, region2);
+ void* addr_pointed1 = MC_region_read_pointer(region1, real_area1);
+ void* addr_pointed2 = MC_region_read_pointer(region2, real_area2);
if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) {
return (addr_pointed1 != addr_pointed2);
// * a pointer leads to the read-only segment of the current object;
// * a pointer lead to a different ELF object.
- if (addr_pointed1 > std_heap
+ if (addr_pointed1 > process->heap_address
&& addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)) {
if (!
- (addr_pointed2 > std_heap
+ (addr_pointed2 > process->heap_address
&& addr_pointed2 < mc_snapshot_get_heap_end(snapshot2)))
return 1;
// The pointers are both in the heap:
case DW_TAG_class_type:
xbt_dynar_foreach(type->members, cursor, member) {
void *member1 =
- mc_member_resolve(real_area1, type, member, snapshot1, process_index);
+ mc_member_resolve(real_area1, type, member, (mc_address_space_t) snapshot1, process_index);
void *member2 =
- mc_member_resolve(real_area2, type, member, snapshot2, process_index);
+ mc_member_resolve(real_area2, type, member, (mc_address_space_t) snapshot2, process_index);
mc_mem_region_t subregion1 = mc_get_region_hinted(member1, snapshot1, process_index, region1);
mc_mem_region_t subregion2 = mc_get_region_hinted(member2, snapshot2, process_index, region2);
res =
mc_snapshot_t snapshot2)
{
xbt_assert(r1 && r2, "Missing region.");
+
+#ifdef HAVE_SMPI
+ if (r1->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+ xbt_assert(process_index >= 0);
+ if (r2->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+ return 1;
+ }
+
+ size_t process_count = MC_smpi_process_count();
+ xbt_assert(process_count == r1->privatized.regions_count
+ && process_count == r2->privatized.regions_count);
+
+ // Compare the global variables separately for each simulates process:
+ for (size_t process_index = 0; process_index < process_count; process_index++) {
+ int is_diff = compare_global_variables(object_info, process_index,
+ r1->privatized.regions[process_index], r2->privatized.regions[process_index],
+ snapshot1, snapshot2);
+ if (is_diff) return 1;
+ }
+ return 0;
+ }
+#else
+ xbt_assert(r1->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED);
+#endif
+ xbt_assert(r2->storage_type != MC_REGION_STORAGE_TYPE_PRIVATIZED);
+
struct mc_compare_state state;
xbt_dynar_t variables;
int snapshot_compare(void *state1, void *state2)
{
+ mc_process_t process = &mc_model_checker->process;
mc_snapshot_t s1, s2;
int num1, num2;
#endif
/* Init heap information used in heap comparison algorithm */
- xbt_mheap_t heap1 = (xbt_mheap_t) mc_snapshot_read(std_heap, s1, MC_NO_PROCESS_INDEX,
- alloca(sizeof(struct mdesc)), sizeof(struct mdesc));
- xbt_mheap_t heap2 = (xbt_mheap_t) mc_snapshot_read(std_heap, s2, MC_NO_PROCESS_INDEX,
- alloca(sizeof(struct mdesc)), sizeof(struct mdesc));
+ xbt_mheap_t heap1 = (xbt_mheap_t) MC_snapshot_read(
+ s1, MC_ADDRESS_SPACE_READ_FLAGS_LAZY,
+ alloca(sizeof(struct mdesc)), process->heap_address, sizeof(struct mdesc),
+ MC_PROCESS_INDEX_MISSING);
+ xbt_mheap_t heap2 = (xbt_mheap_t) MC_snapshot_read(
+ s2, MC_ADDRESS_SPACE_READ_FLAGS_LAZY,
+ alloca(sizeof(struct mdesc)), process->heap_address, sizeof(struct mdesc),
+ MC_PROCESS_INDEX_MISSING);
res_init = init_heap_information(heap1, heap2, s1->to_ignore, s2->to_ignore);
if (res_init == -1) {
#ifdef MC_DEBUG
cursor++;
}
+ size_t regions_count = s1->snapshot_regions_count;
+ // TODO, raise a difference instead?
+ xbt_assert(regions_count == s2->snapshot_regions_count);
+ mc_comp_times->global_variables_comparison_time = 0;
- const char *names[3] = { "?", "libsimgrid", "binary" };
-#ifdef MC_DEBUG
- double *times[3] = {
- NULL,
- &mc_comp_times->libsimgrid_global_variables_comparison_time,
- &mc_comp_times->binary_global_variables_comparison_time
- };
-#endif
+ for (size_t k = 0; k != regions_count; ++k) {
+ mc_mem_region_t region1 = s1->snapshot_regions[k];
+ mc_mem_region_t region2 = s2->snapshot_regions[k];
- mc_object_info_t object_infos[] = { NULL, mc_libsimgrid_info, mc_binary_info };
+ // Preconditions:
+ if (region1->region_type != MC_REGION_TYPE_DATA)
+ continue;
+
+ xbt_assert(region1->region_type == region2->region_type);
+ xbt_assert(region1->object_info == region2->object_info);
+
+ xbt_assert(region1->object_info);
+
+ const char* name = region1->object_info->file_name;
- int k = 0;
- for (k = 2; k != 0; --k) {
#ifdef MC_DEBUG
if (is_diff == 0)
xbt_os_walltimer_stop(timer);
#endif
/* Compare global variables */
-#ifdef HAVE_SMPI
- if (object_infos[k] == mc_binary_info && smpi_privatize_global_variables) {
- // Compare the global variables separately for each simulates process:
- for (int process_index = 0; process_index < smpi_process_count(); process_index++) {
- is_diff =
- compare_global_variables(object_infos[k], process_index,
- s1->privatization_regions[process_index], s2->privatization_regions[process_index], s1, s2);
- if (is_diff) break;
- }
- }
- else
-#endif
- is_diff =
- compare_global_variables(object_infos[k], MC_NO_PROCESS_INDEX, s1->regions[k], s2->regions[k], s1, s2);
+ is_diff =
+ compare_global_variables(region1->object_info, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ region1, region2,
+ s1, s2);
if (is_diff != 0) {
XBT_TRACE3(mc, state_diff, num1, num2, "Different global variables");
#ifdef MC_DEBUG
xbt_os_walltimer_stop(timer);
- *times[k] = xbt_os_timer_elapsed(timer);
+ mc_comp_times->global_variables_comparison_time
+ += xbt_os_timer_elapsed(timer);
XBT_DEBUG("(%d - %d) Different global variables in %s", num1, num2,
- names[k]);
+ name);
errors++;
#else
#ifdef MC_VERBOSE
XBT_VERB("(%d - %d) Different global variables in %s", num1, num2,
- names[k]);
+ name);
#endif
reset_heap_information();
XBT_DEBUG("- Nb processes : %f", mc_comp_times->nb_processes_comparison_time);
XBT_DEBUG("- Nb bytes used : %f", mc_comp_times->bytes_used_comparison_time);
XBT_DEBUG("- Stacks sizes : %f", mc_comp_times->stacks_sizes_comparison_time);
- XBT_DEBUG("- Binary global variables : %f",
- mc_comp_times->binary_global_variables_comparison_time);
- XBT_DEBUG("- Libsimgrid global variables : %f",
- mc_comp_times->libsimgrid_global_variables_comparison_time);
+ XBT_DEBUG("- GLobal variables : %f", mc_comp_times->global_variables_comparison_time);
XBT_DEBUG("- Heap : %f", mc_comp_times->heap_comparison_time);
XBT_DEBUG("- Stacks : %f", mc_comp_times->stacks_comparison_time);
}
-/**************************** MC snapshot compare simcall **************************/
-/***********************************************************************************/
-
-int simcall_HANDLER_mc_compare_snapshots(smx_simcall_t simcall,
- mc_snapshot_t s1, mc_snapshot_t s2)
-{
- return snapshot_compare(s1, s2);
-}
-
-int MC_compare_snapshots(void *s1, void *s2)
-{
-
- return simcall_mc_compare_snapshots(s1, s2);
-
-}
-
}
int _sg_mc_send_determinism = 0;
int _sg_mc_safety = 0;
int _sg_mc_liveness = 0;
+int _sg_mc_snapshot_fds = 0;
int _sg_mc_termination = 0;
-
void _mc_cfg_cb_reduce(const char *name, int pos)
{
if (_sg_cfg_init_status && !_sg_do_model_check) {
_sg_mc_hash = xbt_cfg_get_boolean(_sg_cfg_set, name);
}
+void _mc_cfg_cb_snapshot_fds(const char *name, int pos)
+{
+ if (_sg_cfg_init_status && !_sg_do_model_check) {
+ xbt_die
+ ("You are specifying a value to enable/disable the use of FD snapshoting, but model-checking was not activated at config time (through --cfg=model-check:1). This won't work, sorry.");
+ }
+ _sg_mc_snapshot_fds = xbt_cfg_get_boolean(_sg_cfg_set, name);
+}
+
void _mc_cfg_cb_max_depth(const char *name, int pos)
{
if (_sg_cfg_init_status && !_sg_do_model_check) {
xbt_dynar_t mc_heap_comparison_ignore;
xbt_dynar_t stacks_areas;
-void *maestro_stack_start, *maestro_stack_end;
+
/********************************* Backtrace ***********************************/
typedef char *type_name;
struct s_mc_diff {
- /** \brief Base address of the real heap */
- void *s_heap;
+ s_xbt_mheap_t std_heap_copy;
size_t heaplimit;
// Number of blocks in the heaps:
size_t heapsize1, heapsize2;
}
static ssize_t heap_comparison_ignore_size(xbt_dynar_t ignore_list,
- void *address)
+ const void *address)
{
unsigned int cursor = 0;
return -1;
}
-static int is_stack(void *address)
+static int is_stack(const void *address)
{
unsigned int cursor = 0;
stack_region_t stack;
return -1;
state->heaplimit = ((struct mdesc *) heap1)->heaplimit;
-
- // Mamailloute in order to find the base address of the main heap:
- state->s_heap =
- (char *) mmalloc_get_current_heap() - STD_HEAP_SIZE - xbt_pagesize;
+
+ state->std_heap_copy = *MC_process_get_heap(&mc_model_checker->process);
state->heapsize1 = heap1->heapsize;
state->heapsize2 = heap2->heapsize;
}
-int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2)
+// TODO, have a robust way to find it in O(1)
+static inline
+mc_mem_region_t MC_get_heap_region(mc_snapshot_t snapshot)
{
+ size_t n = snapshot->snapshot_regions_count;
+ for (size_t i=0; i!=n; ++i) {
+ mc_mem_region_t region = snapshot->snapshot_regions[i];
+ if (region->region_type == MC_REGION_TYPE_HEAP)
+ return region;
+ }
+ xbt_die("No heap region");
+}
+int mmalloc_compare_heap(mc_snapshot_t snapshot1, mc_snapshot_t snapshot2)
+{
+ mc_process_t process = &mc_model_checker->process;
struct s_mc_diff *state = mc_diff_info;
/* Start comparison */
malloc_info heapinfo_temp1, heapinfo_temp2;
malloc_info heapinfo_temp2b;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
+
+ // This is the address of std_heap->heapinfo in the application process:
+ void* heapinfo_address = &((xbt_mheap_t) process->heap_address)->heapinfo;
// This is in snapshot do not use them directly:
- malloc_info* heapinfos1 = mc_snapshot_read_pointer(&std_heap->heapinfo, snapshot1, MC_NO_PROCESS_INDEX);
- malloc_info* heapinfos2 = mc_snapshot_read_pointer(&std_heap->heapinfo, snapshot2, MC_NO_PROCESS_INDEX);
+ const malloc_info* heapinfos1 = MC_snapshot_read_pointer(snapshot1, heapinfo_address, MC_PROCESS_INDEX_MISSING);
+ const malloc_info* heapinfos2 = MC_snapshot_read_pointer(snapshot2, heapinfo_address, MC_PROCESS_INDEX_MISSING);
while (i1 <= state->heaplimit) {
- malloc_info* heapinfo1 = mc_snapshot_read_region(&heapinfos1[i1], heap_region1, &heapinfo_temp1, sizeof(malloc_info));
- malloc_info* heapinfo2 = mc_snapshot_read_region(&heapinfos2[i1], heap_region2, &heapinfo_temp2, sizeof(malloc_info));
+ const malloc_info* heapinfo1 = MC_region_read(heap_region1, &heapinfo_temp1, &heapinfos1[i1], sizeof(malloc_info));
+ const malloc_info* heapinfo2 = MC_region_read(heap_region2, &heapinfo_temp2, &heapinfos2[i1], sizeof(malloc_info));
if (heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type == MMALLOC_TYPE_HEAPINFO) { /* Free block */
i1 ++;
addr_block1 =
((void *) (((ADDR2UINT(i1)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ (char *) state->std_heap_copy.heapbase));
if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) { /* Large block */
if (state->equals_to2_(i1, 0).valid == 0) {
- addr_block2 =
- ((void *) (((ADDR2UINT(i1)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
res_compare =
- compare_heap_area(MC_NO_PROCESS_INDEX, addr_block1, addr_block2, snapshot1, snapshot2,
+ compare_heap_area(MC_PROCESS_INDEX_MISSING, addr_block1, addr_block2, snapshot1, snapshot2,
NULL, NULL, 0);
if (res_compare != 1) {
while (i2 <= state->heaplimit && !equal) {
- addr_block2 =
- ((void *) (((ADDR2UINT(i2)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
if (i2 == i1) {
i2++;
continue;
}
- malloc_info* heapinfo2b = mc_snapshot_read_region(&heapinfos2[i2], heap_region2, &heapinfo_temp2b, sizeof(malloc_info));
+ const malloc_info* heapinfo2b = MC_region_read(heap_region2, &heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info));
if (heapinfo2b->type != MMALLOC_TYPE_UNFRAGMENTED) {
i2++;
}
res_compare =
- compare_heap_area(MC_NO_PROCESS_INDEX, addr_block1, addr_block2, snapshot1, snapshot2,
+ compare_heap_area(MC_PROCESS_INDEX_MISSING, addr_block1, addr_block2, snapshot1, snapshot2,
NULL, NULL, 0);
if (res_compare != 1) {
if (state->equals_to2_(i1, j1).valid == 0) {
- addr_block2 =
- ((void *) (((ADDR2UINT(i1)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ addr_block2 = (ADDR2UINT(i1) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
addr_frag2 =
(void *) ((char *) addr_block2 +
(j1 << heapinfo2->type));
res_compare =
- compare_heap_area(MC_NO_PROCESS_INDEX, addr_frag1, addr_frag2, snapshot1, snapshot2,
+ compare_heap_area(MC_PROCESS_INDEX_MISSING, addr_frag1, addr_frag2, snapshot1, snapshot2,
NULL, NULL, 0);
if (res_compare != 1)
while (i2 <= state->heaplimit && !equal) {
- malloc_info* heapinfo2b = mc_snapshot_read_region(&heapinfos2[i2], heap_region2, &heapinfo_temp2b, sizeof(malloc_info));
+ const malloc_info* heapinfo2b = MC_region_read(heap_region2, &heapinfo_temp2b, &heapinfos2[i2], sizeof(malloc_info));
if (heapinfo2b->type == MMALLOC_TYPE_FREE || heapinfo2b->type == MMALLOC_TYPE_HEAPINFO) {
i2 ++;
if (state->equals_to2_(i2, j2).valid)
continue;
- addr_block2 =
- ((void *) (((ADDR2UINT(i2)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ addr_block2 = (ADDR2UINT(i2) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
addr_frag2 =
(void *) ((char *) addr_block2 +
(j2 << heapinfo2b->type));
res_compare =
- compare_heap_area(MC_NO_PROCESS_INDEX, addr_frag1, addr_frag2, snapshot2, snapshot2,
+ compare_heap_area(MC_PROCESS_INDEX_MISSING, addr_frag1, addr_frag2, snapshot2, snapshot2,
NULL, NULL, 0);
if (res_compare != 1) {
size_t i = 1, j = 0;
for(i = 1; i <= state->heaplimit; i++) {
- malloc_info* heapinfo1 = mc_snapshot_read_region(&heapinfos1[i], heap_region1, &heapinfo_temp1, sizeof(malloc_info));
+ const malloc_info* heapinfo1 = MC_region_read(heap_region1, &heapinfo_temp1, &heapinfos1[i], sizeof(malloc_info));
if (heapinfo1->type == MMALLOC_TYPE_UNFRAGMENTED) {
if (i1 == state->heaplimit) {
if (heapinfo1->busy_block.busy_size > 0) {
XBT_DEBUG("Number of blocks/fragments not found in heap1 : %d", nb_diff1);
for (i=1; i <= state->heaplimit; i++) {
- malloc_info* heapinfo2 = mc_snapshot_read_region(&heapinfos2[i], heap_region2, &heapinfo_temp2, sizeof(malloc_info));
+ const malloc_info* heapinfo2 = MC_region_read(heap_region2, &heapinfo_temp2, &heapinfos2[i], sizeof(malloc_info));
if (heapinfo2->type == MMALLOC_TYPE_UNFRAGMENTED) {
if (i1 == state->heaplimit) {
if (heapinfo2->busy_block.busy_size > 0) {
* @param check_ignore
*/
static int compare_heap_area_without_type(struct s_mc_diff *state, int process_index,
- void *real_area1, void *real_area2,
+ const void *real_area1, const void *real_area2,
mc_snapshot_t snapshot1,
mc_snapshot_t snapshot2,
xbt_dynar_t previous, int size,
int check_ignore)
{
+ mc_process_t process = &mc_model_checker->process;
int i = 0;
- void *addr_pointed1, *addr_pointed2;
+ const void *addr_pointed1, *addr_pointed2;
int pointer_align, res_compare;
ssize_t ignore1, ignore2;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
while (i < size) {
}
}
- if (mc_snapshot_region_memcmp(((char *) real_area1) + i, heap_region1, ((char *) real_area2) + i, heap_region2, 1) != 0) {
+ if (MC_snapshot_region_memcmp(((char *) real_area1) + i, heap_region1, ((char *) real_area2) + i, heap_region2, 1) != 0) {
pointer_align = (i / sizeof(void *)) * sizeof(void *);
- addr_pointed1 = mc_snapshot_read_pointer((char *) real_area1 + pointer_align, snapshot1, process_index);
- addr_pointed2 = mc_snapshot_read_pointer((char *) real_area2 + pointer_align, snapshot2, process_index);
+ addr_pointed1 = MC_snapshot_read_pointer(snapshot1, (char *) real_area1 + pointer_align, process_index);
+ addr_pointed2 = MC_snapshot_read_pointer(snapshot2, (char *) real_area2 + pointer_align, process_index);
- if (addr_pointed1 > maestro_stack_start
- && addr_pointed1 < maestro_stack_end
- && addr_pointed2 > maestro_stack_start
- && addr_pointed2 < maestro_stack_end) {
+ if (addr_pointed1 > process->maestro_stack_start
+ && addr_pointed1 < process->maestro_stack_end
+ && addr_pointed2 > process->maestro_stack_start
+ && addr_pointed2 < process->maestro_stack_end) {
i = pointer_align + sizeof(void *);
continue;
- } else if (addr_pointed1 > state->s_heap
+ } else if (addr_pointed1 > state->std_heap_copy.heapbase
&& addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
- && addr_pointed2 > state->s_heap
+ && addr_pointed2 > state->std_heap_copy.heapbase
&& addr_pointed2 < mc_snapshot_get_heap_end(snapshot2)) {
// Both addreses are in the heap:
res_compare =
* @return 0 (same), 1 (different), -1 (unknown)
*/
static int compare_heap_area_with_type(struct s_mc_diff *state, int process_index,
- void *real_area1, void *real_area2,
+ const void *real_area1, const void *real_area2,
mc_snapshot_t snapshot1,
mc_snapshot_t snapshot2,
xbt_dynar_t previous, dw_type_t type,
int res, elm_size, i;
unsigned int cursor = 0;
dw_type_t member;
- void *addr_pointed1, *addr_pointed2;;
+ const void *addr_pointed1, *addr_pointed2;;
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
switch (type->type) {
case DW_TAG_unspecified_type:
if (real_area1 == real_area2)
return -1;
else
- return (mc_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, area_size) != 0);
+ return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, area_size) != 0);
} else {
if (area_size != -1 && type->byte_size != area_size)
return -1;
else {
- return (mc_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
+ return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
}
}
break;
if (area_size != -1 && type->byte_size != area_size)
return -1;
else
- return (mc_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
+ return (MC_snapshot_region_memcmp(real_area1, heap_region1, real_area2, heap_region2, type->byte_size) != 0);
break;
case DW_TAG_typedef:
case DW_TAG_const_type:
case DW_TAG_rvalue_reference_type:
case DW_TAG_pointer_type:
if (type->subtype && type->subtype->type == DW_TAG_subroutine_type) {
- addr_pointed1 = mc_snapshot_read_pointer(real_area1, snapshot1, process_index);
- addr_pointed2 = mc_snapshot_read_pointer(real_area2, snapshot2, process_index);
+ addr_pointed1 = MC_snapshot_read_pointer(snapshot1, real_area1, process_index);
+ addr_pointed2 = MC_snapshot_read_pointer(snapshot2, real_area2, process_index);
return (addr_pointed1 != addr_pointed2);;
} else {
pointer_level++;
if (pointer_level > 1) { /* Array of pointers */
for (i = 0; i < (area_size / sizeof(void *)); i++) {
- addr_pointed1 = mc_snapshot_read_pointer((char*) real_area1 + i * sizeof(void *), snapshot1, process_index);
- addr_pointed2 = mc_snapshot_read_pointer((char*) real_area2 + i * sizeof(void *), snapshot2, process_index);
- if (addr_pointed1 > state->s_heap
+ addr_pointed1 = MC_snapshot_read_pointer(snapshot1, (char*) real_area1 + i * sizeof(void *), process_index);
+ addr_pointed2 = MC_snapshot_read_pointer(snapshot2, (char*) real_area2 + i * sizeof(void *), process_index);
+ if (addr_pointed1 > state->std_heap_copy.heapbase
&& addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
- && addr_pointed2 > state->s_heap
+ && addr_pointed2 > state->std_heap_copy.heapbase
&& addr_pointed2 < mc_snapshot_get_heap_end(snapshot2))
res =
compare_heap_area(process_index, addr_pointed1, addr_pointed2, snapshot1,
return res;
}
} else {
- addr_pointed1 = mc_snapshot_read_pointer(real_area1, snapshot1, process_index);
- addr_pointed2 = mc_snapshot_read_pointer(real_area2, snapshot2, process_index);
- if (addr_pointed1 > state->s_heap
+ addr_pointed1 = MC_snapshot_read_pointer(snapshot1, real_area1, process_index);
+ addr_pointed2 = MC_snapshot_read_pointer(snapshot2, real_area2, process_index);
+ if (addr_pointed1 > state->std_heap_copy.heapbase
&& addr_pointed1 < mc_snapshot_get_heap_end(snapshot1)
- && addr_pointed2 > state->s_heap
+ && addr_pointed2 > state->std_heap_copy.heapbase
&& addr_pointed2 < mc_snapshot_get_heap_end(snapshot2))
return compare_heap_area(process_index, addr_pointed1, addr_pointed2, snapshot1,
snapshot2, previous, type->subtype,
xbt_dynar_foreach(type->members, cursor, member) {
// TODO, optimize this? (for the offset case)
char *real_member1 =
- mc_member_resolve(real_area1, type, member, snapshot1, process_index);
+ mc_member_resolve(real_area1, type, member, (mc_address_space_t) snapshot1, process_index);
char *real_member2 =
- mc_member_resolve(real_area2, type, member, snapshot2, process_index);
+ mc_member_resolve(real_area2, type, member, (mc_address_space_t) snapshot2, process_index);
res =
compare_heap_area_with_type(state, process_index, real_member1, real_member2,
snapshot1, snapshot2,
return member->subtype;
} else {
char *real_member =
- mc_member_resolve(real_base_address, type, member, snapshot, process_index);
+ mc_member_resolve(real_base_address, type, member, (mc_address_space_t) snapshot, process_index);
if (real_member - (char *) real_base_address == offset)
return member->subtype;
}
* @param pointer_level
* @return 0 (same), 1 (different), -1
*/
-int compare_heap_area(int process_index, void *area1, void *area2, mc_snapshot_t snapshot1,
+int compare_heap_area(int process_index, const void *area1, const void *area2, mc_snapshot_t snapshot1,
mc_snapshot_t snapshot2, xbt_dynar_t previous,
dw_type_t type, int pointer_level)
{
+ mc_process_t process = &mc_model_checker->process;
struct s_mc_diff *state = mc_diff_info;
int match_pairs = 0;
- malloc_info* heapinfos1 = mc_snapshot_read_pointer(&std_heap->heapinfo, snapshot1, process_index);
- malloc_info* heapinfos2 = mc_snapshot_read_pointer(&std_heap->heapinfo, snapshot2, process_index);
+ // This is the address of std_heap->heapinfo in the application process:
+ void* heapinfo_address = &((xbt_mheap_t) process->heap_address)->heapinfo;
+
+ const malloc_info* heapinfos1 = MC_snapshot_read_pointer(snapshot1, heapinfo_address, process_index);
+ const malloc_info* heapinfos2 = MC_snapshot_read_pointer(snapshot2, heapinfo_address, process_index);
malloc_info heapinfo_temp1, heapinfo_temp2;
// Get block number:
block1 =
((char *) area1 -
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase) / BLOCKSIZE + 1;
+ (char *) state->std_heap_copy.heapbase) / BLOCKSIZE + 1;
block2 =
((char *) area2 -
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase) / BLOCKSIZE + 1;
+ (char *) state->std_heap_copy.heapbase) / BLOCKSIZE + 1;
// If either block is a stack block:
if (is_block_stack((int) block1) && is_block_stack((int) block2)) {
return 0;
}
// If either block is not in the expected area of memory:
- if (((char *) area1 < (char *) ((xbt_mheap_t) state->s_heap)->heapbase)
+ if (((char *) area1 < (char *) state->std_heap_copy.heapbase)
|| (block1 > state->heapsize1) || (block1 < 1)
- || ((char *) area2 < (char *) ((xbt_mheap_t) state->s_heap)->heapbase)
+ || ((char *) area2 < (char *) state->std_heap_copy.heapbase)
|| (block2 > state->heapsize2) || (block2 < 1)) {
if (match_pairs) {
xbt_dynar_free(&previous);
}
// Process address of the block:
- real_addr_block1 =
- ((void *) (((ADDR2UINT(block1)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
- real_addr_block2 =
- ((void *) (((ADDR2UINT(block2)) - 1) * BLOCKSIZE +
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase));
+ real_addr_block1 = (ADDR2UINT(block1) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
+ real_addr_block2 = (ADDR2UINT(block2) - 1) * BLOCKSIZE +
+ (char *) state->std_heap_copy.heapbase;
if (type) {
}
- mc_mem_region_t heap_region1 = snapshot1->regions[0];
- mc_mem_region_t heap_region2 = snapshot2->regions[0];
+ mc_mem_region_t heap_region1 = MC_get_heap_region(snapshot1);
+ mc_mem_region_t heap_region2 = MC_get_heap_region(snapshot2);
- malloc_info* heapinfo1 = mc_snapshot_read_region(&heapinfos1[block1], heap_region1, &heapinfo_temp1, sizeof(malloc_info));
- malloc_info* heapinfo2 = mc_snapshot_read_region(&heapinfos2[block2], heap_region2, &heapinfo_temp2, sizeof(malloc_info));
+ const malloc_info* heapinfo1 = MC_region_read(heap_region1, &heapinfo_temp1, &heapinfos1[block1], sizeof(malloc_info));
+ const malloc_info* heapinfo2 = MC_region_read(heap_region2, &heapinfo_temp2, &heapinfos2[block2], sizeof(malloc_info));
if ((heapinfo1->type == MMALLOC_TYPE_FREE || heapinfo1->type==MMALLOC_TYPE_HEAPINFO)
&& (heapinfo2->type == MMALLOC_TYPE_FREE || heapinfo2->type ==MMALLOC_TYPE_HEAPINFO)) {
block =
((char *) area -
- (char *) ((xbt_mheap_t) state->s_heap)->heapbase) / BLOCKSIZE + 1;
+ (char *) state->std_heap_copy.heapbase) / BLOCKSIZE + 1;
- if (((char *) area < (char *) ((xbt_mheap_t) state->s_heap)->heapbase)
+ if (((char *) area < (char *) state->std_heap_copy.heapbase)
|| (block > state->heapsize1) || (block < 1))
return -1;
/* Heap information */
state->heaplimit = ((struct mdesc *) heap1)->heaplimit;
-
- // Mamailloute in order to find the base address of the main heap:
- state->s_heap =
- (char *) mmalloc_get_current_heap() - STD_HEAP_SIZE - xbt_pagesize;
+ state->std_heap_copy = *MC_process_get_heap(&mc_model_checker->process);
state->heapbase1 = (char *) heap1 + BLOCKSIZE;
state->heapbase2 = (char *) heap2 + BLOCKSIZE;
}
Dwarf *dwarf = dwarf_begin(fd, DWARF_C_READ);
if (dwarf == NULL) {
- xbt_die("Your program must be compiled with -g");
+ xbt_die("Your program must be compiled with -g (%s)", info->file_name);
}
// For each compilation unit:
Dwarf_Off offset = 0;
info->functions_index = index;
}
-mc_object_info_t MC_ip_find_object_info(void *ip)
-{
- size_t i;
- for (i = 0; i != mc_object_infos_size; ++i) {
- if (ip >= (void *) mc_object_infos[i]->start_exec
- && ip <= (void *) mc_object_infos[i]->end_exec) {
- return mc_object_infos[i];
- }
- }
- return NULL;
-}
-
-static dw_frame_t MC_find_function_by_ip_and_object(void *ip,
- mc_object_info_t info)
-{
- xbt_dynar_t dynar = info->functions_index;
- mc_function_index_item_t base =
- (mc_function_index_item_t) xbt_dynar_get_ptr(dynar, 0);
- int i = 0;
- int j = xbt_dynar_length(dynar) - 1;
- while (j >= i) {
- int k = i + ((j - i) / 2);
- if (ip < base[k].low_pc) {
- j = k - 1;
- } else if (ip >= base[k].high_pc) {
- i = k + 1;
- } else {
- return base[k].function;
- }
- }
- return NULL;
-}
-
-dw_frame_t MC_find_function_by_ip(void *ip)
-{
- mc_object_info_t info = MC_ip_find_object_info(ip);
- if (info == NULL)
- return NULL;
- else
- return MC_find_function_by_ip_and_object(ip, info);
-}
-
static void MC_post_process_variables(mc_object_info_t info)
{
unsigned cursor = 0;
}
/** \brief Finds informations about a given shared object/executable */
-mc_object_info_t MC_find_object_info(memory_map_t maps, char *name,
+mc_object_info_t MC_find_object_info(memory_map_t maps, const char *name,
int executable)
{
mc_object_info_t result = MC_new_object_info();
MC_dwarf_register_non_global_variable(info, frame, variable);
}
-void MC_post_process_object_info(mc_object_info_t info)
+void MC_post_process_object_info(mc_process_t process, mc_object_info_t info)
{
xbt_dict_cursor_t cursor = NULL;
char *key = NULL;
dw_type_t type = NULL;
xbt_dict_foreach(info->types, cursor, key, type) {
+ dw_type_t subtype = type;
+ while (subtype->type == DW_TAG_typedef || subtype->type == DW_TAG_volatile_type
+ || subtype->type == DW_TAG_const_type) {
+ if (subtype->subtype)
+ subtype = subtype->subtype;
+ else
+ break;
+ }
+
// Resolve full_type:
- if (type->name && type->byte_size == 0) {
- for (size_t i = 0; i != mc_object_infos_size; ++i) {
+ if (subtype->name && subtype->byte_size == 0) {
+ for (size_t i = 0; i != process->object_infos_size; ++i) {
dw_type_t same_type =
- xbt_dict_get_or_null(mc_object_infos[i]->full_types_by_name,
- type->name);
+ xbt_dict_get_or_null(process->object_infos[i]->full_types_by_name,
+ subtype->name);
if (same_type && same_type->name && same_type->byte_size) {
type->full_type = same_type;
break;
}
}
- }
+ } else type->full_type = subtype;
}
}
#include <elfutils/libdw.h>
#include "mc_object_info.h"
-#include "mc_snapshot.h"
#include "mc_private.h"
static int mc_dwarf_push_value(mc_expression_state_t state, Dwarf_Off value)
return 0;
}
+/** Convert a DWARF register into a libunwind register
+ *
+ * DWARF and libunwind does not use the same convention for numbering the
+ * registers on some architectures. The function makes the necessary
+ * convertion.
+ */
static int mc_dwarf_register_to_libunwind(int dwarf_register)
{
#if defined(UNW_TARGET_X86_64)
xbt_die("Bad/unknown register number.");
}
#else
-#error This architecture is not supported yet.
+#error This architecture is not supported yet for DWARF expression evaluation.
#endif
}
{
if (!state->frame_base)
return MC_EXPRESSION_E_MISSING_FRAME_BASE;
- error =
- mc_dwarf_push_value(state,
- ((uintptr_t) state->frame_base) + op->number);
+ uintptr_t fb = ((uintptr_t) state->frame_base) + op->number;
+ error = mc_dwarf_push_value(state, fb);
break;
}
- // Constants:
+ // ***** Constants:
+ // Short constant literals:
+ // DW_OP_lit15 pushed the 15 on the stack.
case DW_OP_lit0:
case DW_OP_lit1:
case DW_OP_lit2:
error = mc_dwarf_push_value(state, atom - DW_OP_lit0);
break;
+ // Address from the base address of this ELF object.
+ // Push the address on the stack (base_address + argument).
case DW_OP_addr:
if (!state->object_info)
return MC_EXPRESSION_E_NO_BASE_ADDRESS;
if (state->stack_size == MC_EXPRESSION_STACK_SIZE)
return MC_EXPRESSION_E_STACK_OVERFLOW;
- error = mc_dwarf_push_value(state,
- (Dwarf_Off) (uintptr_t)
- MC_object_base_address(state->object_info) +
- op->number);
+ Dwarf_Off addr = (Dwarf_Off) (uintptr_t)
+ MC_object_base_address(state->object_info) + op->number;
+ error = mc_dwarf_push_value(state, addr);
break;
+ // General constants:
+ // Push the constant argument on the stack.
case DW_OP_const1u:
case DW_OP_const2u:
case DW_OP_const4u:
error = mc_dwarf_push_value(state, op->number);
break;
- // Stack manipulation:
+ // ***** Stack manipulation:
- // Push the value at the top of the stack:
+ // Push another copy/duplicate the value at the top of the stack:
case DW_OP_dup:
if (state->stack_size == 0)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
error = mc_dwarf_push_value(state, state->stack[state->stack_size - 1]);
break;
+ // Pop/drop the top of the stack:
case DW_OP_drop:
if (state->stack_size == 0)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
state->stack_size--;
break;
+ // Swap the two top-most value of the stack:
case DW_OP_swap:
if (state->stack_size < 2)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
}
break;
+ // Duplicate the value under the top of the stack:
case DW_OP_over:
if (state->stack_size < 2)
return MC_EXPRESSION_E_STACK_UNDERFLOW;
error = mc_dwarf_push_value(state, state->stack[state->stack_size - 2]);
break;
- // Operations:
+ // ***** Operations:
+ // Those usually take the top of the stack and the next value as argument
+ // and replace the top of the stack with the computed value
+ // (stack.top() += stack.before_top()).
case DW_OP_plus:
if (state->stack_size < 2)
case DW_OP_nop:
break;
- // Dereference:
+ // ***** Deference (memory fetch)
+
case DW_OP_deref_size:
return MC_EXPRESSION_E_UNSUPPORTED_OPERATION;
{
// Computed address:
uintptr_t address = (uintptr_t) state->stack[state->stack_size - 1];
- uintptr_t temp;
- uintptr_t* res = (uintptr_t*) mc_snapshot_read((void*) address, state->snapshot, state->process_index, &temp, sizeof(uintptr_t));
- state->stack[state->stack_size - 1] = *res;
+ if (!state->address_space)
+ xbt_die("Missing address space");
+ MC_address_space_read(
+ state->address_space, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ &state->stack[state->stack_size - 1], (const void*) address,
+ sizeof(uintptr_t), state->process_index);
}
break;
mc_object_info_t object_info,
unw_cursor_t * c,
void *frame_pointer_address,
- mc_snapshot_t snapshot, int process_index)
+ mc_address_space_t address_space, int process_index)
{
s_mc_expression_state_t state;
memset(&state, 0, sizeof(s_mc_expression_state_t));
state.frame_base = frame_pointer_address;
state.cursor = c;
- state.snapshot = snapshot;
+ state.address_space = address_space;
state.object_info = object_info;
state.process_index = process_index;
mc_object_info_t object_info,
unw_cursor_t * c,
void *frame_pointer_address,
- mc_snapshot_t snapshot, int process_index)
+ mc_address_space_t address_space, int process_index)
{
unw_word_t ip = 0;
if (expression) {
mc_dwarf_resolve_location(location,
expression, object_info, c,
- frame_pointer_address, snapshot, process_index);
+ frame_pointer_address, address_space, process_index);
} else {
xbt_die("Could not resolve location");
}
typedef struct s_memory_map s_memory_map_t, *memory_map_t;
typedef struct s_dw_variable s_dw_variable_t, *dw_variable_t;
typedef struct s_dw_frame s_dw_frame_t, *dw_frame_t;
+
typedef struct s_mc_pages_store s_mc_pages_store_t, *mc_pages_store_t;
+typedef struct s_mc_snapshot s_mc_snapshot_t, *mc_snapshot_t;
+
+typedef struct s_mc_process s_mc_process_t, * mc_process_t;
typedef struct s_mc_model_checker s_mc_model_checker_t, *mc_model_checker_t;
extern mc_model_checker_t mc_model_checker;
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <assert.h>
+#include <string.h>
+#include <stdint.h>
+
#include "mc_base.h"
#ifndef _XBT_WIN32
#include <unistd.h>
-#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
-#include <sys/mman.h>
-#include <libgen.h>
#endif
#include "simgrid/sg_config.h"
#include "xbt/fifo.h"
#include "xbt/automaton.h"
#include "xbt/dict.h"
+#include "mc_record.h"
#ifdef HAVE_MC
-#define UNW_LOCAL_ONLY
+#include "mc_server.h"
#include <libunwind.h>
-
+#include <xbt/mmalloc.h>
#include "../xbt/mmalloc/mmprivate.h"
#include "mc_object_info.h"
#include "mc_comm_pattern.h"
#include "mc_snapshot.h"
#include "mc_liveness.h"
#include "mc_private.h"
+#include "mc_unw.h"
+#include "mc_smx.h"
#endif
#include "mc_record.h"
+#include "mc_protocol.h"
+#include "mc_client.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_global, mc,
"Logging specific to MC (global)");
+e_mc_mode_t mc_mode;
+
double *mc_time = NULL;
#ifdef HAVE_MC
/* Liveness */
xbt_automaton_t _mc_property_automaton = NULL;
-/* Variables */
-mc_object_info_t mc_libsimgrid_info = NULL;
-mc_object_info_t mc_binary_info = NULL;
-
-mc_object_info_t mc_object_infos[2] = { NULL, NULL };
-
-size_t mc_object_infos_size = 2;
-
/* Dot output */
FILE *dot_output = NULL;
const char *colors[13];
}
-static void MC_init_debug_info(void)
+void MC_init()
{
- XBT_INFO("Get debug information ...");
-
- memory_map_t maps = MC_get_memory_map();
-
- /* Get local variables for state equality detection */
- mc_binary_info = MC_find_object_info(maps, xbt_binary_name, 1);
- mc_object_infos[0] = mc_binary_info;
-
- mc_libsimgrid_info = MC_find_object_info(maps, libsimgrid_path, 0);
- mc_object_infos[1] = mc_libsimgrid_info;
-
- // Use information of the other objects:
- MC_post_process_object_info(mc_binary_info);
- MC_post_process_object_info(mc_libsimgrid_info);
-
- MC_free_memory_map(maps);
- XBT_INFO("Get debug information done !");
+ MC_init_pid(getpid(), -1);
}
-
-mc_model_checker_t mc_model_checker = NULL;
-
-mc_model_checker_t MC_model_checker_new()
+static void MC_init_mode(void)
{
- mc_model_checker_t mc = xbt_new0(s_mc_model_checker_t, 1);
- mc->pages = mc_pages_store_new();
- mc->fd_clear_refs = -1;
- mc->fd_pagemap = -1;
- return mc;
-}
-
-void MC_model_checker_delete(mc_model_checker_t mc) {
- mc_pages_store_delete(mc->pages);
- if(mc->record)
- xbt_dynar_free(&mc->record);
+ if (mc_mode == MC_MODE_NONE) {
+ if (getenv(MC_ENV_SOCKET_FD)) {
+ mc_mode = MC_MODE_CLIENT;
+ } else {
+ mc_mode = MC_MODE_STANDALONE;
+ }
+ }
}
-void MC_init()
+void MC_init_pid(pid_t pid, int socket)
{
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- mc_time = xbt_new0(double, simix_process_maxpid);
-
/* Initialize the data structures that must be persistent across every
iteration of the model-checker (in RAW memory) */
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ mc_model_checker = MC_model_checker_new(pid, socket);
- mc_model_checker = MC_model_checker_new();
+ // It's not useful anymore:
+ if (0 && mc_mode == MC_MODE_SERVER) {
+ unsigned long maxpid;
+ MC_process_read_variable(&mc_model_checker->process, "simix_process_maxpid",
+ &maxpid, sizeof(maxpid));
+ simix_process_maxpid = maxpid;
+ }
+
+ mmalloc_set_current_heap(std_heap);
+ mc_time = xbt_new0(double, MC_smx_get_maxpid());
+ mmalloc_set_current_heap(mc_heap);
mc_comp_times = xbt_new0(s_mc_comparison_times_t, 1);
mc_stats = xbt_new0(s_mc_stats_t, 1);
mc_stats->state_size = 1;
- MC_init_memory_map_info();
- MC_init_debug_info(); /* FIXME : get debug information only if liveness verification or visited state reduction */
-
if ((_sg_mc_dot_output_file != NULL) && (_sg_mc_dot_output_file[0] != '\0'))
MC_init_dot_output();
MC_SET_STD_HEAP;
- if (_sg_mc_visited > 0 || _sg_mc_liveness || _sg_mc_termination) {
+ if (_sg_mc_visited > 0 || _sg_mc_liveness || _sg_mc_termination || mc_mode == MC_MODE_SERVER) {
/* Ignore some variables from xbt/ex.h used by exception e for stacks comparison */
MC_ignore_local_variable("e", "*");
MC_ignore_local_variable("__ex_cleanup", "*");
/* SIMIX */
MC_ignore_global_variable("smx_total_comms");
- MC_ignore_heap(mc_time, simix_process_maxpid * sizeof(double));
+ if (mc_mode == MC_MODE_STANDALONE || mc_mode == MC_MODE_CLIENT) {
+ /* Those requests are handled on the client side and propagated by message
+ * to the server: */
- smx_process_t process;
- xbt_swag_foreach(process, simix_global->process_list) {
- MC_ignore_heap(&(process->process_hookup), sizeof(process->process_hookup));
+ MC_ignore_heap(mc_time, MC_smx_get_maxpid() * sizeof(double));
+
+ smx_process_t process;
+ xbt_swag_foreach(process, simix_global->process_list) {
+ MC_ignore_heap(&(process->process_hookup), sizeof(process->process_hookup));
+ }
}
- }
- if (raw_mem_set)
- MC_SET_MC_HEAP;
+ }
+ mmalloc_set_current_heap(heap);
}
/******************************* Core of MC *******************************/
/**************************************************************************/
-static void MC_modelcheck_comm_determinism_init(void)
-{
-
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_init();
-
- if (!mc_mem_set)
- MC_SET_MC_HEAP;
-
- /* Create exploration stack */
- mc_stack = xbt_fifo_new();
-
- MC_SET_STD_HEAP;
-
- MC_pre_modelcheck_comm_determinism();
-
- MC_SET_MC_HEAP;
- initial_global_state = xbt_new0(s_mc_global_t, 1);
- initial_global_state->snapshot = MC_take_snapshot(0);
- initial_global_state->initial_communications_pattern_done = 0;
- initial_global_state->recv_deterministic = 1;
- initial_global_state->send_deterministic = 1;
- initial_global_state->recv_diff = NULL;
- initial_global_state->send_diff = NULL;
-
- MC_SET_STD_HEAP;
-
- MC_modelcheck_comm_determinism();
-
- if(mc_mem_set)
- MC_SET_MC_HEAP;
-
-}
-
-static void MC_modelcheck_safety_init(void)
-{
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- _sg_mc_safety = 1;
-
- MC_init();
-
- if (!mc_mem_set)
- MC_SET_MC_HEAP;
-
- /* Create exploration stack */
- mc_stack = xbt_fifo_new();
-
- MC_SET_STD_HEAP;
-
- MC_pre_modelcheck_safety();
-
- MC_SET_MC_HEAP;
- /* Save the initial state */
- initial_global_state = xbt_new0(s_mc_global_t, 1);
- initial_global_state->snapshot = MC_take_snapshot(0);
- MC_SET_STD_HEAP;
-
- MC_modelcheck_safety();
-
- if (mc_mem_set)
- MC_SET_MC_HEAP;
-
- xbt_abort();
- //MC_exit();
-}
-
-static void MC_modelcheck_liveness_init()
-{
-
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- _sg_mc_liveness = 1;
-
- MC_init();
-
- if (!mc_mem_set)
- MC_SET_MC_HEAP;
-
- /* Create exploration stack */
- mc_stack = xbt_fifo_new();
-
- /* Create the initial state */
- initial_global_state = xbt_new0(s_mc_global_t, 1);
-
- MC_SET_STD_HEAP;
-
- MC_pre_modelcheck_liveness();
-
- /* We're done */
- MC_print_statistics(mc_stats);
- xbt_free(mc_time);
-
- if (mc_mem_set)
- MC_SET_MC_HEAP;
-
-}
-
void MC_do_the_modelcheck_for_real()
{
+ MC_init_mode();
+
+ switch(mc_mode) {
+ default:
+ xbt_die("Unexpected mc mode");
+ break;
+ case MC_MODE_CLIENT:
+ MC_init();
+ MC_client_main_loop();
+ return;
+ case MC_MODE_SERVER:
+ break;
+ case MC_MODE_STANDALONE:
+ MC_init();
+ break;
+ }
if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
XBT_INFO("Check communication determinism");
mc_reduce_kind = e_mc_reduce_none;
- MC_modelcheck_comm_determinism_init();
- } else if (!_sg_mc_property_file || _sg_mc_property_file[0] == '\0') {
- if(_sg_mc_termination){
- XBT_INFO("Check non progressive cycles");
+ MC_wait_for_requests();
+ MC_modelcheck_comm_determinism();
+ }
+
+ else if (!_sg_mc_property_file || _sg_mc_property_file[0] == '\0') {
+ if(_sg_mc_termination)
mc_reduce_kind = e_mc_reduce_none;
- }else{
+ else if (mc_reduce_kind == e_mc_reduce_unset)
+ mc_reduce_kind = e_mc_reduce_dpor;
+ _sg_mc_safety = 1;
+ if (_sg_mc_termination)
+ XBT_INFO("Check non progressive cycles");
+ else
XBT_INFO("Check a safety property");
- }
- MC_modelcheck_safety_init();
- } else {
+ MC_wait_for_requests();
+ MC_modelcheck_safety();
+ }
+
+ else {
if (mc_reduce_kind == e_mc_reduce_unset)
mc_reduce_kind = e_mc_reduce_none;
XBT_INFO("Check the liveness property %s", _sg_mc_property_file);
MC_automaton_load(_sg_mc_property_file);
- MC_modelcheck_liveness_init();
+ MC_wait_for_requests();
+ MC_modelcheck_liveness();
}
+
}
int MC_deadlock_check()
{
+ if (mc_mode == MC_MODE_SERVER) {
+ int res;
+ if ((res = MC_protocol_send_simple_message(mc_model_checker->process.socket,
+ MC_MESSAGE_DEADLOCK_CHECK)))
+ xbt_die("Could not check deadlock state");
+ s_mc_int_message_t message;
+ ssize_t s = MC_receive_message(mc_model_checker->process.socket, &message, sizeof(message), 0);
+ if (s == -1)
+ xbt_die("Could not receive message");
+ else if (s != sizeof(message) || message.type != MC_MESSAGE_DEADLOCK_CHECK_REPLY) {
+ xbt_die("%s received unexpected message %s (%i, size=%i) "
+ "expected MC_MESSAGE_DEADLOCK_CHECK_REPLY (%i, size=%i)",
+ MC_mode_name(mc_mode),
+ MC_message_type_name(message.type), (int) message.type, (int) s,
+ (int) MC_MESSAGE_DEADLOCK_CHECK_REPLY, (int) sizeof(message)
+ );
+ }
+ else
+ return message.value;
+ }
+
int deadlock = FALSE;
smx_process_t process;
if (xbt_swag_size(simix_global->process_list)) {
deadlock = TRUE;
- xbt_swag_foreach(process, simix_global->process_list) {
- if (MC_request_is_enabled(&process->simcall)) {
+ MC_EACH_SIMIX_PROCESS(process,
+ if (MC_process_is_enabled(process)) {
deadlock = FALSE;
break;
}
- }
+ );
}
return deadlock;
}
-void handle_comm_pattern(e_mc_call_type_t call_type, smx_simcall_t req, int value, xbt_dynar_t pattern, int backtracking) {
-
- switch(call_type) {
- case MC_CALL_TYPE_NONE:
- break;
- case MC_CALL_TYPE_SEND:
- case MC_CALL_TYPE_RECV:
- get_comm_pattern(pattern, req, call_type, backtracking);
- break;
- case MC_CALL_TYPE_WAIT:
- case MC_CALL_TYPE_WAITANY:
- {
- smx_synchro_t current_comm = NULL;
- if (call_type == MC_CALL_TYPE_WAIT)
- current_comm = simcall_comm_wait__get__comm(req);
- else
- current_comm = xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value, smx_synchro_t);
- complete_comm_pattern(pattern, current_comm, req->issuer->pid, backtracking);
- }
- break;
- default:
- xbt_die("Unexpected call type %i", (int)call_type);
- }
-
-}
-
-static void MC_restore_communications_pattern(mc_state_t state) {
- mc_list_comm_pattern_t list_process_comm;
- unsigned int cursor, cursor2;
- xbt_dynar_foreach(initial_communications_pattern, cursor, list_process_comm){
- list_process_comm->index_comm = (int)xbt_dynar_get_as(state->index_comm, cursor, int);
- }
- mc_comm_pattern_t comm;
- cursor = 0;
- xbt_dynar_t initial_incomplete_process_comms, incomplete_process_comms;
- for(int i=0; i<simix_process_maxpid; i++){
- initial_incomplete_process_comms = xbt_dynar_get_as(incomplete_communications_pattern, i, xbt_dynar_t);
- xbt_dynar_reset(initial_incomplete_process_comms);
- incomplete_process_comms = xbt_dynar_get_as(state->incomplete_comm_pattern, i, xbt_dynar_t);
- xbt_dynar_foreach(incomplete_process_comms, cursor2, comm) {
- mc_comm_pattern_t copy_comm = xbt_new0(s_mc_comm_pattern_t, 1);
- copy_comm->index = comm->index;
- copy_comm->type = comm->type;
- copy_comm->comm = comm->comm;
- copy_comm->rdv = strdup(comm->rdv);
- copy_comm->data_size = -1;
- copy_comm->data = NULL;
- if(comm->type == SIMIX_COMM_SEND){
- copy_comm->src_proc = comm->src_proc;
- copy_comm->src_host = comm->src_host;
- if(comm->data != NULL){
- copy_comm->data_size = comm->data_size;
- copy_comm->data = xbt_malloc0(comm->data_size);
- memcpy(copy_comm->data, comm->data, comm->data_size);
- }
- }else{
- copy_comm->dst_proc = comm->dst_proc;
- copy_comm->dst_host = comm->dst_host;
- }
- xbt_dynar_push(initial_incomplete_process_comms, ©_comm);
- }
- }
-}
-
/**
* \brief Re-executes from the state at position start all the transitions indicated by
* a given model-checker stack.
*/
void MC_replay(xbt_fifo_t stack)
{
- int raw_mem = (mmalloc_get_current_heap() == mc_heap);
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
int value, count = 1, j;
char *req_str;
MC_SET_MC_HEAP;
if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
- for (j=0; j<simix_process_maxpid; j++) {
+ // int n = xbt_dynar_length(incomplete_communications_pattern);
+ int n = MC_smx_get_maxpid();
+ assert(n == xbt_dynar_length(incomplete_communications_pattern));
+ assert(n == xbt_dynar_length(initial_communications_pattern));
+ for (j=0; j < n ; j++) {
xbt_dynar_reset((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, j, xbt_dynar_t));
- ((mc_list_comm_pattern_t)xbt_dynar_get_as(initial_communications_pattern, j, mc_list_comm_pattern_t))->index_comm = 0;
+ xbt_dynar_get_as(initial_communications_pattern, j, mc_list_comm_pattern_t)->index_comm = 0;
}
}
if (saved_req) {
/* because we got a copy of the executed request, we have to fetch the
real one, pointed by the request field of the issuer process */
- req = &saved_req->issuer->simcall;
+
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(saved_req);
+ req = &issuer->simcall;
/* Debug information */
if (XBT_LOG_ISENABLED(mc_global, xbt_log_priority_debug)) {
- req_str = MC_request_to_string(req, value);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
XBT_DEBUG("Replay: %s (%p)", req_str, state);
xbt_free(req_str);
}
/* TODO : handle test and testany simcalls */
e_mc_call_type_t call = MC_CALL_TYPE_NONE;
if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
- call = mc_get_call_type(req);
+ call = MC_get_call_type(req);
- SIMIX_simcall_handle(req, value);
+ MC_simcall_handle(req, value);
MC_SET_MC_HEAP;
if (_sg_mc_comms_determinism || _sg_mc_send_determinism)
- handle_comm_pattern(call, req, value, NULL, 1);
+ MC_handle_comm_pattern(call, req, value, NULL, 1);
MC_SET_STD_HEAP;
-
+
MC_wait_for_requests();
count++;
}
XBT_DEBUG("**** End Replay ****");
-
- if (raw_mem)
- MC_SET_MC_HEAP;
- else
- MC_SET_STD_HEAP;
-
-
+ mmalloc_set_current_heap(heap);
}
void MC_replay_liveness(xbt_fifo_t stack)
if (saved_req != NULL) {
/* because we got a copy of the executed request, we have to fetch the
real one, pointed by the request field of the issuer process */
- req = &saved_req->issuer->simcall;
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(saved_req);
+ req = &issuer->simcall;
/* Debug information */
if (XBT_LOG_ISENABLED(mc_global, xbt_log_priority_debug)) {
- req_str = MC_request_to_string(req, value);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
XBT_DEBUG("Replay (depth = %d) : %s (%p)", depth, req_str, state);
xbt_free(req_str);
}
}
- SIMIX_simcall_handle(req, value);
+ MC_simcall_handle(req, value);
MC_wait_for_requests();
}
*/
void MC_dump_stack_safety(xbt_fifo_t stack)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
MC_show_stack_safety(stack);
MC_SET_MC_HEAP;
while ((state = (mc_state_t) xbt_fifo_pop(stack)) != NULL)
MC_state_delete(state, !state->in_visited_states ? 1 : 0);
- MC_SET_STD_HEAP;
-
- if (raw_mem_set)
- MC_SET_MC_HEAP;
- else
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
}
void MC_show_stack_safety(xbt_fifo_t stack)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
int value;
mc_state_t state;
: (NULL)); item = xbt_fifo_get_prev_item(item)) {
req = MC_state_get_executed_request(state, &value);
if (req) {
- req_str = MC_request_to_string(req, value);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_EXECUTED);
XBT_INFO("%s", req_str);
xbt_free(req_str);
}
}
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
}
void MC_show_deadlock(smx_simcall_t req)
item = xbt_fifo_get_prev_item(item)) {
req = MC_state_get_executed_request(pair->graph_state, &value);
if (req && req->call != SIMCALL_NONE) {
- req_str = MC_request_to_string(req, value);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_EXECUTED);
XBT_INFO("%s", req_str);
xbt_free(req_str);
}
void MC_dump_stack_liveness(xbt_fifo_t stack)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
mc_pair_t pair;
-
- MC_SET_MC_HEAP;
while ((pair = (mc_pair_t) xbt_fifo_pop(stack)) != NULL)
MC_pair_delete(pair);
- MC_SET_STD_HEAP;
-
- if (raw_mem_set)
- MC_SET_MC_HEAP;
-
+ mmalloc_set_current_heap(heap);
}
void MC_print_statistics(mc_stats_t stats)
{
- xbt_mheap_t previous_heap = mmalloc_get_current_heap();
-
if(_sg_mc_comms_determinism) {
if (!initial_global_state->recv_deterministic && initial_global_state->send_deterministic){
XBT_INFO("******************************************************");
XBT_INFO("%s", initial_global_state->send_diff);
}
}
+
if (stats->expanded_pairs == 0) {
XBT_INFO("Expanded states = %lu", stats->expanded_states);
XBT_INFO("Visited states = %lu", stats->visited_states);
XBT_INFO("Visited pairs = %lu", stats->visited_pairs);
}
XBT_INFO("Executed transitions = %lu", stats->executed_transitions);
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
if ((_sg_mc_dot_output_file != NULL) && (_sg_mc_dot_output_file[0] != '\0')) {
fprintf(dot_output, "}\n");
fclose(dot_output);
if (_sg_mc_comms_determinism)
XBT_INFO("Recv-deterministic : %s", !initial_global_state->recv_deterministic ? "No" : "Yes");
}
- mmalloc_set_current_heap(previous_heap);
-}
-
-void MC_assert(int prop)
-{
- if (MC_is_active() && !prop) {
- XBT_INFO("**************************");
- XBT_INFO("*** PROPERTY NOT VALID ***");
- XBT_INFO("**************************");
- XBT_INFO("Counter-example execution trace:");
- MC_record_dump_path(mc_stack);
- MC_dump_stack_safety(mc_stack);
- MC_print_statistics(mc_stats);
- xbt_abort();
- }
-}
-
-void MC_cut(void)
-{
- user_max_depth_reached = 1;
+ mmalloc_set_current_heap(heap);
}
void MC_automaton_load(const char *file)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
if (_mc_property_automaton == NULL)
_mc_property_automaton = xbt_automaton_new();
xbt_automaton_load(_mc_property_automaton, file);
-
- MC_SET_STD_HEAP;
-
- if (raw_mem_set)
- MC_SET_MC_HEAP;
-
+ mmalloc_set_current_heap(heap);
}
-void MC_automaton_new_propositional_symbol(const char *id, void *fct)
+static void register_symbol(xbt_automaton_propositional_symbol_t symbol)
{
+ if (mc_mode != MC_MODE_CLIENT)
+ return;
+ s_mc_register_symbol_message_t message;
+ message.type = MC_MESSAGE_REGISTER_SYMBOL;
+ const char* name = xbt_automaton_propositional_symbol_get_name(symbol);
+ if (strlen(name) + 1 > sizeof(message.name))
+ xbt_die("Symbol is too long");
+ strncpy(message.name, name, sizeof(message.name));
+ message.callback = xbt_automaton_propositional_symbol_get_callback(symbol);
+ message.data = xbt_automaton_propositional_symbol_get_data(symbol);
+ MC_client_send_message(&message, sizeof(message));
+}
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+void MC_automaton_new_propositional_symbol(const char *id, int(*fct)(void))
+{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
if (_mc_property_automaton == NULL)
_mc_property_automaton = xbt_automaton_new();
- xbt_automaton_propositional_symbol_new(_mc_property_automaton, id, fct);
-
- MC_SET_STD_HEAP;
+ xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new(_mc_property_automaton, id, fct);
+ register_symbol(symbol);
+ mmalloc_set_current_heap(heap);
+}
- if (raw_mem_set)
- MC_SET_MC_HEAP;
+void MC_automaton_new_propositional_symbol_pointer(const char *id, int* value)
+{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ if (_mc_property_automaton == NULL)
+ _mc_property_automaton = xbt_automaton_new();
+ xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new_pointer(_mc_property_automaton, id, value);
+ register_symbol(symbol);
+ mmalloc_set_current_heap(heap);
+}
+void MC_automaton_new_propositional_symbol_callback(const char* id,
+ xbt_automaton_propositional_symbol_callback_type callback,
+ void* data, xbt_automaton_propositional_symbol_free_function_type free_function)
+{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ if (_mc_property_automaton == NULL)
+ _mc_property_automaton = xbt_automaton_new();
+ xbt_automaton_propositional_symbol_t symbol = xbt_automaton_propositional_symbol_new_callback(
+ _mc_property_automaton, id, callback, data, free_function);
+ register_symbol(symbol);
+ mmalloc_set_current_heap(heap);
}
+// TODO, fix cross-process access (this function is not used)
void MC_dump_stacks(FILE* file)
{
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
int nstack = 0;
stack_region_t current_stack;
unw_word_t off;
do {
const char * name = !unw_get_proc_name(&c, buffer, 100, &off) ? buffer : "?";
+#if defined(__x86_64__)
+ unw_word_t rip = 0;
+ unw_word_t rsp = 0;
+ unw_get_reg(&c, UNW_X86_64_RIP, &rip);
+ unw_get_reg(&c, UNW_X86_64_RSP, &rsp);
+ fprintf(file, " %i: %s (RIP=0x%" PRIx64 " RSP=0x%" PRIx64 ")\n",
+ nframe, name, rip, rsp);
+#else
fprintf(file, " %i: %s\n", nframe, name);
+#endif
++nframe;
} while(unw_step(&c));
++nstack;
}
-
- if (raw_mem_set)
- MC_SET_MC_HEAP;
+ mmalloc_set_current_heap(heap);
}
#endif
{
mc_time[process->pid] += amount;
}
+
+#ifdef HAVE_MC
+void MC_report_assertion_error(void)
+{
+ XBT_INFO("**************************");
+ XBT_INFO("*** PROPERTY NOT VALID ***");
+ XBT_INFO("**************************");
+ XBT_INFO("Counter-example execution trace:");
+ MC_record_dump_path(mc_stack);
+ MC_dump_stack_safety(mc_stack);
+ MC_print_statistics(mc_stats);
+}
+#endif
mc_object_info_t info, const void *address,
dw_type_t type)
{
+ mc_process_t process = &mc_model_checker->process;
top:
switch (type->type) {
mc_address_add(state->handled_addresses, pointed);
// Anything outside the R/W segments and the heap is not hashed:
- bool valid_pointer = (pointed >= (void *) mc_binary_info->start_rw
- && pointed <= (void *) mc_binary_info->end_rw)
- || (pointed >= (void *) mc_libsimgrid_info->start_rw
- && pointed <= (void *) mc_libsimgrid_info->end_rw)
- || (pointed >= std_heap
- && pointed < (void *) ((const char *) std_heap + STD_HEAP_SIZE));
+ bool valid_pointer = (pointed >= (void *) binary_info->start_rw
+ && pointed <= (void *) binary_info->end_rw)
+ || (pointed >= (void *) libsimgrid_info->start_rw
+ && pointed <= (void *) libsimgrid_info->end_rw)
+ || (pointed >= process->heap_address
+ && pointed < (void *) ((const char *) process->heap_address + STD_HEAP_SIZE));
if (!valid_pointer) {
XBT_DEBUG("Hashed pointed data %p is in an ignored range", pointed);
return;
}
const char *address = variable->address;
- bool valid_pointer = (address >= mc_binary_info->start_rw
- && address <= mc_binary_info->end_rw)
- || (address >= mc_libsimgrid_info->start_rw
- && address <= mc_libsimgrid_info->end_rw)
- || (address >= (const char *) std_heap
- && address < (const char *) std_heap + STD_HEAP_SIZE);
+ bool valid_pointer = (address >= binary_info->start_rw
+ && address <= binary_info->end_rw)
+ || (address >= libsimgrid_info->start_rw
+ && address <= libsimgrid_info->end_rw)
+ || (address >= (const char *) process->heap_address
+ && address < (const char *) process->heap_address + STD_HEAP_SIZE);
if (!valid_pointer)
continue;
MC_HASH(*hash, stack_frame->ip);
mc_object_info_t info;
- if (stack_frame->ip >= (unw_word_t) mc_libsimgrid_info->start_exec
- && stack_frame->ip < (unw_word_t) mc_libsimgrid_info->end_exec)
- info = mc_libsimgrid_info;
- else if (stack_frame->ip >= (unw_word_t) mc_binary_info->start_exec
- && stack_frame->ip < (unw_word_t) mc_binary_info->end_exec)
- info = mc_binary_info;
+ if (stack_frame->ip >= (unw_word_t) libsimgrid_info->start_exec
+ && stack_frame->ip < (unw_word_t) libsimgrid_info->end_exec)
+ info = libsimgrid_info;
+ else if (stack_frame->ip >= (unw_word_t) binary_info->start_exec
+ && stack_frame->ip < (unw_word_t) binary_info->end_exec)
+ info = binary_info;
else
continue;
mc_hash_t hash = MC_HASH_INIT;
MC_HASH(hash, xbt_swag_size(simix_global->process_list)); // process count
- // mc_hash_object_globals(&hash, &state, mc_binary_info);
- // mc_hash_object_globals(&hash, &state, mc_libsimgrid_info);
+ // mc_hash_object_globals(&hash, &state, binary_info);
+ // mc_hash_object_globals(&hash, &state, libsimgrid_info);
// mc_hash_stacks(&hash, &state, stacks);
mc_hash_state_destroy(&state);
#include "mc_private.h"
#include "smpi/private.h"
#include "mc/mc_snapshot.h"
+#include "mc_ignore.h"
+#include "mc_protocol.h"
+#include "mc_client.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_ignore, mc,
"Logging specific to MC ignore mechanism");
/**************************** Global variables ******************************/
-xbt_dynar_t mc_checkpoint_ignore;
+// Those structures live with the MCer and should be moved in the model_checker
+// structure but they are currently used before the MC initialisation
+// (in standalone mode).
+
extern xbt_dynar_t mc_heap_comparison_ignore;
extern xbt_dynar_t stacks_areas;
checkpoint_ignore_region_free((mc_checkpoint_ignore_region_t) * (void **) r);
}
-/***********************************************************************/
-
-void MC_ignore_heap(void *address, size_t size)
+xbt_dynar_t MC_checkpoint_ignore_new(void)
{
+ return xbt_dynar_new(sizeof(mc_checkpoint_ignore_region_t),
+ checkpoint_ignore_region_free_voidp);
+}
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
-
- mc_heap_ignore_region_t region = NULL;
- region = xbt_new0(s_mc_heap_ignore_region_t, 1);
- region->address = address;
- region->size = size;
-
- region->block =
- ((char *) address -
- (char *) std_heap->heapbase) / BLOCKSIZE + 1;
-
- if (std_heap->heapinfo[region->block].type == 0) {
- region->fragment = -1;
- std_heap->heapinfo[region->block].busy_block.ignore++;
- } else {
- region->fragment =
- ((uintptr_t) (ADDR2UINT(address) % (BLOCKSIZE))) >> std_heap->
- heapinfo[region->block].type;
- std_heap->heapinfo[region->block].busy_frag.ignore[region->fragment]++;
- }
+/***********************************************************************/
+// Mcer
+void MC_heap_region_ignore_insert(mc_heap_ignore_region_t region)
+{
if (mc_heap_comparison_ignore == NULL) {
mc_heap_comparison_ignore =
xbt_dynar_new(sizeof(mc_heap_ignore_region_t),
heap_ignore_region_free_voidp);
xbt_dynar_push(mc_heap_comparison_ignore, ®ion);
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
return;
}
int start = 0;
int end = xbt_dynar_length(mc_heap_comparison_ignore) - 1;
+ // Find the position where we want to insert the mc_heap_ignore_region_t:
while (start <= end) {
cursor = (start + end) / 2;
current_region =
(mc_heap_ignore_region_t) xbt_dynar_get_as(mc_heap_comparison_ignore,
cursor,
mc_heap_ignore_region_t);
- if (current_region->address == address) {
+ if (current_region->address == region->address) {
heap_ignore_region_free(region);
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
return;
- } else if (current_region->address < address) {
+ } else if (current_region->address < region->address) {
start = cursor + 1;
} else {
end = cursor - 1;
}
}
- if (current_region->address < address)
+ // Insert it mc_heap_ignore_region_t:
+ if (current_region->address < region->address)
xbt_dynar_insert_at(mc_heap_comparison_ignore, cursor + 1, ®ion);
else
xbt_dynar_insert_at(mc_heap_comparison_ignore, cursor, ®ion);
+}
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+// MCed:
+static void MC_heap_region_ignore_send(mc_heap_ignore_region_t region)
+{
+ s_mc_ignore_heap_message_t message;
+ message.type = MC_MESSAGE_IGNORE_HEAP;
+ message.region = *region;
+ if (MC_protocol_send(mc_client->fd, &message, sizeof(message)))
+ xbt_die("Could not send ignored region to MCer");
}
-void MC_remove_ignore_heap(void *address, size_t size)
+// MCed:
+void MC_ignore_heap(void *address, size_t size)
{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+
+ mc_heap_ignore_region_t region = xbt_new0(s_mc_heap_ignore_region_t, 1);
+ region->address = address;
+ region->size = size;
+
+ region->block =
+ ((char *) address -
+ (char *) std_heap->heapbase) / BLOCKSIZE + 1;
+
+ if (std_heap->heapinfo[region->block].type == 0) {
+ region->fragment = -1;
+ std_heap->heapinfo[region->block].busy_block.ignore++;
+ } else {
+ region->fragment =
+ ((uintptr_t) (ADDR2UINT(address) % (BLOCKSIZE))) >> std_heap->
+ heapinfo[region->block].type;
+ std_heap->heapinfo[region->block].busy_frag.ignore[region->fragment]++;
+ }
+
+ MC_heap_region_ignore_insert(region);
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
+#if 1
+ if (mc_mode == MC_MODE_CLIENT)
+ MC_heap_region_ignore_send(region);
+#endif
+ mmalloc_set_current_heap(heap);
+}
+
+void MC_remove_ignore_heap(void *address, size_t size)
+{
+ if (mc_mode == MC_MODE_CLIENT) {
+ s_mc_ignore_memory_message_t message;
+ message.type = MC_MESSAGE_UNIGNORE_HEAP;
+ message.addr = address;
+ message.size = size;
+ MC_client_send_message(&message, sizeof(message));
+ }
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
unsigned int cursor = 0;
int start = 0;
xbt_dynar_remove_at(mc_heap_comparison_ignore, cursor, NULL);
MC_remove_ignore_heap(address, size);
}
-
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
}
+// MCer
void MC_ignore_global_variable(const char *name)
{
+ mc_process_t process = &mc_model_checker->process;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ xbt_assert(process->object_infos, "MC subsystem not initialized");
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
-
- xbt_assert(mc_libsimgrid_info, "MC subsystem not initialized");
-
- unsigned int cursor = 0;
- dw_variable_t current_var;
- int start = 0;
- int end = xbt_dynar_length(mc_libsimgrid_info->global_variables) - 1;
+ size_t n = process->object_infos_size;
+ for (size_t i=0; i!=n; ++i) {
+ mc_object_info_t info = process->object_infos[i];
- while (start <= end) {
- cursor = (start + end) / 2;
- current_var =
- (dw_variable_t) xbt_dynar_get_as(mc_libsimgrid_info->global_variables,
- cursor, dw_variable_t);
- if (strcmp(current_var->name, name) == 0) {
- xbt_dynar_remove_at(mc_libsimgrid_info->global_variables, cursor, NULL);
- start = 0;
- end = xbt_dynar_length(mc_libsimgrid_info->global_variables) - 1;
- } else if (strcmp(current_var->name, name) < 0) {
- start = cursor + 1;
- } else {
- end = cursor - 1;
+ // Binary search:
+ int start = 0;
+ int end = xbt_dynar_length(info->global_variables) - 1;
+ while (start <= end) {
+ unsigned int cursor = (start + end) / 2;
+ dw_variable_t current_var =
+ (dw_variable_t) xbt_dynar_get_as(info->global_variables,
+ cursor, dw_variable_t);
+ if (strcmp(current_var->name, name) == 0) {
+ xbt_dynar_remove_at(info->global_variables, cursor, NULL);
+ start = 0;
+ end = xbt_dynar_length(info->global_variables) - 1;
+ } else if (strcmp(current_var->name, name) < 0) {
+ start = cursor + 1;
+ } else {
+ end = cursor - 1;
+ }
}
}
-
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
}
/** \brief Ignore a local variable in a scope
{
// Processing of direct variables:
- // If the current subprogram matche the given name:
+ // If the current subprogram matches the given name:
if (!subprogram_name ||
(subprogram->name && strcmp(subprogram_name, subprogram->name) == 0)) {
}
}
+// MCer
void MC_ignore_local_variable(const char *var_name, const char *frame_name)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
+ mc_process_t process = &mc_model_checker->process;
if (strcmp(frame_name, "*") == 0)
frame_name = NULL;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
- MC_SET_MC_HEAP;
-
- MC_ignore_local_variable_in_object(var_name, frame_name, mc_libsimgrid_info);
- if (frame_name != NULL)
- MC_ignore_local_variable_in_object(var_name, frame_name, mc_binary_info);
+ size_t n = process->object_infos_size;
+ size_t i;
+ for (i=0; i!=n; ++i) {
+ MC_ignore_local_variable_in_object(var_name, frame_name, process->object_infos[i]);
+ }
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
+}
+void MC_stack_area_add(stack_region_t stack_area)
+{
+ if (stacks_areas == NULL)
+ stacks_areas = xbt_dynar_new(sizeof(stack_region_t), NULL);
+ xbt_dynar_push(stacks_areas, &stack_area);
}
/** @brief Register a stack in the model checker
*
* The stacks are allocated in the heap. The MC handle them especially
- * when we analyse/compare the content of theap so it must be told where
+ * when we analyse/compare the content of the heap so it must be told where
* they are with this function.
*
* @param stack
*/
void MC_new_stack_area(void *stack, smx_process_t process, void *context, size_t size)
{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
-
- if (stacks_areas == NULL)
- stacks_areas = xbt_dynar_new(sizeof(stack_region_t), NULL);
-
- stack_region_t region = NULL;
- region = xbt_new0(s_stack_region_t, 1);
+ stack_region_t region = xbt_new0(s_stack_region_t, 1);
region->address = stack;
- region->process_name = process && process->name ? strdup(process->name) : NULL;
region->context = context;
region->size = size;
region->block =
#endif
region->process_index = -1;
- xbt_dynar_push(stacks_areas, ®ion);
+ if (mc_mode == MC_MODE_CLIENT) {
+ s_mc_stack_region_message_t message;
+ message.type = MC_MESSAGE_STACK_REGION;
+ message.stack_region = *region;
+ MC_client_send_message(&message, sizeof(message));
+ }
+
+ MC_stack_area_add(region);
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
}
-void MC_ignore(void *addr, size_t size)
+void MC_process_ignore_memory(mc_process_t process, void *addr, size_t size)
{
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
-
- if (mc_checkpoint_ignore == NULL)
- mc_checkpoint_ignore =
- xbt_dynar_new(sizeof(mc_checkpoint_ignore_region_t),
- checkpoint_ignore_region_free_voidp);
-
+ xbt_dynar_t checkpoint_ignore = process->checkpoint_ignore;
mc_checkpoint_ignore_region_t region =
xbt_new0(s_mc_checkpoint_ignore_region_t, 1);
region->addr = addr;
region->size = size;
- if (xbt_dynar_is_empty(mc_checkpoint_ignore)) {
- xbt_dynar_push(mc_checkpoint_ignore, ®ion);
+ if (xbt_dynar_is_empty(checkpoint_ignore)) {
+ xbt_dynar_push(checkpoint_ignore, ®ion);
} else {
unsigned int cursor = 0;
int start = 0;
- int end = xbt_dynar_length(mc_checkpoint_ignore) - 1;
+ int end = xbt_dynar_length(checkpoint_ignore) - 1;
mc_checkpoint_ignore_region_t current_region = NULL;
while (start <= end) {
cursor = (start + end) / 2;
current_region =
- (mc_checkpoint_ignore_region_t) xbt_dynar_get_as(mc_checkpoint_ignore,
+ (mc_checkpoint_ignore_region_t) xbt_dynar_get_as(checkpoint_ignore,
cursor,
mc_checkpoint_ignore_region_t);
if (current_region->addr == addr) {
if (current_region->size == size) {
checkpoint_ignore_region_free(region);
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
return;
} else if (current_region->size < size) {
start = cursor + 1;
if (current_region->addr == addr) {
if (current_region->size < size) {
- xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, ®ion);
+ xbt_dynar_insert_at(checkpoint_ignore, cursor + 1, ®ion);
} else {
- xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, ®ion);
+ xbt_dynar_insert_at(checkpoint_ignore, cursor, ®ion);
}
} else if (current_region->addr < addr) {
- xbt_dynar_insert_at(mc_checkpoint_ignore, cursor + 1, ®ion);
+ xbt_dynar_insert_at(checkpoint_ignore, cursor + 1, ®ion);
} else {
- xbt_dynar_insert_at(mc_checkpoint_ignore, cursor, ®ion);
+ xbt_dynar_insert_at(checkpoint_ignore, cursor, ®ion);
}
}
-
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team. All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <xbt/dynar.h>
+
+#include "mc/datatypes.h"
+#include "mc_process.h"
+
+#include "xbt/misc.h" /* SG_BEGIN_DECL */
+
+SG_BEGIN_DECL();
+
+void MC_heap_region_ignore_insert(mc_heap_ignore_region_t region);
+void MC_process_ignore_memory(mc_process_t process, void *addr, size_t size);
+void MC_stack_area_add(stack_region_t stack_area);
+
+xbt_dynar_t MC_checkpoint_ignore_new(void);
+
+
+SG_END_DECL();
#include "mc_liveness.h"
#include "mc_private.h"
#include "mc_record.h"
+#include "mc_smx.h"
+#include "mc_client.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_liveness, mc,
"Logging specific to algorithms for liveness properties verification");
static xbt_dynar_t get_atomic_propositions_values()
{
- int res;
- int_f_void_t f;
unsigned int cursor = 0;
xbt_automaton_propositional_symbol_t ps = NULL;
xbt_dynar_t values = xbt_dynar_new(sizeof(int), NULL);
-
xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, ps) {
- f = (int_f_void_t) ps->function;
- res = f();
+ int res = xbt_automaton_propositional_symbol_evaluate(ps);
xbt_dynar_push_as(values, int, res);
}
return values;
}
-
-static mc_visited_pair_t is_reached_acceptance_pair(mc_pair_t pair){
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+static mc_visited_pair_t is_reached_acceptance_pair(mc_pair_t pair) {
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
mc_visited_pair_t new_pair = NULL;
new_pair = MC_visited_pair_new(pair->num, pair->automaton_state, pair->atomic_propositions, pair->graph_state);
xbt_fifo_shift(mc_stack);
if (dot_output != NULL)
fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", initial_global_state->prev_pair, pair_test->num, initial_global_state->prev_req);
-
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return NULL;
}
}
}
}
-
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return new_pair;
-
}
-static void remove_acceptance_pair(int pair_num) {
-
- int raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+static void remove_acceptance_pair(int pair_num)
+{
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
unsigned int cursor = 0;
mc_visited_pair_t pair_test = NULL;
}
- if (!raw_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
}
unsigned int cursor = 0;
xbt_automaton_propositional_symbol_t p = NULL;
xbt_dynar_foreach(_mc_property_automaton->propositional_symbols, cursor, p) {
- if (strcmp(p->pred, l->u.predicat) == 0)
+ if (strcmp(xbt_automaton_propositional_symbol_get_name(p), l->u.predicat) == 0)
return (int) xbt_dynar_get_as(atomic_propositions_values, cursor, int);
}
return -1;
}
}
-void MC_pre_modelcheck_liveness(void) {
+static void MC_modelcheck_liveness_main(void);
+static void MC_pre_modelcheck_liveness(void)
+{
initial_global_state->raw_mem_set = (mmalloc_get_current_heap() == mc_heap);
mc_pair_t initial_pair = NULL;
initial_pair->depth = 1;
/* Get enabled processes and insert them in the interleave set of the graph_state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(initial_pair->graph_state, process);
}
- }
+ );
initial_pair->requests = MC_state_interleave_size(initial_pair->graph_state);
initial_pair->search_cycle = 0;
MC_SET_STD_HEAP;
- MC_modelcheck_liveness();
+ MC_modelcheck_liveness_main();
if (initial_global_state->raw_mem_set)
MC_SET_MC_HEAP;
-
-
}
-void MC_modelcheck_liveness() {
-
+static void MC_modelcheck_liveness_main(void)
+{
smx_process_t process = NULL;
mc_pair_t current_pair = NULL;
int value, res, visited_num = -1;
/* Update current state in buchi automaton */
_mc_property_automaton->current_state = current_pair->automaton_state;
- XBT_DEBUG("********************* ( Depth = %d, search_cycle = %d, interleave size %d, pair_num %d)",
+ XBT_DEBUG("********************* ( Depth = %d, search_cycle = %d, interleave size = %d, pair_num = %d, requests = %d)",
current_pair->depth, current_pair->search_cycle,
- MC_state_interleave_size(current_pair->graph_state), current_pair->num);
+ MC_state_interleave_size(current_pair->graph_state), current_pair->num,
+ current_pair->requests);
if (current_pair->requests > 0) {
MC_SET_STD_HEAP;
}
- char* req_str = MC_request_to_string(req, value);
- XBT_DEBUG("Execute: %s", req_str);
+ char* req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
+ XBT_DEBUG("Execute: %s", req_str);
xbt_free(req_str);
/* Set request as executed */
mc_stats->visited_pairs++;
/* Answer the request */
- SIMIX_simcall_handle(req, value);
+ MC_simcall_handle(req, value);
/* Wait for requests (schedules processes) */
MC_wait_for_requests();
next_pair->atomic_propositions = get_atomic_propositions_values();
next_pair->depth = current_pair->depth + 1;
/* Get enabled processes and insert them in the interleave set of the next graph_state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(next_pair->graph_state, process);
}
- }
+ );
next_pair->requests = MC_state_interleave_size(next_pair->graph_state);
} /* End of while(xbt_fifo_size(mc_stack) > 0) */
}
+
+void MC_modelcheck_liveness(void)
+{
+ XBT_DEBUG("Starting the liveness algorithm");
+ _sg_mc_liveness = 1;
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+
+ /* Create exploration stack */
+ mc_stack = xbt_fifo_new();
+
+ /* Create the initial state */
+ initial_global_state = xbt_new0(s_mc_global_t, 1);
+
+ MC_SET_STD_HEAP;
+
+ MC_pre_modelcheck_liveness();
+
+ /* We're done */
+ MC_print_statistics(mc_stats);
+ xbt_free(mc_time);
+
+ mmalloc_set_current_heap(heap);
+
+}
mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state);
void MC_visited_pair_delete(mc_visited_pair_t p);
-void MC_pre_modelcheck_liveness(void);
void MC_modelcheck_liveness(void);
void MC_show_stack_liveness(xbt_fifo_t stack);
void MC_dump_stack_liveness(xbt_fifo_t stack);
#include <stdint.h>
-#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <dwarf.h>
#include <elfutils/libdw.h>
#include "mc_interface.h"
#include "mc_object_info.h"
#include "mc_forward.h"
+#include "mc_address_space.h"
SG_BEGIN_DECL()
}
}
-void mc_dwarf_resolve_location(mc_location_t location, mc_expression_t expression, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot, int process_index);
-void mc_dwarf_resolve_locations(mc_location_t location, mc_location_list_t locations, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_snapshot_t snapshot, int process_index);
+void mc_dwarf_resolve_location(mc_location_t location, mc_expression_t expression, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_address_space_t address_space, int process_index);
+void mc_dwarf_resolve_locations(mc_location_t location, mc_location_list_t locations, mc_object_info_t object_info, unw_cursor_t* c, void* frame_pointer_address, mc_address_space_t address_space, int process_index);
void mc_dwarf_expression_clear(mc_expression_t expression);
void mc_dwarf_expression_init(mc_expression_t expression, size_t len, Dwarf_Op* ops);
unw_cursor_t* cursor;
void* frame_base;
- mc_snapshot_t snapshot;
+ mc_address_space_t address_space;
mc_object_info_t object_info;
int process_index;
} s_mc_expression_state_t, *mc_expression_state_t;
* @return Process address of the given member of the 'object' struct/class
*/
void *mc_member_resolve(const void *base, dw_type_t type, dw_type_t member,
- mc_snapshot_t snapshot, int process_index)
+ mc_address_space_t address_space, int process_index)
{
if (!member->location.size) {
return ((char *) base) + member->offset;
memset(&state, 0, sizeof(s_mc_expression_state_t));
state.frame_base = NULL;
state.cursor = NULL;
- state.snapshot = snapshot;
+ state.address_space = address_space;
state.stack_size = 1;
state.stack[0] = (uintptr_t) base;
state.process_index = process_index;
#include <fcntl.h>
#include "xbt/log.h"
+#include "xbt/dynar.h"
+#include "xbt/virtu.h"
#include "mc/mc.h"
#include "mc_object_info.h"
/* It creates the two heap regions: std_heap and mc_heap */
void MC_memory_init()
{
+ if (!malloc_use_mmalloc()) {
+ xbt_die("Model-checking support is not enabled: run with simgrid-mc.");
+ }
+
/* Create the first region HEAP_OFFSET bytes after the heap break address */
std_heap = mmalloc_get_default_md();
xbt_assert(std_heap != NULL);
-#if 0 && defined HAVE_GNU_LD && !defined MMALLOC_WANT_OVERRIDE_LEGACY
- /* use the system malloc for the model-checker data */
- mc_heap = NULL;
-#else
/* Create the second region a page after the first one ends + safety gap */
mc_heap =
xbt_mheap_new_options(-1,
(char *) (std_heap) + STD_HEAP_SIZE + xbt_pagesize,
0);
xbt_assert(mc_heap != NULL);
-#endif
}
/* Finalize the memory subsystem */
#include "xbt_modinter.h"
void MC_memory_exit(void)
{
- MC_free_object_info(&mc_binary_info);
- MC_free_object_info(&mc_libsimgrid_info);
-
- if (mc_heap)
+ if (mc_heap && mc_heap != std_heap)
xbt_mheap_destroy(mc_heap);
}
#ifndef MC_MEMORY_MAP_H
#define MC_MEMORY_MAP_H
+#include <sys/types.h>
+
#include <simgrid_config.h>
#include "mc_forward.h"
};
-void MC_init_memory_map_info(void);
-memory_map_t MC_get_memory_map(void);
+memory_map_t MC_get_memory_map(pid_t pid);
void MC_free_memory_map(memory_map_t map);
SG_END_DECL()
* @return Virtual memory page number of the given address
*/
static inline __attribute__ ((always_inline))
-size_t mc_page_number(void* base, void* address)
+size_t mc_page_number(const void* base, const void* address)
{
xbt_assert(address>=base, "The address is not in the range");
return ((uintptr_t) address - (uintptr_t) base) >> xbt_pagebits;
* @return Offset within the memory page
*/
static inline __attribute__ ((always_inline))
-size_t mc_page_offset(void* address)
+size_t mc_page_offset(const void* address)
{
return ((uintptr_t) address) & (xbt_pagesize-1);
}
* @param page Index of the page
*/
static inline __attribute__ ((always_inline))
-void* mc_page_from_number(void* base, size_t page)
+void* mc_page_from_number(const void* base, size_t page)
{
return (void*) ((char*)base + (page << xbt_pagebits));
}
static inline __attribute__ ((always_inline))
-bool mc_same_page(void* a, void* b)
+bool mc_same_page(const void* a, const void* b)
{
return ((uintptr_t) a >> xbt_pagebits) == ((uintptr_t) b >> xbt_pagebits);
}
--- /dev/null
+/* Copyright (c) 2008-2014. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "mc_model_checker.h"
+#include "mc_page_store.h"
+
+mc_model_checker_t mc_model_checker = NULL;
+
+mc_model_checker_t MC_model_checker_new(pid_t pid, int socket)
+{
+ mc_model_checker_t mc = xbt_new0(s_mc_model_checker_t, 1);
+ mc->pages = mc_pages_store_new();
+ mc->fd_clear_refs = -1;
+ mc->fd_pagemap = -1;
+ MC_process_init(&mc->process, pid, socket);
+ mc->hosts = xbt_dict_new();
+ return mc;
+}
+
+void MC_model_checker_delete(mc_model_checker_t mc)
+{
+ mc_pages_store_delete(mc->pages);
+ if(mc->record)
+ xbt_dynar_free(&mc->record);
+ MC_process_clear(&mc->process);
+ xbt_dict_free(&mc->hosts);
+}
+
+unsigned long MC_smx_get_maxpid(void)
+{
+ if (mc_mode == MC_MODE_STANDALONE)
+ return simix_process_maxpid;
+
+ unsigned long maxpid;
+ MC_process_read_variable(&mc_model_checker->process, "simix_process_maxpid",
+ &maxpid, sizeof(maxpid));
+ return maxpid;
+}
#ifndef MC_MODEL_CHECKER_H
#define MC_MODEL_CHECKER_H
+#include <sys/types.h>
+
#include <simgrid_config.h>
+#include <xbt/dynar.h>
#include "mc_forward.h"
+#include "mc_process.h"
+#include "mc_page_store.h"
+#include "mc_protocol.h"
SG_BEGIN_DECL()
int fd_clear_refs;
int fd_pagemap;
xbt_dynar_t record;
+ s_mc_process_t process;
+ /** String pool for host names */
+ xbt_dict_t /* <hostname, NULL> */ hosts;
};
-mc_model_checker_t MC_model_checker_new(void);
+mc_model_checker_t MC_model_checker_new(pid_t pid, int socket);
void MC_model_checker_delete(mc_model_checker_t mc);
+unsigned long MC_smx_get_maxpid(void);
SG_END_DECL()
--- /dev/null
+#include <stddef.h>
+
+#include <xbt/dynar.h>
+
+#include "mc_object_info.h"
+#include "mc_private.h"
+
+dw_frame_t MC_file_object_info_find_function(mc_object_info_t info, const void *ip)
+{
+ xbt_dynar_t dynar = info->functions_index;
+ mc_function_index_item_t base =
+ (mc_function_index_item_t) xbt_dynar_get_ptr(dynar, 0);
+ int i = 0;
+ int j = xbt_dynar_length(dynar) - 1;
+ while (j >= i) {
+ int k = i + ((j - i) / 2);
+ if (ip < base[k].low_pc) {
+ j = k - 1;
+ } else if (ip >= base[k].high_pc) {
+ i = k + 1;
+ } else {
+ return base[k].function;
+ }
+ }
+ return NULL;
+}
+
+dw_variable_t MC_file_object_info_find_variable_by_name(mc_object_info_t info, const char* name)
+{
+ unsigned int cursor = 0;
+ dw_variable_t variable;
+ xbt_dynar_foreach(info->global_variables, cursor, variable){
+ if(!strcmp(name, variable->name))
+ return variable;
+ }
+
+ return NULL;
+}
#define MC_OBJECT_INFO_H
#include <stdint.h>
+#include <stdbool.h>
#include <simgrid_config.h>
#include <xbt/dict.h>
#include "mc_forward.h"
#include "mc_location.h"
+#include "mc_process.h"
+#include "../smpi/private.h"
SG_BEGIN_DECL();
struct s_mc_object_info {
enum mc_object_info_flags flags;
char* file_name;
+ const void* start, *end;
char *start_exec, *end_exec; // Executable segment
char *start_rw, *end_rw; // Read-write segment
char *start_ro, *end_ro; // read-only segment
xbt_dynar_t functions_index;
};
+static inline __attribute__ ((always_inline))
+bool MC_object_info_executable(mc_object_info_t info)
+{
+ return info->flags & MC_OBJECT_INFO_EXECUTABLE;
+}
+
+static inline __attribute__ ((always_inline))
+bool MC_object_info_is_privatized(mc_object_info_t info)
+{
+ return info && MC_object_info_executable(info) && smpi_privatize_global_variables;
+}
+
/** Find the DWARF offset for this ELF object
*
* An offset is applied to address found in DWARF:
void* MC_object_base_address(mc_object_info_t info);
mc_object_info_t MC_new_object_info(void);
-mc_object_info_t MC_find_object_info(memory_map_t maps, char* name, int executable);
+mc_object_info_t MC_find_object_info(memory_map_t maps, const char* name, int executable);
void MC_free_object_info(mc_object_info_t* p);
-void MC_post_process_object_info(mc_object_info_t info);
+dw_frame_t MC_file_object_info_find_function(mc_object_info_t info, const void *ip);
+dw_variable_t MC_file_object_info_find_variable_by_name(mc_object_info_t info, const char* name);
+
+void MC_post_process_object_info(mc_process_t process, mc_object_info_t info);
void MC_dwarf_get_variables(mc_object_info_t info);
void MC_dwarf_get_variables_libdw(mc_object_info_t info);
// Not used:
char* get_type_description(mc_object_info_t info, char *type_name);
-extern mc_object_info_t mc_libsimgrid_info;
-extern mc_object_info_t mc_binary_info;
-extern mc_object_info_t mc_object_infos[2];
-extern size_t mc_object_infos_size;
-
-void* mc_member_resolve(const void* base, dw_type_t type, dw_type_t member, mc_snapshot_t snapshot, int process_index);
+void* mc_member_resolve(const void* base, dw_type_t type, dw_type_t member, mc_address_space_t snapshot, int process_index);
struct s_dw_variable{
Dwarf_Off dwarf_offset; /* Global offset of the field. */
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <unistd.h> // pread, pwrite
+
#include "mc_page_store.h"
#include "mc_mmu.h"
#include "mc_private.h"
* @param reference_pages Snapshot page numbers of the previous soft_dirty_reset (or NULL)
* @return Snapshot page numbers of this new snapshot
*/
-size_t* mc_take_page_snapshot_region(void* data, size_t page_count, uint64_t* pagemap, size_t* reference_pages)
+size_t* mc_take_page_snapshot_region(mc_process_t process,
+ void* data, size_t page_count, uint64_t* pagemap, size_t* reference_pages)
{
size_t* pagenos = (size_t*) malloc(page_count * sizeof(size_t));
+ const bool is_self = MC_process_is_self(process);
+
+ void* temp = NULL;
+ if (!is_self)
+ temp = malloc(xbt_pagesize);
+
for (size_t i=0; i!=page_count; ++i) {
bool softclean = pagemap && !(pagemap[i] & SOFT_DIRTY);
if (softclean && reference_pages) {
// Otherwise, we need to store the page the hard way
// (by reading its content):
void* page = (char*) data + (i << xbt_pagebits);
- pagenos[i] = mc_model_checker->pages->store_page(page);
+ xbt_assert(mc_page_offset(page)==0, "Not at the beginning of a page");
+ void* page_data;
+ if (is_self) {
+ page_data = page;
+ } else {
+ /* Adding another copy (and a syscall) will probably slow things a lot.
+ TODO, optimize this somehow (at least by grouping the syscalls)
+ if needed. Either:
+ - reduce the number of syscalls;
+ - let the application snapshot itself;
+ - move the segments in shared memory (this will break `fork` however).
+ */
+ page_data = temp;
+ MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ temp, page, xbt_pagesize, MC_PROCESS_INDEX_DISABLED);
+ }
+ pagenos[i] = mc_model_checker->pages->store_page(page_data);
}
}
+ free(temp);
return pagenos;
}
* @param pagemap Linux kernel pagemap values fot this region (or NULL)
* @param reference_pages Snapshot page numbers of the previous soft_dirty_reset (or NULL)
*/
-void mc_restore_page_snapshot_region(void* start_addr, size_t page_count, size_t* pagenos, uint64_t* pagemap, size_t* reference_pagenos)
+void mc_restore_page_snapshot_region(mc_process_t process,
+ void* start_addr, size_t page_count, size_t* pagenos, uint64_t* pagemap, size_t* reference_pagenos)
{
for (size_t i=0; i!=page_count; ++i) {
// Otherwise, copy the page:
void* target_page = mc_page_from_number(start_addr, i);
const void* source_page = mc_model_checker->pages->get_page(pagenos[i]);
- memcpy(target_page, source_page, xbt_pagesize);
+ MC_process_write(process, source_page, target_page, xbt_pagesize);
}
}
// ***** High level API
-mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, void* permanent_addr, size_t size, mc_mem_region_t ref_reg)
+mc_mem_region_t mc_region_new_sparse(mc_region_type_t region_type,
+ void *start_addr, void* permanent_addr, size_t size,
+ mc_mem_region_t ref_reg)
{
- mc_mem_region_t new_reg = xbt_new(s_mc_mem_region_t, 1);
+ mc_process_t process = &mc_model_checker->process;
- new_reg->start_addr = start_addr;
- new_reg->permanent_addr = permanent_addr;
- new_reg->data = NULL;
- new_reg->size = size;
- new_reg->page_numbers = NULL;
+ mc_mem_region_t region = xbt_new(s_mc_mem_region_t, 1);
+ region->region_type = region_type;
+ region->storage_type = MC_REGION_STORAGE_TYPE_CHUNKED;
+ region->start_addr = start_addr;
+ region->permanent_addr = permanent_addr;
+ region->size = size;
xbt_assert((((uintptr_t)start_addr) & (xbt_pagesize-1)) == 0,
"Not at the beginning of a page");
size_t page_count = mc_page_count(size);
uint64_t* pagemap = NULL;
- if (_sg_mc_soft_dirty && mc_model_checker->parent_snapshot) {
- pagemap = (uint64_t*) mmalloc_no_memset(mc_heap, sizeof(uint64_t) * page_count);
+ if (_sg_mc_soft_dirty && mc_model_checker->parent_snapshot &&
+ MC_process_is_self(process)) {
+ pagemap = (uint64_t*) malloc_no_memset(sizeof(uint64_t) * page_count);
mc_read_pagemap(pagemap, mc_page_number(NULL, permanent_addr), page_count);
}
+ size_t* reg_page_numbers = NULL;
+ if (ref_reg!=NULL && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_CHUNKED)
+ reg_page_numbers = ref_reg->chunked.page_numbers;
+
// Take incremental snapshot:
- new_reg->page_numbers = mc_take_page_snapshot_region(permanent_addr, page_count, pagemap,
- ref_reg==NULL ? NULL : ref_reg->page_numbers);
+ region->chunked.page_numbers = mc_take_page_snapshot_region(process,
+ permanent_addr, page_count, pagemap, reg_page_numbers);
if(pagemap) {
mfree(mc_heap, pagemap);
}
- return new_reg;
+ return region;
}
-void mc_region_restore_sparse(mc_mem_region_t reg, mc_mem_region_t ref_reg)
+void mc_region_restore_sparse(mc_process_t process, mc_mem_region_t reg, mc_mem_region_t ref_reg)
{
xbt_assert((((uintptr_t)reg->permanent_addr) & (xbt_pagesize-1)) == 0,
"Not at the beginning of a page");
uint64_t* pagemap = NULL;
// Read soft-dirty bits if necessary in order to know which pages have changed:
- if (_sg_mc_soft_dirty && mc_model_checker->parent_snapshot) {
- pagemap = (uint64_t*) mmalloc_no_memset(mc_heap, sizeof(uint64_t) * page_count);
+ if (_sg_mc_soft_dirty && mc_model_checker->parent_snapshot
+ && MC_process_is_self(process)) {
+ pagemap = (uint64_t*) malloc_no_memset(sizeof(uint64_t) * page_count);
mc_read_pagemap(pagemap, mc_page_number(NULL, reg->permanent_addr), page_count);
}
- // Incremental per-page snapshot restoration:
- mc_restore_page_snapshot_region(reg->permanent_addr, page_count, reg->page_numbers,
- pagemap, ref_reg ? ref_reg->page_numbers : NULL);
+ // Incremental per-page snapshot restoration:s
+ size_t* reg_page_numbers = NULL;
+ if (ref_reg && ref_reg->storage_type == MC_REGION_STORAGE_TYPE_CHUNKED)
+ reg_page_numbers = ref_reg->chunked.page_numbers;
+
+ mc_restore_page_snapshot_region(process,
+ reg->permanent_addr, page_count, reg->chunked.page_numbers,
+ pagemap, reg_page_numbers);
if(pagemap) {
free(pagemap);
/** Store a page in memory */
size_t s_mc_pages_store::store_page(void* page)
{
- xbt_assert(mc_page_offset(page)==0, "Not at the beginning of a page");
xbt_assert(top_index_ <= this->capacity_, "top_index is not consistent");
// First, we check if a page with the same content is already in the page
{
xbt_test_add("Init");
size_t pagesize = (size_t) getpagesize();
- std::auto_ptr<s_mc_pages_store_t> store = std::auto_ptr<s_mc_pages_store_t>(new s_mc_pages_store(500));
+ std::unique_ptr<s_mc_pages_store_t> store = std::unique_ptr<s_mc_pages_store_t>(new s_mc_pages_store(500));
void* data = getpage();
xbt_test_assert(store->size()==0, "Bad size");
#ifndef MC_PRIVATE_H
#define MC_PRIVATE_H
+#include <sys/types.h>
+
#include "simgrid_config.h"
#include <stdio.h>
#include <stdint.h>
#include "mc/datatypes.h"
#include "xbt/fifo.h"
#include "xbt/config.h"
+
#include "xbt/function_types.h"
#include "xbt/mmalloc.h"
#include "../simix/smx_private.h"
#include "../xbt/mmalloc/mmprivate.h"
#include "xbt/automaton.h"
#include "xbt/hash.h"
-#include "simgrid/msg.h"
-#include "msg/datatypes.h"
+#include <simgrid/msg.h>
#include "xbt/strbuff.h"
#include "xbt/parmap.h"
#include "mc_forward.h"
+#include "mc_protocol.h"
SG_BEGIN_DECL()
typedef struct s_mc_function_index_item s_mc_function_index_item_t, *mc_function_index_item_t;
-/****************************** Snapshots ***********************************/
-
-extern xbt_dynar_t mc_checkpoint_ignore;
-
/********************************* MC Global **********************************/
+/** Initialisation of the model-checker
+ *
+ * @param pid PID of the target process
+ * @param socket FD for the communication socket **in server mode** (or -1 otherwise)
+ */
+void MC_init_pid(pid_t pid, int socket);
+
extern FILE *dot_output;
extern const char* colors[13];
extern xbt_parmap_t parmap;
void MC_print_statistics(mc_stats_t stats);
-extern char *libsimgrid_path;
-
/********************************** Snapshot comparison **********************************/
typedef struct s_mc_comparison_times{
double nb_processes_comparison_time;
double bytes_used_comparison_time;
double stacks_sizes_comparison_time;
- double binary_global_variables_comparison_time;
- double libsimgrid_global_variables_comparison_time;
+ double global_variables_comparison_time;
double heap_comparison_time;
double stacks_comparison_time;
}s_mc_comparison_times_t, *mc_comparison_times_t;
/********************************** Variables with DWARF **********************************/
-dw_frame_t MC_find_function_by_ip(void* ip);
-mc_object_info_t MC_ip_find_object_info(void* ip);
-
void MC_find_object_address(memory_map_t maps, mc_object_info_t result);
/********************************** Miscellaneous **********************************/
*/
void MC_dump_stacks(FILE* file);
+void MC_report_assertion_error(void);
+
SG_END_DECL()
#endif
--- /dev/null
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <regex.h>
+#include <sys/mman.h> // PROT_*
+
+#include <pthread.h>
+
+#include <libgen.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include <xbt/mmalloc.h>
+
+#include "mc_process.h"
+#include "mc_object_info.h"
+#include "mc_address_space.h"
+#include "mc_unw.h"
+#include "mc_snapshot.h"
+#include "mc_ignore.h"
+#include "mc_smx.h"
+#include "mc_server.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_process, mc,
+ "MC process information");
+
+static void MC_process_init_memory_map_info(mc_process_t process);
+static void MC_process_open_memory_file(mc_process_t process);
+
+// ***** Destructor callbacks
+
+// ***** mc_address_space methods for mc_process
+
+static mc_process_t MC_process_get_process(mc_process_t p) {
+ return p;
+}
+
+static const s_mc_address_space_class_t mc_process_class = {
+ .read = (void*) &MC_process_read,
+ .get_process = (void*) MC_process_get_process
+};
+
+bool MC_is_process(mc_address_space_t p)
+{
+ return p->address_space_class == &mc_process_class;
+}
+
+// ***** mc_process
+
+void MC_process_init(mc_process_t process, pid_t pid, int sockfd)
+{
+ process->address_space.address_space_class = &mc_process_class;
+ process->process_flags = MC_PROCESS_NO_FLAG;
+ process->socket = sockfd;
+ process->pid = pid;
+ if (pid==getpid())
+ process->process_flags |= MC_PROCESS_SELF_FLAG;
+ process->running = true;
+ process->status = 0;
+ process->memory_map = MC_get_memory_map(pid);
+ process->memory_file = -1;
+ process->cache_flags = 0;
+ process->heap = NULL;
+ process->heap_info = NULL;
+ MC_process_init_memory_map_info(process);
+ MC_process_open_memory_file(process);
+
+ // Read std_heap (is a struct mdesc*):
+ dw_variable_t std_heap_var = MC_process_find_variable_by_name(process, "std_heap");
+ if (!std_heap_var)
+ xbt_die("No heap information in the target process");
+ if(!std_heap_var->address)
+ xbt_die("No constant address for this variable");
+ MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ &process->heap_address, std_heap_var->address, sizeof(struct mdesc*),
+ MC_PROCESS_INDEX_DISABLED);
+
+ process->smx_process_infos = MC_smx_process_info_list_new();
+ process->smx_old_process_infos = MC_smx_process_info_list_new();
+
+ process->checkpoint_ignore = MC_checkpoint_ignore_new();
+
+ process->unw_addr_space = unw_create_addr_space(&mc_unw_accessors , __BYTE_ORDER);
+ if (process->process_flags & MC_PROCESS_SELF_FLAG) {
+ process->unw_underlying_addr_space = unw_local_addr_space;
+ process->unw_underlying_context = NULL;
+ } else {
+ process->unw_underlying_addr_space = unw_create_addr_space(&mc_unw_vmread_accessors, __BYTE_ORDER);
+ process->unw_underlying_context = _UPT_create(pid);
+ }
+}
+
+void MC_process_clear(mc_process_t process)
+{
+ process->address_space.address_space_class = NULL;
+ process->process_flags = MC_PROCESS_NO_FLAG;
+ process->pid = 0;
+
+ MC_free_memory_map(process->memory_map);
+ process->memory_map = NULL;
+
+ process->maestro_stack_start = NULL;
+ process->maestro_stack_end = NULL;
+
+ xbt_dynar_free(&process->checkpoint_ignore);
+
+ xbt_dynar_free(&process->smx_process_infos);
+ xbt_dynar_free(&process->smx_old_process_infos);
+
+ size_t i;
+ for (i=0; i!=process->object_infos_size; ++i) {
+ MC_free_object_info(&process->object_infos[i]);
+ }
+ free(process->object_infos);
+ process->object_infos = NULL;
+ process->object_infos_size = 0;
+ if (process->memory_file >= 0) {
+ close(process->memory_file);
+ }
+
+ if (process->unw_underlying_addr_space != unw_local_addr_space) {
+ unw_destroy_addr_space(process->unw_underlying_addr_space);
+ _UPT_destroy(process->unw_underlying_context);
+ }
+ process->unw_underlying_context = NULL;
+ process->unw_underlying_addr_space = NULL;
+
+ unw_destroy_addr_space(process->unw_addr_space);
+ process->unw_addr_space = NULL;
+
+ process->cache_flags = 0;
+
+ free(process->heap);
+ process->heap = NULL;
+
+ free(process->heap_info);
+ process->heap_info = NULL;
+}
+
+void MC_process_refresh_heap(mc_process_t process)
+{
+ assert(!MC_process_is_self(process));
+ // Read/dereference/refresh the std_heap pointer:
+ if (!process->heap) {
+ xbt_mheap_t oldheap = mmalloc_set_current_heap(mc_heap);
+ process->heap = malloc(sizeof(struct mdesc));
+ mmalloc_set_current_heap(oldheap);
+ }
+ MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ process->heap, process->heap_address, sizeof(struct mdesc),
+ MC_PROCESS_INDEX_DISABLED
+ );
+}
+
+void MC_process_refresh_malloc_info(mc_process_t process)
+{
+ assert(!MC_process_is_self(process));
+ if (!(process->cache_flags & MC_PROCESS_CACHE_FLAG_HEAP))
+ MC_process_refresh_heap(process);
+ // Refresh process->heapinfo:
+ size_t malloc_info_bytesize =
+ (process->heap->heaplimit + 1) * sizeof(malloc_info);
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ process->heap_info = realloc(process->heap_info, malloc_info_bytesize);
+ mmalloc_set_current_heap(heap);
+
+ MC_process_read(process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ process->heap_info,
+ process->heap->heapinfo, malloc_info_bytesize,
+ MC_PROCESS_INDEX_DISABLED);
+}
+
+#define SO_RE "\\.so[\\.0-9]*$"
+#define VERSION_RE "-[\\.0-9]*$"
+
+const char* FILTERED_LIBS[] = {
+ "libstdc++",
+ "libc++",
+ "libm",
+ "libgcc_s",
+ "libpthread",
+ "libunwind",
+ "libunwind-x86_64",
+ "libunwind-x86",
+ "libunwind-ptrace",
+ "libdw",
+ "libdl",
+ "librt",
+ "liblzma",
+ "libelf",
+ "libbz2",
+ "libz",
+ "libelf",
+ "libc",
+ "ld"
+};
+
+static bool MC_is_simgrid_lib(const char* libname)
+{
+ return !strcmp(libname, "libsimgrid");
+}
+
+static bool MC_is_filtered_lib(const char* libname)
+{
+ const size_t n = sizeof(FILTERED_LIBS) / sizeof(const char*);
+ size_t i;
+ for (i=0; i!=n; ++i)
+ if (strcmp(libname, FILTERED_LIBS[i])==0)
+ return true;
+ return false;
+}
+
+struct s_mc_memory_map_re {
+ regex_t so_re;
+ regex_t version_re;
+};
+
+static char* MC_get_lib_name(const char* pathname, struct s_mc_memory_map_re* res) {
+ const char* map_basename = basename((char*) pathname);
+
+ regmatch_t match;
+ if(regexec(&res->so_re, map_basename, 1, &match, 0))
+ return NULL;
+
+ char* libname = strndup(map_basename, match.rm_so);
+
+ // Strip the version suffix:
+ if(libname && !regexec(&res->version_re, libname, 1, &match, 0)) {
+ char* temp = libname;
+ libname = strndup(temp, match.rm_so);
+ free(temp);
+ }
+
+ return libname;
+}
+
+/** @brief Finds the range of the different memory segments and binary paths */
+static void MC_process_init_memory_map_info(mc_process_t process)
+{
+ XBT_DEBUG("Get debug information ...");
+ process->maestro_stack_start = NULL;
+ process->maestro_stack_end = NULL;
+ process->object_infos = NULL;
+ process->object_infos_size = 0;
+ process->binary_info = NULL;
+ process->libsimgrid_info = NULL;
+
+ struct s_mc_memory_map_re res;
+
+ if(regcomp(&res.so_re, SO_RE, 0) || regcomp(&res.version_re, VERSION_RE, 0))
+ xbt_die(".so regexp did not compile");
+
+ memory_map_t maps = process->memory_map;
+
+ const char* current_name = NULL;
+
+ size_t i = 0;
+ for (i=0; i < maps->mapsize; i++) {
+ map_region_t reg = &(maps->regions[i]);
+ const char* pathname = maps->regions[i].pathname;
+
+ // Nothing to do
+ if (maps->regions[i].pathname == NULL) {
+ current_name = NULL;
+ continue;
+ }
+
+ // [stack], [vvar], [vsyscall], [vdso] ...
+ if (pathname[0] == '[') {
+ if ((reg->prot & PROT_WRITE) && !memcmp(pathname, "[stack]", 7)) {
+ process->maestro_stack_start = reg->start_addr;
+ process->maestro_stack_end = reg->end_addr;
+ }
+ current_name = NULL;
+ continue;
+ }
+
+ if (current_name && strcmp(current_name, pathname)==0)
+ continue;
+
+ current_name = pathname;
+ if (!(reg->prot & PROT_READ) && (reg->prot & PROT_EXEC))
+ continue;
+
+ const bool is_executable = !i;
+ char* libname = NULL;
+ if (!is_executable) {
+ libname = MC_get_lib_name(pathname, &res);
+ if(!libname)
+ continue;
+ if (MC_is_filtered_lib(libname)) {
+ free(libname);
+ continue;
+ }
+ }
+
+ mc_object_info_t info =
+ MC_find_object_info(process->memory_map, pathname, is_executable);
+ process->object_infos = (mc_object_info_t*) realloc(process->object_infos,
+ (process->object_infos_size+1) * sizeof(mc_object_info_t*));
+ process->object_infos[process->object_infos_size] = info;
+ process->object_infos_size++;
+ if (is_executable)
+ process->binary_info = info;
+ else if (libname && MC_is_simgrid_lib(libname))
+ process->libsimgrid_info = info;
+ free(libname);
+ }
+
+ regfree(&res.so_re);
+ regfree(&res.version_re);
+
+ // Resolve time (including accress differents objects):
+ for (i=0; i!=process->object_infos_size; ++i)
+ MC_post_process_object_info(process, process->object_infos[i]);
+
+ xbt_assert(process->maestro_stack_start, "Did not find maestro_stack_start");
+ xbt_assert(process->maestro_stack_end, "Did not find maestro_stack_end");
+
+ XBT_DEBUG("Get debug information done !");
+}
+
+mc_object_info_t MC_process_find_object_info(mc_process_t process, const void *addr)
+{
+ size_t i;
+ for (i = 0; i != process->object_infos_size; ++i) {
+ if (addr >= (void *) process->object_infos[i]->start
+ && addr <= (void *) process->object_infos[i]->end) {
+ return process->object_infos[i];
+ }
+ }
+ return NULL;
+}
+
+mc_object_info_t MC_process_find_object_info_exec(mc_process_t process, const void *addr)
+{
+ size_t i;
+ for (i = 0; i != process->object_infos_size; ++i) {
+ if (addr >= (void *) process->object_infos[i]->start_exec
+ && addr <= (void *) process->object_infos[i]->end_exec) {
+ return process->object_infos[i];
+ }
+ }
+ return NULL;
+}
+
+mc_object_info_t MC_process_find_object_info_rw(mc_process_t process, const void *addr)
+{
+ size_t i;
+ for (i = 0; i != process->object_infos_size; ++i) {
+ if (addr >= (void *) process->object_infos[i]->start_rw
+ && addr <= (void *) process->object_infos[i]->end_rw) {
+ return process->object_infos[i];
+ }
+ }
+ return NULL;
+}
+
+// Functions, variables…
+
+dw_frame_t MC_process_find_function(mc_process_t process, const void *ip)
+{
+ mc_object_info_t info = MC_process_find_object_info_exec(process, ip);
+ if (info == NULL)
+ return NULL;
+ else
+ return MC_file_object_info_find_function(info, ip);
+}
+
+dw_variable_t MC_process_find_variable_by_name(mc_process_t process, const char* name)
+{
+ const size_t n = process->object_infos_size;
+ size_t i;
+
+ // First lookup the variable in the executable shared object.
+ // A global variable used directly by the executable code from a library
+ // is reinstanciated in the executable memory .data/.bss.
+ // We need to look up the variable in the execvutable first.
+ if (process->binary_info) {
+ mc_object_info_t info = process->binary_info;
+ dw_variable_t var = MC_file_object_info_find_variable_by_name(info, name);
+ if (var)
+ return var;
+ }
+
+ for (i=0; i!=n; ++i) {
+ mc_object_info_t info =process->object_infos[i];
+ dw_variable_t var = MC_file_object_info_find_variable_by_name(info, name);
+ if (var)
+ return var;
+ }
+
+ return NULL;
+}
+
+void MC_process_read_variable(mc_process_t process, const char* name, void* target, size_t size)
+{
+ dw_variable_t var = MC_process_find_variable_by_name(process, name);
+ if (!var->address)
+ xbt_die("No simple location for this variable");
+ if (!var->type->full_type)
+ xbt_die("Partial type for %s, cannot check size", name);
+ if (var->type->full_type->byte_size != size)
+ xbt_die("Unexpected size for %s (expected %zi, was %zi)",
+ name, size, (size_t) var->type->full_type->byte_size);
+ MC_process_read(process, MC_PROCESS_NO_FLAG, target, var->address, size,
+ MC_PROCESS_INDEX_ANY);
+}
+
+char* MC_process_read_string(mc_process_t process, void* address)
+{
+ if (!address)
+ return NULL;
+ if (MC_process_is_self(process))
+ return strdup((char*) address);
+
+ size_t len = 128;
+ char* res = malloc(len);
+ off_t off = 0;
+
+ while (1) {
+ ssize_t c = pread(process->memory_file, res + off, len - off, (off_t) address + off);
+ if (c == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ xbt_die("Could not read from from remote process");
+ }
+ if (c==0)
+ xbt_die("Could not read string from remote process");
+
+ void* p = memchr(res + off, '\0', c);
+ if (p)
+ return res;
+
+ off += c;
+ if (off == len) {
+ len *= 2;
+ res = realloc(res, len);
+ }
+ }
+}
+
+// ***** Memory access
+
+int MC_process_vm_open(pid_t pid, int flags)
+{
+ const size_t buffer_size = 30;
+ char buffer[buffer_size];
+ int res = snprintf(buffer, buffer_size, "/proc/%lli/mem", (long long) pid);
+ if (res < 0 || res >= buffer_size) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+ return open(buffer, flags);
+}
+
+static void MC_process_open_memory_file(mc_process_t process)
+{
+ if (MC_process_is_self(process) || process->memory_file >= 0)
+ return;
+
+ int fd = MC_process_vm_open(process->pid, O_RDWR);
+ if (fd<0)
+ xbt_die("Could not open file for process virtual address space");
+ process->memory_file = fd;
+}
+
+static ssize_t pread_whole(int fd, void *buf, size_t count, off_t offset)
+{
+ char* buffer = (char*) buf;
+ ssize_t real_count = count;
+ while (count) {
+ ssize_t res = pread(fd, buffer, count, offset);
+ if (res > 0) {
+ count -= res;
+ buffer += res;
+ offset += res;
+ } else if (res==0) {
+ return -1;
+ } else if (errno != EINTR) {
+ return -1;
+ }
+ }
+ return real_count;
+}
+
+static ssize_t pwrite_whole(int fd, const void *buf, size_t count, off_t offset)
+{
+ const char* buffer = (const char*) buf;
+ ssize_t real_count = count;
+ while (count) {
+ ssize_t res = pwrite(fd, buffer, count, offset);
+ if (res > 0) {
+ count -= res;
+ buffer += res;
+ offset += res;
+ } else if (res==0) {
+ return -1;
+ } else if (errno != EINTR) {
+ return -1;
+ }
+ }
+ return real_count;
+}
+
+const void* MC_process_read(mc_process_t process, e_adress_space_read_flags_t flags,
+ void* local, const void* remote, size_t len,
+ int process_index)
+{
+ if (process_index != MC_PROCESS_INDEX_DISABLED) {
+ mc_object_info_t info = MC_process_find_object_info_rw(process, remote);
+ // Segment overlap is not handled.
+ if (MC_object_info_is_privatized(info)) {
+ if (process_index < 0)
+ xbt_die("Missing process index");
+ // Address translation in the privaization segment:
+ size_t offset = (const char*) remote - info->start_rw;
+ remote = (const char*) remote - offset;
+ }
+ }
+
+ if (MC_process_is_self(process)) {
+ if (flags & MC_ADDRESS_SPACE_READ_FLAGS_LAZY)
+ return remote;
+ else {
+ memcpy(local, remote, len);
+ return local;
+ }
+ } else {
+ if (pread_whole(process->memory_file, local, len, (off_t) remote) < 0)
+ xbt_die("Read from process %lli failed", (long long) process->pid);
+ return local;
+ }
+}
+
+const void* MC_process_read_simple(mc_process_t process,
+ void* local, const void* remote, size_t len)
+{
+ e_adress_space_read_flags_t flags = MC_PROCESS_NO_FLAG;
+ int index = MC_PROCESS_INDEX_ANY;
+ MC_process_read(process, flags, local, remote, len, index);
+ return local;
+}
+
+const void* MC_process_read_dynar_element(mc_process_t process,
+ void* local, const void* remote_dynar, size_t i, size_t len)
+{
+ s_xbt_dynar_t d;
+ MC_process_read_simple(process, &d, remote_dynar, sizeof(d));
+ if (i >= d.used)
+ xbt_die("Out of bound index %zi/%zi", i, d.used);
+ if (len != d.elmsize)
+ xbt_die("Bad size in MC_process_read_dynar_element");
+ MC_process_read_simple(process, local, xbt_dynar_get_ptr(&d, i), len);
+ return local;
+}
+
+void MC_process_write(mc_process_t process, const void* local, void* remote, size_t len)
+{
+ if (MC_process_is_self(process)) {
+ memcpy(remote, local, len);
+ } else {
+ if (pwrite_whole(process->memory_file, local, len, (off_t) remote) < 0)
+ xbt_die("Write to process %lli failed", (long long) process->pid);
+ }
+}
+
+unsigned long MC_process_read_dynar_length(mc_process_t process, const void* remote_dynar)
+{
+ if (!remote_dynar)
+ return 0;
+ unsigned long res;
+ MC_process_read_simple(process, &res,
+ &((xbt_dynar_t)remote_dynar)->used, sizeof(res));
+ return res;
+}
+
+static pthread_once_t zero_buffer_flag = PTHREAD_ONCE_INIT;
+static const void* zero_buffer;
+static const int zero_buffer_size = 10 * 4096;
+
+static void MC_zero_buffer_init(void)
+{
+ int fd = open("/dev/zero", O_RDONLY);
+ if (fd<0)
+ xbt_die("Could not open /dev/zero");
+ zero_buffer = mmap(NULL, zero_buffer_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (zero_buffer == MAP_FAILED)
+ xbt_die("Could not map the zero buffer");
+ close(fd);
+}
+
+void MC_process_clear_memory(mc_process_t process, void* remote, size_t len)
+{
+ if (MC_process_is_self(process)) {
+ memset(remote, 0, len);
+ } else {
+ pthread_once(&zero_buffer_flag, MC_zero_buffer_init);
+ while (len) {
+ size_t s = len > zero_buffer_size ? zero_buffer_size : len;
+ MC_process_write(process, zero_buffer, remote, s);
+ remote = (char*) remote + s;
+ len -= s;
+ }
+ }
+}
+
+void MC_simcall_handle(smx_simcall_t req, int value)
+{
+ if (MC_process_is_self(&mc_model_checker->process)) {
+ SIMIX_simcall_handle(req, value);
+ return;
+ }
+
+ unsigned i;
+ mc_smx_process_info_t pi = NULL;
+
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_process_infos, i, pi) {
+ if (req == &pi->copy.simcall) {
+ MC_server_simcall_handle(&mc_model_checker->process, pi->copy.pid, value);
+ return;
+ }
+ }
+
+ xbt_die("Could not find the request");
+}
--- /dev/null
+/* Copyright (c) 2008-2014. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_PROCESS_H
+#define MC_PROCESS_H
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include "simgrid_config.h"
+
+#include <sys/types.h>
+
+#include <xbt/mmalloc.h>
+
+#ifdef HAVE_MC
+#include "xbt/mmalloc/mmprivate.h"
+#endif
+
+#include "simix/popping_private.h"
+#include "simix/smx_private.h"
+
+#include "mc_forward.h"
+#include "mc_mmalloc.h" // std_heap
+#include "mc_memory_map.h"
+#include "mc_address_space.h"
+#include "mc_protocol.h"
+
+SG_BEGIN_DECL()
+
+int MC_process_vm_open(pid_t pid, int flags);
+
+typedef enum {
+ MC_PROCESS_NO_FLAG = 0,
+ MC_PROCESS_SELF_FLAG = 1,
+} e_mc_process_flags_t;
+
+// Those flags are used to track down which cached information
+// is still up to date and which information needs to be updated.
+typedef enum {
+ MC_PROCESS_CACHE_FLAG_HEAP = 1,
+ MC_PROCESS_CACHE_FLAG_MALLOC_INFO = 2,
+ MC_PROCESS_CACHE_FLAG_SIMIX_PROCESSES = 4,
+} e_mc_process_cache_flags_t ;
+
+typedef struct s_mc_smx_process_info s_mc_smx_process_info_t, *mc_smx_process_info_t;
+
+/** Representation of a process
+ */
+struct s_mc_process {
+ s_mc_address_space_t address_space;
+ e_mc_process_flags_t process_flags;
+ pid_t pid;
+ int socket;
+ int status;
+ bool running;
+ memory_map_t memory_map;
+ void *maestro_stack_start, *maestro_stack_end;
+ mc_object_info_t libsimgrid_info;
+ mc_object_info_t binary_info;
+ mc_object_info_t* object_infos;
+ size_t object_infos_size;
+ int memory_file;
+
+ /** Copy of `simix_global->process_list`
+ *
+ * See mc_smx.c.
+ */
+ xbt_dynar_t smx_process_infos;
+
+ /** Copy of `simix_global->process_to_destroy`
+ *
+ * See mc_smx.c.
+ */
+ xbt_dynar_t smx_old_process_infos;
+
+ /** State of the cache (which variables are up to date) */
+ e_mc_process_cache_flags_t cache_flags;
+
+ /** Address of the heap structure in the MCed process. */
+ void* heap_address;
+
+ /** Copy of the heap structure of the process
+ *
+ * This is refreshed with the `MC_process_refresh` call.
+ * This is not used if the process is the current one:
+ * use `MC_process_get_heap_info` in order to use it.
+ */
+ xbt_mheap_t heap;
+
+ /** Copy of the allocation info structure
+ *
+ * This is refreshed with the `MC_process_refresh` call.
+ * This is not used if the process is the current one:
+ * use `MC_process_get_malloc_info` in order to use it.
+ */
+ malloc_info* heap_info;
+
+ // ***** Libunwind-data
+
+ /** Full-featured MC-aware libunwind address space for the process
+ *
+ * This address space is using a mc_unw_context_t
+ * (with mc_process_t/mc_address_space_t and unw_context_t).
+ */
+ unw_addr_space_t unw_addr_space;
+
+ /** Underlying libunwind addres-space
+ *
+ * The `find_proc_info`, `put_unwind_info`, `get_dyn_info_list_addr`
+ * operations of the native MC address space is currently delegated
+ * to this address space (either the local or a ptrace unwinder).
+ */
+ unw_addr_space_t unw_underlying_addr_space;
+
+ /** The corresponding context
+ */
+ void* unw_underlying_context;
+
+ xbt_dynar_t checkpoint_ignore;
+};
+
+bool MC_is_process(mc_address_space_t p);
+
+void MC_process_init(mc_process_t process, pid_t pid, int sockfd);
+void MC_process_clear(mc_process_t process);
+
+/** Refresh the information about the process
+ *
+ * Do not use direclty, this is used by the getters when appropriate
+ * in order to have fresh data.
+ */
+void MC_process_refresh_heap(mc_process_t process);
+
+/** Refresh the information about the process
+ *
+ * Do not use direclty, this is used by the getters when appropriate
+ * in order to have fresh data.
+ * */
+void MC_process_refresh_malloc_info(mc_process_t process);
+
+static inline
+bool MC_process_is_self(mc_process_t process)
+{
+ return process->process_flags & MC_PROCESS_SELF_FLAG;
+}
+
+/* Process memory access: */
+
+/** Read data from a process memory
+ *
+ * @param process the process
+ * @param local local memory address (destination)
+ * @param remote target process memory address (source)
+ * @param len data size
+ */
+const void* MC_process_read(mc_process_t process,
+ e_adress_space_read_flags_t flags,
+ void* local, const void* remote, size_t len,
+ int process_index);
+
+// Simplified versions/wrappers (whould be moved in mc_address_space):
+const void* MC_process_read_simple(mc_process_t process,
+ void* local, const void* remote, size_t len);
+const void* MC_process_read_dynar_element(mc_process_t process,
+ void* local, const void* remote_dynar, size_t i, size_t len);
+unsigned long MC_process_read_dynar_length(mc_process_t process, const void* remote_dynar);
+
+/** Write data to a process memory
+ *
+ * @param process the process
+ * @param local local memory address (source)
+ * @param remote target process memory address (target)
+ * @param len data size
+ */
+void MC_process_write(mc_process_t process, const void* local, void* remote, size_t len);
+
+void MC_process_clear_memory(mc_process_t process, void* remote, size_t len);
+
+/* Functions, variables of the process: */
+
+mc_object_info_t MC_process_find_object_info(mc_process_t process, const void* addr);
+mc_object_info_t MC_process_find_object_info_exec(mc_process_t process, const void* addr);
+mc_object_info_t MC_process_find_object_info_rw(mc_process_t process, const void* addr);
+
+dw_frame_t MC_process_find_function(mc_process_t process, const void* ip);
+
+void MC_process_read_variable(mc_process_t process, const char* name, void* target, size_t size);
+char* MC_process_read_string(mc_process_t, void* address);
+
+static inline xbt_mheap_t MC_process_get_heap(mc_process_t process)
+{
+ if (MC_process_is_self(process))
+ return std_heap;
+ if (!(process->cache_flags & MC_PROCESS_CACHE_FLAG_HEAP))
+ MC_process_refresh_heap(process);
+ return process->heap;
+}
+
+static inline malloc_info* MC_process_get_malloc_info(mc_process_t process)
+{
+ if (MC_process_is_self(process))
+ return std_heap->heapinfo;
+ if (!(process->cache_flags & MC_PROCESS_CACHE_FLAG_MALLOC_INFO))
+ MC_process_refresh_malloc_info(process);
+ return process->heap_info;
+}
+
+/** Find (one occurence of) the named variable definition
+ */
+dw_variable_t MC_process_find_variable_by_name(mc_process_t process, const char* name);
+
+SG_END_DECL()
+
+#endif
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <errno.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <xbt/log.h>
+
+#include "mc_protocol.h"
+#include "mc_client.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_protocol, mc, "Generic MC protocol logic");
+
+int MC_protocol_send(int socket, void* message, size_t size)
+{
+ XBT_DEBUG("Protocol [%s] send %s",
+ MC_mode_name(mc_mode),
+ MC_message_type_name(*(e_mc_message_type*) message));
+
+ while (send(socket, message, size, 0) == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ return errno;
+ }
+ return 0;
+}
+
+int MC_protocol_send_simple_message(int socket, int type)
+{
+ s_mc_message_t message;
+ message.type = type;
+ return MC_protocol_send(socket, &message, sizeof(message));
+}
+
+int MC_protocol_hello(int socket)
+{
+ int e;
+ if ((e = MC_protocol_send_simple_message(socket, MC_MESSAGE_HELLO)) != 0) {
+ XBT_ERROR("Could not send HELLO message");
+ return 1;
+ }
+
+ s_mc_message_t message;
+ message.type = MC_MESSAGE_NONE;
+
+ size_t s;
+ while ((s = MC_receive_message(socket, &message, sizeof(message), 0)) == -1) {
+ if (errno == EINTR)
+ continue;
+ else {
+ XBT_ERROR("Could not receive HELLO message");
+ return 2;
+ }
+ }
+ if (s < sizeof(message) || message.type != MC_MESSAGE_HELLO) {
+ XBT_ERROR("Did not receive suitable HELLO message. Who are you?");
+ return 3;
+ }
+
+ return 0;
+}
+
+ssize_t MC_receive_message(int socket, void* message, size_t size, int options)
+{
+ int res = recv(socket, message, size, options);
+ if (res != -1) {
+ XBT_DEBUG("Protocol [%s] received %s",
+ MC_mode_name(mc_mode),
+ MC_message_type_name(*(e_mc_message_type*) message));
+ }
+ return res;
+}
+
+const char* MC_message_type_name(e_mc_message_type type)
+{
+ switch(type) {
+ case MC_MESSAGE_NONE:
+ return "NONE";
+ case MC_MESSAGE_HELLO:
+ return "HELLO";
+ case MC_MESSAGE_CONTINUE:
+ return "CONTINUE";
+ case MC_MESSAGE_IGNORE_HEAP:
+ return "IGNORE_HEAP";
+ case MC_MESSAGE_UNIGNORE_HEAP:
+ return "UNIGNORE_HEAP";
+ case MC_MESSAGE_IGNORE_MEMORY:
+ return "IGNORE_MEMORY";
+ case MC_MESSAGE_STACK_REGION:
+ return "STACK_REGION";
+ case MC_MESSAGE_REGISTER_SYMBOL:
+ return "REGISTER_SYMBOL";
+ case MC_MESSAGE_DEADLOCK_CHECK:
+ return "DEADLOCK_CHECK";
+ case MC_MESSAGE_DEADLOCK_CHECK_REPLY:
+ return "DEADLOCK_CHECK_REPLY";
+ case MC_MESSAGE_WAITING:
+ return "WAITING";
+ case MC_MESSAGE_SIMCALL_HANDLE:
+ return "SIMCALL_HANDLE";
+ case MC_MESSAGE_ASSERTION_FAILED:
+ return "ASSERTION_FAILED";
+ default:
+ return "?";
+ }
+}
+
+const char* MC_mode_name(e_mc_mode_t mode)
+{
+ switch(mode) {
+ case MC_MODE_NONE:
+ return "NONE";
+ case MC_MODE_STANDALONE:
+ return "STANDALONE";
+ case MC_MODE_CLIENT:
+ return "CLIENT";
+ case MC_MODE_SERVER:
+ return "SERVER";
+ default:
+ return "?";
+ }
+}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_PROTOCOL_H
+#define MC_PROTOCOL_H
+
+#include <xbt/misc.h>
+
+#include "mc/datatypes.h"
+
+SG_BEGIN_DECL()
+
+// ***** Environment variables for passing context to the model-checked process
+
+/** Environment variable name set by `simgrid-mc` to enable MC support in the
+ * children MC processes
+ */
+#define MC_ENV_VARIABLE "SIMGRIC_MC"
+
+/** Environment variable name used to pass the communication socket */
+#define MC_ENV_SOCKET_FD "SIMGRID_MC_SOCKET_FD"
+
+// ***** MC mode
+
+typedef enum {
+ MC_MODE_NONE = 0,
+ MC_MODE_STANDALONE,
+ MC_MODE_CLIENT,
+ MC_MODE_SERVER
+} e_mc_mode_t;
+
+extern e_mc_mode_t mc_mode;
+
+// ***** Messages
+
+typedef enum {
+ MC_MESSAGE_NONE,
+ MC_MESSAGE_HELLO,
+ MC_MESSAGE_CONTINUE,
+ MC_MESSAGE_IGNORE_HEAP,
+ MC_MESSAGE_UNIGNORE_HEAP,
+ MC_MESSAGE_IGNORE_MEMORY,
+ MC_MESSAGE_STACK_REGION,
+ MC_MESSAGE_REGISTER_SYMBOL,
+ MC_MESSAGE_DEADLOCK_CHECK,
+ MC_MESSAGE_DEADLOCK_CHECK_REPLY,
+ MC_MESSAGE_WAITING,
+ MC_MESSAGE_SIMCALL_HANDLE,
+ MC_MESSAGE_ASSERTION_FAILED,
+} e_mc_message_type;
+
+#define MC_MESSAGE_LENGTH 512
+
+/** Basic structure for a MC message
+ *
+ * The current version of the client/server protocol sends C structures over `AF_LOCAL`
+ * `SOCK_DGRAM` sockets. This means that the protocol is ABI/architecture specific:
+ * we currently can't model-check a x86 process from a x86_64 process.
+ *
+ * Moreover the protocol is not stable. The same version of the library should be used
+ * for the client and the server.
+ *
+ * This is the basic structure shared by all messages: all message start with a message
+ * type.
+ */
+typedef struct s_mc_message {
+ e_mc_message_type type;
+} s_mc_message_t, *mc_message_t;
+
+typedef struct s_mc_int_message {
+ e_mc_message_type type;
+ uint64_t value;
+} s_mc_int_message_t, *mc_int_message_t;
+
+typedef struct s_mc_ignore_heap_message {
+ e_mc_message_type type;
+ s_mc_heap_ignore_region_t region;
+} s_mc_ignore_heap_message_t, *mc_ignore_heap_message_t;
+
+typedef struct s_mc_ignore_memory_message {
+ e_mc_message_type type;
+ void *addr;
+ size_t size;
+} s_mc_ignore_memory_message_t, *mc_ignore_memory_message_t;
+
+typedef struct s_mc_stack_region_message {
+ e_mc_message_type type;
+ s_stack_region_t stack_region;
+} s_mc_stack_region_message_t, *mc_stack_region_message_t;
+
+typedef struct s_mc_simcall_handle_message {
+ e_mc_message_type type;
+ unsigned long pid;
+ int value;
+} s_mc_simcall_handle_message_t, *mc_simcall_handle_message;
+
+typedef struct s_mc_register_symbol_message {
+ e_mc_message_type type;
+ char name[128];
+ int (*callback)(void*);
+ void* data;
+} s_mc_register_symbol_message_t, * mc_register_symbol_message_t;
+
+int MC_protocol_send(int socket, void* message, size_t size);
+int MC_protocol_send_simple_message(int socket, int type);
+int MC_protocol_hello(int socket);
+ssize_t MC_receive_message(int socket, void* message, size_t size, int options);
+
+const char* MC_message_type_name(e_mc_message_type type);
+const char* MC_mode_name(e_mc_mode_t mode);
+
+SG_END_DECL()
+
+#endif
#include "mc_private.h"
#include "mc_model_checker.h"
#include "mc_state.h"
+#include "mc_smx.h"
#endif
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_record, mc,
mc_state_t state = (mc_state_t) xbt_fifo_get_item_content(item);
int value = 0;
smx_simcall_t saved_req = MC_state_get_executed_request(state, &value);
- int pid = saved_req->issuer->pid;
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(saved_req);
+ const int pid = issuer->pid;
// Serialization the (pid, value) pair:
const char* sep = (item!=start) ? ";" : "";
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <assert.h>
+
#include "mc_request.h"
#include "mc_safety.h"
#include "mc_private.h"
+#include "mc_smx.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_request, mc,
"Logging specific to MC (request)");
static char *pointer_to_string(void *pointer);
static char *buff_size_to_string(size_t size);
+// Those are MC_state_get_internal_request(state)
int MC_request_depend(smx_simcall_t r1, smx_simcall_t r2)
{
if (mc_reduce_kind == e_mc_reduce_none)
if (r1->call == SIMCALL_COMM_IRECV && r2->call == SIMCALL_COMM_ISEND)
return FALSE;
+ // Those are internal requests, we do not need indirection
+ // because those objects are copies:
+ smx_synchro_t synchro1, synchro2;
+ if (r1->call == SIMCALL_COMM_WAIT) {
+ synchro1 = simcall_comm_wait__get__comm(r1);
+ }
+ if (r2->call == SIMCALL_COMM_WAIT) {
+ synchro2 = simcall_comm_wait__get__comm(r2);
+ }
+ if (r1->call == SIMCALL_COMM_TEST) {
+ synchro1 = simcall_comm_test__get__comm(r1);
+ }
+ if (r2->call == SIMCALL_COMM_TEST) {
+ synchro2 = simcall_comm_test__get__comm(r2);
+ }
+
if ((r1->call == SIMCALL_COMM_ISEND || r1->call == SIMCALL_COMM_IRECV)
&& r2->call == SIMCALL_COMM_WAIT) {
SIMCALL_COMM_ISEND ? simcall_comm_isend__get__rdv(r1) :
simcall_comm_irecv__get__rdv(r1);
- if (rdv != simcall_comm_wait__get__comm(r2)->comm.rdv_cpy
+ if (rdv != synchro2->comm.rdv_cpy
&& simcall_comm_wait__get__timeout(r2) <= 0)
return FALSE;
- if ((r1->issuer != simcall_comm_wait__get__comm(r2)->comm.src_proc)
- && (r1->issuer != simcall_comm_wait__get__comm(r2)->comm.dst_proc)
+ if ((r1->issuer != synchro2->comm.src_proc)
+ && (r1->issuer != synchro2->comm.dst_proc)
&& simcall_comm_wait__get__timeout(r2) <= 0)
return FALSE;
if ((r1->call == SIMCALL_COMM_ISEND)
- && (simcall_comm_wait__get__comm(r2)->comm.type == SIMIX_COMM_SEND)
- && (simcall_comm_wait__get__comm(r2)->comm.src_buff !=
+ && (synchro2->comm.type == SIMIX_COMM_SEND)
+ && (synchro2->comm.src_buff !=
simcall_comm_isend__get__src_buff(r1))
&& simcall_comm_wait__get__timeout(r2) <= 0)
return FALSE;
if ((r1->call == SIMCALL_COMM_IRECV)
- && (simcall_comm_wait__get__comm(r2)->comm.type == SIMIX_COMM_RECEIVE)
- && (simcall_comm_wait__get__comm(r2)->comm.dst_buff !=
- simcall_comm_irecv__get__dst_buff(r1))
+ && (synchro2->comm.type == SIMIX_COMM_RECEIVE)
+ && (synchro2->comm.dst_buff != simcall_comm_irecv__get__dst_buff(r1))
&& simcall_comm_wait__get__timeout(r2) <= 0)
return FALSE;
}
SIMCALL_COMM_ISEND ? simcall_comm_isend__get__rdv(r2) :
simcall_comm_irecv__get__rdv(r2);
- if (rdv != simcall_comm_wait__get__comm(r1)->comm.rdv_cpy
+ if (rdv != synchro1->comm.rdv_cpy
&& simcall_comm_wait__get__timeout(r1) <= 0)
return FALSE;
- if ((r2->issuer != simcall_comm_wait__get__comm(r1)->comm.src_proc)
- && (r2->issuer != simcall_comm_wait__get__comm(r1)->comm.dst_proc)
+ if ((r2->issuer != synchro1->comm.src_proc)
+ && (r2->issuer != synchro1->comm.dst_proc)
&& simcall_comm_wait__get__timeout(r1) <= 0)
return FALSE;
if ((r2->call == SIMCALL_COMM_ISEND)
- && (simcall_comm_wait__get__comm(r1)->comm.type == SIMIX_COMM_SEND)
- && (simcall_comm_wait__get__comm(r1)->comm.src_buff !=
+ && (synchro1->comm.type == SIMIX_COMM_SEND)
+ && (synchro1->comm.src_buff !=
simcall_comm_isend__get__src_buff(r2))
&& simcall_comm_wait__get__timeout(r1) <= 0)
return FALSE;
if ((r2->call == SIMCALL_COMM_IRECV)
- && (simcall_comm_wait__get__comm(r1)->comm.type == SIMIX_COMM_RECEIVE)
- && (simcall_comm_wait__get__comm(r1)->comm.dst_buff !=
+ && (synchro1->comm.type == SIMIX_COMM_RECEIVE)
+ && (synchro1->comm.dst_buff !=
simcall_comm_irecv__get__dst_buff(r2))
&& simcall_comm_wait__get__timeout(r1) <= 0)
return FALSE;
if (r1->call == SIMCALL_COMM_WAIT
&& (r2->call == SIMCALL_COMM_WAIT || r2->call == SIMCALL_COMM_TEST)
- && (simcall_comm_wait__get__comm(r1)->comm.src_proc == NULL
- || simcall_comm_wait__get__comm(r1)->comm.dst_proc == NULL))
+ && (synchro1->comm.src_proc == NULL || synchro1->comm.dst_proc == NULL))
return FALSE;
if (r2->call == SIMCALL_COMM_WAIT
&& (r1->call == SIMCALL_COMM_WAIT || r1->call == SIMCALL_COMM_TEST)
- && (simcall_comm_wait__get__comm(r2)->comm.src_proc == NULL
- || simcall_comm_wait__get__comm(r2)->comm.dst_proc == NULL))
- return FALSE;
+ && (synchro2->comm.src_proc == NULL || synchro2->comm.dst_proc == NULL))
+ return FALSE;
if (r1->call == SIMCALL_COMM_WAIT && r2->call == SIMCALL_COMM_WAIT
- && simcall_comm_wait__get__comm(r1)->comm.src_buff ==
- simcall_comm_wait__get__comm(r2)->comm.src_buff
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff ==
- simcall_comm_wait__get__comm(r2)->comm.dst_buff)
+ && synchro1->comm.src_buff == synchro2->comm.src_buff
+ && synchro2->comm.dst_buff == synchro2->comm.dst_buff)
return FALSE;
if (r1->call == SIMCALL_COMM_WAIT && r2->call == SIMCALL_COMM_WAIT
- && simcall_comm_wait__get__comm(r1)->comm.src_buff != NULL
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff != NULL
- && simcall_comm_wait__get__comm(r2)->comm.src_buff != NULL
- && simcall_comm_wait__get__comm(r2)->comm.dst_buff != NULL
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r2)->comm.src_buff
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r2)->comm.dst_buff
- && simcall_comm_wait__get__comm(r2)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r1)->comm.src_buff)
+ && synchro1->comm.src_buff != NULL
+ && synchro1->comm.dst_buff != NULL
+ && synchro2->comm.src_buff != NULL
+ && synchro2->comm.dst_buff != NULL
+ && synchro1->comm.dst_buff != synchro2->comm.src_buff
+ && synchro1->comm.dst_buff != synchro2->comm.dst_buff
+ && synchro2->comm.dst_buff != synchro1->comm.src_buff)
return FALSE;
if (r1->call == SIMCALL_COMM_TEST &&
(simcall_comm_test__get__comm(r1) == NULL
- || simcall_comm_test__get__comm(r1)->comm.src_buff == NULL
- || simcall_comm_test__get__comm(r1)->comm.dst_buff == NULL))
+ || synchro1->comm.src_buff == NULL
+ || synchro1->comm.dst_buff == NULL))
return FALSE;
if (r2->call == SIMCALL_COMM_TEST &&
(simcall_comm_test__get__comm(r2) == NULL
- || simcall_comm_test__get__comm(r2)->comm.src_buff == NULL
- || simcall_comm_test__get__comm(r2)->comm.dst_buff == NULL))
+ || synchro2->comm.src_buff == NULL
+ || synchro2->comm.dst_buff == NULL))
return FALSE;
if (r1->call == SIMCALL_COMM_TEST && r2->call == SIMCALL_COMM_WAIT
- && simcall_comm_test__get__comm(r1)->comm.src_buff ==
- simcall_comm_wait__get__comm(r2)->comm.src_buff
- && simcall_comm_test__get__comm(r1)->comm.dst_buff ==
- simcall_comm_wait__get__comm(r2)->comm.dst_buff)
+ && synchro1->comm.src_buff == synchro2->comm.src_buff
+ && synchro1->comm.dst_buff == synchro2->comm.dst_buff)
return FALSE;
if (r1->call == SIMCALL_COMM_WAIT && r2->call == SIMCALL_COMM_TEST
- && simcall_comm_wait__get__comm(r1)->comm.src_buff ==
- simcall_comm_test__get__comm(r2)->comm.src_buff
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff ==
- simcall_comm_test__get__comm(r2)->comm.dst_buff)
+ && synchro1->comm.src_buff == synchro2->comm.src_buff
+ && synchro1->comm.dst_buff == synchro2->comm.dst_buff)
return FALSE;
if (r1->call == SIMCALL_COMM_WAIT && r2->call == SIMCALL_COMM_TEST
- && simcall_comm_wait__get__comm(r1)->comm.src_buff != NULL
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff != NULL
- && simcall_comm_test__get__comm(r2)->comm.src_buff != NULL
- && simcall_comm_test__get__comm(r2)->comm.dst_buff != NULL
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff !=
- simcall_comm_test__get__comm(r2)->comm.src_buff
- && simcall_comm_wait__get__comm(r1)->comm.dst_buff !=
- simcall_comm_test__get__comm(r2)->comm.dst_buff
- && simcall_comm_test__get__comm(r2)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r1)->comm.src_buff)
+ && synchro1->comm.src_buff != NULL
+ && synchro1->comm.dst_buff != NULL
+ && synchro2->comm.src_buff != NULL
+ && synchro2->comm.dst_buff != NULL
+ && synchro1->comm.dst_buff != synchro2->comm.src_buff
+ && synchro1->comm.dst_buff != synchro2->comm.dst_buff
+ && synchro2->comm.dst_buff != synchro1->comm.src_buff)
return FALSE;
if (r1->call == SIMCALL_COMM_TEST && r2->call == SIMCALL_COMM_WAIT
- && simcall_comm_test__get__comm(r1)->comm.src_buff != NULL
- && simcall_comm_test__get__comm(r1)->comm.dst_buff != NULL
- && simcall_comm_wait__get__comm(r2)->comm.src_buff != NULL
- && simcall_comm_wait__get__comm(r2)->comm.dst_buff != NULL
- && simcall_comm_test__get__comm(r1)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r2)->comm.src_buff
- && simcall_comm_test__get__comm(r1)->comm.dst_buff !=
- simcall_comm_wait__get__comm(r2)->comm.dst_buff
- && simcall_comm_wait__get__comm(r2)->comm.dst_buff !=
- simcall_comm_test__get__comm(r1)->comm.src_buff)
+ && synchro1->comm.src_buff != NULL
+ && synchro1->comm.dst_buff != NULL
+ && synchro2->comm.src_buff != NULL
+ && synchro2->comm.dst_buff != NULL
+ && synchro1->comm.dst_buff != synchro2->comm.src_buff
+ && synchro1->comm.dst_buff != synchro2->comm.dst_buff
+ && synchro2->comm.dst_buff != synchro1->comm.src_buff)
return FALSE;
-
return TRUE;
}
}
-char *MC_request_to_string(smx_simcall_t req, int value)
+char *MC_request_to_string(smx_simcall_t req, int value, e_mc_request_type_t request_type)
{
- char *type = NULL, *args = NULL, *str = NULL, *p = NULL, *bs = NULL;
- smx_synchro_t act = NULL;
- smx_mutex_t mutex = NULL;
- size_t size = 0;
+ bool use_remote_comm;
+ switch(request_type) {
+ case MC_REQUEST_SIMIX:
+ use_remote_comm = true;
+ break;
+ case MC_REQUEST_EXECUTED:
+ case MC_REQUEST_INTERNAL:
+ use_remote_comm = false;
+ break;
+ }
+
+ const char* type = NULL;
+ char *args = NULL;
+
+ smx_process_t issuer = MC_smx_simcall_get_issuer(req);
switch (req->call) {
- case SIMCALL_COMM_ISEND:
- type = xbt_strdup("iSend");
- p = pointer_to_string(simcall_comm_isend__get__src_buff(req));
- bs = buff_size_to_string(simcall_comm_isend__get__src_buff_size(req));
- if (req->issuer->smx_host)
+
+ case SIMCALL_COMM_ISEND: {
+ type = "iSend";
+ char* p = pointer_to_string(simcall_comm_isend__get__src_buff(req));
+ char* bs = buff_size_to_string(simcall_comm_isend__get__src_buff_size(req));
+ if (issuer->smx_host)
args =
- bprintf("src=(%lu)%s (%s), buff=%s, size=%s", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), req->issuer->name,
+ bprintf("src=(%lu)%s (%s), buff=%s, size=%s", issuer->pid,
+ MC_smx_process_get_host_name(issuer),
+ MC_smx_process_get_name(issuer),
p, bs);
else
args =
- bprintf("src=(%lu)%s, buff=%s, size=%s", req->issuer->pid,
- req->issuer->name, p, bs);
+ bprintf("src=(%lu)%s, buff=%s, size=%s", issuer->pid,
+ MC_smx_process_get_name(issuer), p, bs);
+ xbt_free(bs);
+ xbt_free(p);
break;
- case SIMCALL_COMM_IRECV:
- size =
- simcall_comm_irecv__get__dst_buff_size(req) ?
- *simcall_comm_irecv__get__dst_buff_size(req) : 0;
- type = xbt_strdup("iRecv");
- p = pointer_to_string(simcall_comm_irecv__get__dst_buff(req));
- bs = buff_size_to_string(size);
- if (req->issuer->smx_host)
+ }
+
+ case SIMCALL_COMM_IRECV: {
+ size_t* remote_size = simcall_comm_irecv__get__dst_buff_size(req);
+
+ // size_t size = size_pointer ? *size_pointer : 0;
+ size_t size = 0;
+ if (remote_size)
+ MC_process_read_simple(&mc_model_checker->process, &size,
+ remote_size, sizeof(size));
+
+ type = "iRecv";
+ char* p = pointer_to_string(simcall_comm_irecv__get__dst_buff(req));
+ char* bs = buff_size_to_string(size);
+ if (issuer->smx_host)
args =
- bprintf("dst=(%lu)%s (%s), buff=%s, size=%s", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), req->issuer->name,
+ bprintf("dst=(%lu)%s (%s), buff=%s, size=%s", issuer->pid,
+ MC_smx_process_get_host_name(issuer),
+ MC_smx_process_get_name(issuer),
p, bs);
else
args =
- bprintf("dst=(%lu)%s, buff=%s, size=%s", req->issuer->pid,
- req->issuer->name, p, bs);
+ bprintf("dst=(%lu)%s, buff=%s, size=%s", issuer->pid,
+ MC_smx_process_get_name(issuer),
+ p, bs);
+ xbt_free(bs);
+ xbt_free(p);
break;
- case SIMCALL_COMM_WAIT:
- act = simcall_comm_wait__get__comm(req);
+ }
+
+ case SIMCALL_COMM_WAIT: {
+ smx_synchro_t remote_act = simcall_comm_wait__get__comm(req);
+ char* p;
if (value == -1) {
- type = xbt_strdup("WaitTimeout");
- p = pointer_to_string(act);
+ type = "WaitTimeout";
+ p = pointer_to_string(remote_act);
args = bprintf("comm=%s", p);
} else {
- type = xbt_strdup("Wait");
- p = pointer_to_string(act);
+ type = "Wait";
+ p = pointer_to_string(remote_act);
+
+ s_smx_synchro_t synchro;
+ smx_synchro_t act;
+ if (use_remote_comm) {
+ MC_process_read_simple(&mc_model_checker->process, &synchro,
+ remote_act, sizeof(synchro));
+ act = &synchro;
+ } else
+ act = remote_act;
+
+ smx_process_t src_proc = MC_smx_resolve_process(act->comm.src_proc);
+ smx_process_t dst_proc = MC_smx_resolve_process(act->comm.dst_proc);
args = bprintf("comm=%s [(%lu)%s (%s)-> (%lu)%s (%s)]", p,
- act->comm.src_proc ? act->comm.src_proc->pid : 0,
- act->comm.src_proc ? MSG_host_get_name(act->comm.src_proc->
- smx_host) : "",
- act->comm.src_proc ? act->comm.src_proc->name : "",
- act->comm.dst_proc ? act->comm.dst_proc->pid : 0,
- act->comm.dst_proc ? MSG_host_get_name(act->comm.dst_proc->
- smx_host) : "",
- act->comm.dst_proc ? act->comm.dst_proc->name : "");
+ src_proc ? src_proc->pid : 0,
+ src_proc ? MC_smx_process_get_host_name(src_proc) : "",
+ src_proc ? MC_smx_process_get_name(src_proc) : "",
+ dst_proc ? dst_proc->pid : 0,
+ dst_proc ? MC_smx_process_get_host_name(dst_proc) : "",
+ dst_proc ? MC_smx_process_get_name(dst_proc) : "");
}
+ xbt_free(p);
break;
- case SIMCALL_COMM_TEST:
- act = simcall_comm_test__get__comm(req);
+ }
+
+ case SIMCALL_COMM_TEST: {
+ smx_synchro_t remote_act = simcall_comm_test__get__comm(req);
+ s_smx_synchro_t synchro;
+ smx_synchro_t act;
+ if (use_remote_comm) {
+ MC_process_read_simple(&mc_model_checker->process, &synchro,
+ remote_act, sizeof(synchro));
+ act = &synchro;
+ } else
+ act = remote_act;
+
+ char* p;
if (act->comm.src_proc == NULL || act->comm.dst_proc == NULL) {
- type = xbt_strdup("Test FALSE");
- p = pointer_to_string(act);
+ type = "Test FALSE";
+ p = pointer_to_string(remote_act);
args = bprintf("comm=%s", p);
} else {
- type = xbt_strdup("Test TRUE");
- p = pointer_to_string(act);
+ type = "Test TRUE";
+ p = pointer_to_string(remote_act);
+
+ smx_process_t src_proc = MC_smx_resolve_process(act->comm.src_proc);
+ smx_process_t dst_proc = MC_smx_resolve_process(act->comm.dst_proc);
args = bprintf("comm=%s [(%lu)%s (%s) -> (%lu)%s (%s)]", p,
- act->comm.src_proc->pid, act->comm.src_proc->name,
- MSG_host_get_name(act->comm.src_proc->smx_host),
- act->comm.dst_proc->pid, act->comm.dst_proc->name,
- MSG_host_get_name(act->comm.dst_proc->smx_host));
+ src_proc->pid,
+ MC_smx_process_get_name(src_proc),
+ MC_smx_process_get_host_name(src_proc),
+ dst_proc->pid,
+ MC_smx_process_get_name(dst_proc),
+ MC_smx_process_get_host_name(dst_proc));
}
+ xbt_free(p);
break;
+ }
- case SIMCALL_COMM_WAITANY:
- type = xbt_strdup("WaitAny");
- if (!xbt_dynar_is_empty(simcall_comm_waitany__get__comms(req))) {
- p = pointer_to_string(xbt_dynar_get_as
- (simcall_comm_waitany__get__comms(req), value,
- smx_synchro_t));
- args =
- bprintf("comm=%s (%d of %lu)", p, value + 1,
- xbt_dynar_length(simcall_comm_waitany__get__comms(req)));
+ case SIMCALL_COMM_WAITANY: {
+ type = "WaitAny";
+ s_xbt_dynar_t comms;
+ MC_process_read_simple(&mc_model_checker->process,
+ &comms, simcall_comm_waitany__get__comms(req), sizeof(comms));
+ if (!xbt_dynar_is_empty(&comms)) {
+ smx_synchro_t remote_sync;
+ MC_process_read_dynar_element(&mc_model_checker->process,
+ &remote_sync, simcall_comm_waitany__get__comms(req), value,
+ sizeof(remote_sync));
+ char* p = pointer_to_string(remote_sync);
+ args = bprintf("comm=%s (%d of %lu)",
+ p, value + 1, xbt_dynar_length(&comms));
+ xbt_free(p);
} else {
args = bprintf("comm at idx %d", value);
}
break;
+ }
case SIMCALL_COMM_TESTANY:
if (value == -1) {
- type = xbt_strdup("TestAny FALSE");
+ type = "TestAny FALSE";
args = xbt_strdup("-");
} else {
- type = xbt_strdup("TestAny");
+ type = "TestAny";
args =
bprintf("(%d of %lu)", value + 1,
- xbt_dynar_length(simcall_comm_testany__get__comms(req)));
+ MC_process_read_dynar_length(&mc_model_checker->process,
+ simcall_comm_testany__get__comms(req)));
}
break;
- case SIMCALL_MUTEX_LOCK:
- mutex = simcall_mutex_lock__get__mutex(req);
- type = xbt_strdup("Mutex LOCK");
- args = bprintf("locked = %d, owner = %d, sleeping = %d", mutex->locked, mutex->owner != NULL ? (int)mutex->owner->pid : -1, xbt_swag_size(mutex->sleeping));
+ case SIMCALL_MUTEX_LOCK: {
+ type = "Mutex LOCK";
+
+ s_smx_mutex_t mutex;
+ MC_process_read_simple(&mc_model_checker->process, &mutex,
+ simcall_mutex_lock__get__mutex(req), sizeof(mutex));
+ s_xbt_swag_t mutex_sleeping;
+ MC_process_read_simple(&mc_model_checker->process, &mutex_sleeping,
+ mutex.sleeping, sizeof(mutex_sleeping));
+
+ args = bprintf("locked = %d, owner = %d, sleeping = %d",
+ mutex.locked,
+ mutex.owner != NULL ? (int) MC_smx_resolve_process(mutex.owner)->pid : -1,
+ mutex_sleeping.count);
break;
+ }
case SIMCALL_MC_SNAPSHOT:
- type = xbt_strdup("MC_SNAPSHOT");
+ type = "MC_SNAPSHOT";
args = NULL;
break;
case SIMCALL_MC_COMPARE_SNAPSHOTS:
- type = xbt_strdup("MC_COMPARE_SNAPSHOTS");
+ type = "MC_COMPARE_SNAPSHOTS";
args = NULL;
break;
case SIMCALL_MC_RANDOM:
- type = xbt_strdup("MC_RANDOM");
+ type = "MC_RANDOM";
args = bprintf("%d", value);
break;
THROW_UNIMPLEMENTED;
}
+ char* str;
if (args != NULL) {
str =
- bprintf("[(%lu)%s (%s)] %s(%s)", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), req->issuer->name,
+ bprintf("[(%lu)%s (%s)] %s(%s)", issuer->pid,
+ MC_smx_process_get_host_name(issuer),
+ MC_smx_process_get_name(issuer),
type, args);
} else {
str =
- bprintf("[(%lu)%s (%s)] %s ", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), req->issuer->name,
+ bprintf("[(%lu)%s (%s)] %s ", issuer->pid,
+ MC_smx_process_get_host_name(issuer),
+ MC_smx_process_get_name(issuer),
type);
}
-
xbt_free(args);
- xbt_free(type);
- xbt_free(p);
- xbt_free(bs);
return str;
}
unsigned int MC_request_testany_fail(smx_simcall_t req)
{
- unsigned int cursor;
- smx_synchro_t action;
-
- xbt_dynar_foreach(simcall_comm_testany__get__comms(req), cursor, action) {
- if (action->comm.src_proc && action->comm.dst_proc)
+ // Remote xbt_dynar_foreach on simcall_comm_testany__get__comms(req).
+
+ // Read the dynar:
+ s_xbt_dynar_t comms;
+ MC_process_read_simple(&mc_model_checker->process,
+ &comms, simcall_comm_testany__get__comms(req), sizeof(comms));
+
+ // Read ther dynar buffer:
+ size_t buffer_size = comms.elmsize * comms.used;
+ char buffer[buffer_size];
+ MC_process_read_simple(&mc_model_checker->process,
+ buffer, comms.data, buffer_size);
+
+ // Iterate over the elements:
+ assert(comms.elmsize == sizeof(smx_synchro_t));
+ unsigned cursor;
+ for (cursor=0; cursor != comms.used; ++cursor) {
+
+ // Get the element:
+ smx_synchro_t remote_action;
+ memcpy(buffer + comms.elmsize * cursor, &remote_action, sizeof(remote_action));
+
+ // Dereference the pointer:
+ s_smx_synchro_t action;
+ MC_process_read_simple(&mc_model_checker->process,
+ &action, remote_action, sizeof(action));
+
+ // Finally so something useful about it:
+ if (action.comm.src_proc && action.comm.dst_proc)
return FALSE;
}
int MC_request_is_enabled_by_idx(smx_simcall_t req, unsigned int idx)
{
- smx_synchro_t act;
-
+ smx_synchro_t remote_act = NULL;
switch (req->call) {
case SIMCALL_COMM_WAIT:
/* FIXME: check also that src and dst processes are not suspended */
- act = simcall_comm_wait__get__comm(req);
- return (act->comm.src_proc && act->comm.dst_proc);
+ remote_act = simcall_comm_wait__get__comm(req);
break;
- case SIMCALL_COMM_WAITANY:
- act =
- xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), idx,
- smx_synchro_t);
- return (act->comm.src_proc && act->comm.dst_proc);
+ case SIMCALL_COMM_WAITANY: {
+ MC_process_read_dynar_element(
+ &mc_model_checker->process, &remote_act, simcall_comm_waitany__get__comms(req),
+ idx, sizeof(remote_act));
+ }
break;
- case SIMCALL_COMM_TESTANY:
- act =
- xbt_dynar_get_as(simcall_comm_testany__get__comms(req), idx,
- smx_synchro_t);
- return (act->comm.src_proc && act->comm.dst_proc);
+ case SIMCALL_COMM_TESTANY: {
+ MC_process_read_dynar_element(
+ &mc_model_checker->process, &remote_act, simcall_comm_testany__get__comms(req),
+ idx, sizeof(remote_act));
+ }
break;
default:
return TRUE;
}
+
+ s_smx_synchro_t synchro;
+ MC_process_read_simple(&mc_model_checker->process,
+ &synchro, remote_act, sizeof(synchro));
+ return synchro.comm.src_proc && synchro.comm.dst_proc;
}
int MC_process_is_enabled(smx_process_t process)
char *MC_request_get_dot_output(smx_simcall_t req, int value)
{
+ char *label = NULL;
+
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
- char *str = NULL, *label = NULL;
- smx_synchro_t act = NULL;
-
switch (req->call) {
case SIMCALL_COMM_ISEND:
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] iSend", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] iSend", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] iSend", req->issuer->pid);
+ label = bprintf("[(%lu)] iSend", issuer->pid);
break;
case SIMCALL_COMM_IRECV:
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] iRecv", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] iRecv", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] iRecv", req->issuer->pid);
+ label = bprintf("[(%lu)] iRecv", issuer->pid);
break;
- case SIMCALL_COMM_WAIT:
- act = simcall_comm_wait__get__comm(req);
+ case SIMCALL_COMM_WAIT: {
if (value == -1) {
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] WaitTimeout", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] WaitTimeout", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] WaitTimeout", req->issuer->pid);
+ label = bprintf("[(%lu)] WaitTimeout", issuer->pid);
} else {
- if (req->issuer->smx_host)
+ smx_synchro_t remote_act = simcall_comm_wait__get__comm(req);
+ s_smx_synchro_t synchro;
+ MC_process_read_simple(&mc_model_checker->process, &synchro,
+ remote_act, sizeof(synchro));
+
+ smx_process_t src_proc = MC_smx_resolve_process(synchro.comm.src_proc);
+ smx_process_t dst_proc = MC_smx_resolve_process(synchro.comm.dst_proc);
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] Wait [(%lu)->(%lu)]", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host),
- act->comm.src_proc ? act->comm.src_proc->pid : 0,
- act->comm.dst_proc ? act->comm.dst_proc->pid : 0);
+ bprintf("[(%lu)%s] Wait [(%lu)->(%lu)]", issuer->pid,
+ MC_smx_process_get_host_name(issuer),
+ src_proc ? src_proc->pid : 0,
+ dst_proc ? dst_proc->pid : 0);
else
label =
- bprintf("[(%lu)] Wait [(%lu)->(%lu)]", req->issuer->pid,
- act->comm.src_proc ? act->comm.src_proc->pid : 0,
- act->comm.dst_proc ? act->comm.dst_proc->pid : 0);
+ bprintf("[(%lu)] Wait [(%lu)->(%lu)]", issuer->pid,
+ src_proc ? src_proc->pid : 0,
+ dst_proc ? dst_proc->pid : 0);
}
break;
+ }
- case SIMCALL_COMM_TEST:
- act = simcall_comm_test__get__comm(req);
- if (act->comm.src_proc == NULL || act->comm.dst_proc == NULL) {
- if (req->issuer->smx_host)
+ case SIMCALL_COMM_TEST: {
+ smx_synchro_t remote_act = simcall_comm_test__get__comm(req);
+ s_smx_synchro_t synchro;
+ MC_process_read_simple(&mc_model_checker->process, &synchro,
+ remote_act, sizeof(synchro));
+ if (synchro.comm.src_proc == NULL || synchro.comm.dst_proc == NULL) {
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] Test FALSE", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] Test FALSE", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] Test FALSE", req->issuer->pid);
+ label = bprintf("[(%lu)] Test FALSE", issuer->pid);
} else {
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] Test TRUE", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] Test TRUE", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] Test TRUE", req->issuer->pid);
+ label = bprintf("[(%lu)] Test TRUE", issuer->pid);
}
break;
+ }
- case SIMCALL_COMM_WAITANY:
- if (req->issuer->smx_host)
+ case SIMCALL_COMM_WAITANY: {
+ unsigned long comms_size = MC_process_read_dynar_length(
+ &mc_model_checker->process, simcall_comm_waitany__get__comms(req));
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] WaitAny [%d of %lu]", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), value + 1,
- xbt_dynar_length(simcall_comm_waitany__get__comms(req)));
+ bprintf("[(%lu)%s] WaitAny [%d of %lu]", issuer->pid,
+ MC_smx_process_get_host_name(issuer), value + 1,
+ comms_size);
else
label =
- bprintf("[(%lu)] WaitAny [%d of %lu]", req->issuer->pid, value + 1,
- xbt_dynar_length(simcall_comm_waitany__get__comms(req)));
+ bprintf("[(%lu)] WaitAny [%d of %lu]", issuer->pid, value + 1,
+ comms_size);
break;
+ }
case SIMCALL_COMM_TESTANY:
if (value == -1) {
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] TestAny FALSE", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] TestAny FALSE", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] TestAny FALSE", req->issuer->pid);
+ label = bprintf("[(%lu)] TestAny FALSE", issuer->pid);
} else {
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] TestAny TRUE [%d of %lu]", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), value + 1,
+ bprintf("[(%lu)%s] TestAny TRUE [%d of %lu]", issuer->pid,
+ MC_smx_process_get_host_name(issuer), value + 1,
xbt_dynar_length(simcall_comm_testany__get__comms(req)));
else
label =
- bprintf("[(%lu)] TestAny TRUE [%d of %lu]", req->issuer->pid,
+ bprintf("[(%lu)] TestAny TRUE [%d of %lu]", issuer->pid,
value + 1,
xbt_dynar_length(simcall_comm_testany__get__comms(req)));
}
break;
case SIMCALL_MC_RANDOM:
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] MC_RANDOM (%d)", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host), value);
+ bprintf("[(%lu)%s] MC_RANDOM (%d)", issuer->pid,
+ MC_smx_process_get_host_name(issuer), value);
else
- label = bprintf("[(%lu)] MC_RANDOM (%d)", req->issuer->pid, value);
+ label = bprintf("[(%lu)] MC_RANDOM (%d)", issuer->pid, value);
break;
case SIMCALL_MC_SNAPSHOT:
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] MC_SNAPSHOT", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] MC_SNAPSHOT", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] MC_SNAPSHOT", req->issuer->pid);
+ label = bprintf("[(%lu)] MC_SNAPSHOT", issuer->pid);
break;
case SIMCALL_MC_COMPARE_SNAPSHOTS:
- if (req->issuer->smx_host)
+ if (issuer->smx_host)
label =
- bprintf("[(%lu)%s] MC_COMPARE_SNAPSHOTS", req->issuer->pid,
- MSG_host_get_name(req->issuer->smx_host));
+ bprintf("[(%lu)%s] MC_COMPARE_SNAPSHOTS", issuer->pid,
+ MC_smx_process_get_host_name(issuer));
else
- label = bprintf("[(%lu)] MC_COMPARE_SNAPSHOTS", req->issuer->pid);
+ label = bprintf("[(%lu)] MC_COMPARE_SNAPSHOTS", issuer->pid);
break;
default:
THROW_UNIMPLEMENTED;
}
- str =
+ char* str =
bprintf("label = \"%s\", color = %s, fontcolor = %s", label,
- colors[req->issuer->pid - 1], colors[req->issuer->pid - 1]);
+ colors[issuer->pid - 1], colors[issuer->pid - 1]);
xbt_free(label);
return str;
SG_BEGIN_DECL()
+typedef enum e_mc_request_type {
+ MC_REQUEST_SIMIX,
+ MC_REQUEST_EXECUTED,
+ MC_REQUEST_INTERNAL,
+} e_mc_request_type_t;
+
int MC_request_depend(smx_simcall_t req1, smx_simcall_t req2);
-char* MC_request_to_string(smx_simcall_t req, int value);
+char* MC_request_to_string(smx_simcall_t req, int value, e_mc_request_type_t type);
unsigned int MC_request_testany_fail(smx_simcall_t req);
/*int MC_waitany_is_enabled_by_comm(smx_req_t req, unsigned int comm);*/
int MC_request_is_visible(smx_simcall_t req);
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <assert.h>
+
#include "mc_state.h"
#include "mc_request.h"
#include "mc_safety.h"
#include "mc_private.h"
#include "mc_record.h"
+#include "mc_smx.h"
+#include "mc_client.h"
#include "xbt/mmalloc/mmprivate.h"
/**
* \brief Initialize the DPOR exploration algorithm
*/
-void MC_pre_modelcheck_safety()
+static void MC_pre_modelcheck_safety()
{
-
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- mc_state_t initial_state = NULL;
- smx_process_t process;
-
- /* Create the initial state and push it into the exploration stack */
- if (!mc_mem_set)
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
if (_sg_mc_visited > 0)
visited_states = xbt_dynar_new(sizeof(mc_visited_state_t), visited_state_free_voidp);
- initial_state = MC_state_new();
-
+ mc_state_t initial_state = MC_state_new();
MC_SET_STD_HEAP;
XBT_DEBUG("**************************************************");
MC_SET_MC_HEAP;
/* Get an enabled process and insert it in the interleave set of the initial state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ smx_process_t process;
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(initial_state, process);
if (mc_reduce_kind != e_mc_reduce_none)
break;
}
- }
+ );
xbt_fifo_unshift(mc_stack, initial_state);
-
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
}
/** \brief Model-check the application using a DFS exploration
* with DPOR (Dynamic Partial Order Reductions)
*/
-void MC_modelcheck_safety(void)
+static void MC_modelcheck_safety_main(void)
{
-
char *req_str = NULL;
int value;
- smx_simcall_t req = NULL, prev_req = NULL;
+ smx_simcall_t req = NULL;
mc_state_t state = NULL, prev_state = NULL, next_state = NULL;
- smx_process_t process = NULL;
xbt_fifo_item_t item = NULL;
mc_visited_state_t visited_state = NULL;
if (xbt_fifo_size(mc_stack) <= _sg_mc_max_depth && !user_max_depth_reached
&& (req = MC_state_get_request(state, &value)) && visited_state == NULL) {
- char* req_str = MC_request_to_string(req, value);
- XBT_DEBUG("Execute: %s", req_str);
+ req_str = MC_request_to_string(req, value, MC_REQUEST_SIMIX);
+ XBT_DEBUG("Execute: %s", req_str);
xbt_free(req_str);
if (dot_output != NULL) {
MC_state_set_executed_request(state, req, value);
mc_stats->executed_transitions++;
- /* Answer the request */
- SIMIX_simcall_handle(req, value);
+ // TODO, bundle both operations in a single message
+ // MC_execute_transition(req, value)
- /* Wait for requests (schedules processes) */
+ /* Answer the request */
+ MC_simcall_handle(req, value);
MC_wait_for_requests();
/* Create the new expanded state */
if ((visited_state = is_visited_state(next_state)) == NULL) {
/* Get an enabled process and insert it in the interleave set of the next state */
- xbt_swag_foreach(process, simix_global->process_list) {
+ smx_process_t process = NULL;
+ MC_EACH_SIMIX_PROCESS(process,
if (MC_process_is_enabled(process)) {
MC_state_interleave_process(next_state, process);
if (mc_reduce_kind != e_mc_reduce_none)
break;
}
- }
+ );
if (dot_output != NULL)
fprintf(dot_output, "\"%d\" -> \"%d\" [%s];\n", state->num, next_state->num, req_str);
/* Trash the current state, no longer needed */
xbt_fifo_shift(mc_stack);
- MC_state_delete(state, !state->in_visited_states ? 1 : 0);
XBT_DEBUG("Delete state %d at depth %d", state->num, xbt_fifo_size(mc_stack) + 1);
+ MC_state_delete(state, !state->in_visited_states ? 1 : 0);
MC_SET_STD_HEAP;
while ((state = xbt_fifo_shift(mc_stack)) != NULL) {
if (mc_reduce_kind == e_mc_reduce_dpor) {
req = MC_state_get_internal_request(state);
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
xbt_fifo_foreach(mc_stack, item, prev_state, mc_state_t) {
if (MC_request_depend(req, MC_state_get_internal_request(prev_state))) {
if (XBT_LOG_ISENABLED(mc_safety, xbt_log_priority_debug)) {
XBT_DEBUG("Dependent Transitions:");
- prev_req = MC_state_get_executed_request(prev_state, &value);
- req_str = MC_request_to_string(prev_req, value);
+ smx_simcall_t prev_req = MC_state_get_executed_request(prev_state, &value);
+ req_str = MC_request_to_string(prev_req, value, MC_REQUEST_INTERNAL);
XBT_DEBUG("%s (state=%d)", req_str, prev_state->num);
xbt_free(req_str);
prev_req = MC_state_get_executed_request(state, &value);
- req_str = MC_request_to_string(prev_req, value);
+ req_str = MC_request_to_string(prev_req, value, MC_REQUEST_EXECUTED);
XBT_DEBUG("%s (state=%d)", req_str, state->num);
xbt_free(req_str);
}
- if (!MC_state_process_is_done(prev_state, req->issuer))
- MC_state_interleave_process(prev_state, req->issuer);
+ if (!MC_state_process_is_done(prev_state, issuer))
+ MC_state_interleave_process(prev_state, issuer);
else
XBT_DEBUG("Process %p is in done set", req->issuer);
} else {
+ const smx_process_t previous_issuer = MC_smx_simcall_get_issuer(MC_state_get_internal_request(prev_state));
XBT_DEBUG("Simcall %d, process %lu (state %d) and simcall %d, process %lu (state %d) are independant",
- req->call, req->issuer->pid, state->num,
+ req->call, issuer->pid, state->num,
MC_state_get_internal_request(prev_state)->call,
- MC_state_get_internal_request(prev_state)->issuer->pid,
+ previous_issuer->pid,
prev_state->num);
}
return;
}
+
+void MC_modelcheck_safety(void)
+{
+ XBT_DEBUG("Starting the safety algorithm");
+
+ _sg_mc_safety = 1;
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+
+ /* Create exploration stack */
+ mc_stack = xbt_fifo_new();
+
+ MC_SET_STD_HEAP;
+
+ MC_pre_modelcheck_safety();
+
+ MC_SET_MC_HEAP;
+ /* Save the initial state */
+ initial_global_state = xbt_new0(s_mc_global_t, 1);
+ initial_global_state->snapshot = MC_take_snapshot(0);
+ MC_SET_STD_HEAP;
+
+ MC_modelcheck_safety_main();
+
+ mmalloc_set_current_heap(heap);
+
+ xbt_abort();
+ //MC_exit();
+}
extern e_mc_reduce_t mc_reduce_kind;
-void MC_pre_modelcheck_safety(void);
void MC_modelcheck_safety(void);
typedef struct s_mc_visited_state{
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <memory>
+#include <system_error>
+
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/signalfd.h>
+
+#include <xbt/log.h>
+
+#include "mc_model_checker.h"
+#include "mc_protocol.h"
+#include "mc_server.h"
+#include "mc_private.h"
+#include "mc_ignore.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_server, mc, "MC server logic");
+
+// HArdcoded index for now:
+#define SOCKET_FD_INDEX 0
+#define SIGNAL_FD_INDEX 1
+
+mc_server_t mc_server;
+
+struct mc_symbol_pointer_callback
+{
+ mc_process_t process;
+ void* value;
+};
+
+static int mc_symbol_pointer_callback_evaluate(void* p)
+{
+ struct mc_symbol_pointer_callback* callback = (struct mc_symbol_pointer_callback*) p;
+ int value;
+ MC_process_read(callback->process, MC_ADDRESS_SPACE_READ_FLAGS_NONE,
+ &value, callback->value, sizeof(value), MC_PROCESS_INDEX_ANY);
+ return value;
+}
+
+s_mc_server::s_mc_server(pid_t pid, int socket)
+{
+ this->pid = pid;
+ this->socket = socket;
+}
+
+void s_mc_server::start()
+{
+ /* Wait for the target process to initialize and exchange a HELLO messages
+ * before trying to look at its memory map.
+ */
+ int res = MC_protocol_hello(socket);
+ if (res != 0)
+ throw std::system_error(res, std::system_category());
+
+ // Block SIGCHLD (this will be handled with accept/signalfd):
+ sigset_t set;
+ sigemptyset(&set);
+ sigaddset(&set, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
+ throw std::system_error(errno, std::system_category());
+
+ sigset_t full_set;
+ sigfillset(&full_set);
+
+ // Prepare data for poll:
+
+ struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
+ socket_pollfd->fd = socket;
+ socket_pollfd->events = POLLIN;
+ socket_pollfd->revents = 0;
+
+ int signal_fd = signalfd(-1, &set, 0);
+ if (signal_fd == -1)
+ throw std::system_error(errno, std::system_category());
+
+ struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
+ signalfd_pollfd->fd = signal_fd;
+ signalfd_pollfd->events = POLLIN;
+ signalfd_pollfd->revents = 0;
+}
+
+void s_mc_server::shutdown()
+{
+ XBT_DEBUG("Shuting down model-checker");
+
+ mc_process_t process = &mc_model_checker->process;
+ int status = process->status;
+ if (process->running) {
+ XBT_DEBUG("Killing process");
+ kill(process->pid, SIGTERM);
+ if (waitpid(process->pid, &status, 0) == -1)
+ throw std::system_error(errno, std::system_category());
+ // TODO, handle the case when the process does not want to die with a timeout
+ process->status = status;
+ }
+}
+
+void s_mc_server::exit()
+{
+ // Finished:
+ int status = mc_model_checker->process.status;
+ if (WIFEXITED(status))
+ ::exit(WEXITSTATUS(status));
+ else if (WIFSIGNALED(status)) {
+ // Try to uplicate the signal of the model-checked process.
+ // This is a temporary hack so we don't try too hard.
+ kill(mc_model_checker->process.pid, WTERMSIG(status));
+ abort();
+ } else {
+ xbt_die("Unexpected status from model-checked process");
+ }
+}
+
+void s_mc_server::resume(mc_process_t process)
+{
+ int socket = process->socket;
+ int res = MC_protocol_send_simple_message(socket, MC_MESSAGE_CONTINUE);
+ if (res)
+ throw std::system_error(res, std::system_category());
+ process->cache_flags = (e_mc_process_cache_flags_t) 0;
+}
+
+static
+void throw_socket_error(int fd)
+{
+ int error = 0;
+ socklen_t errlen = sizeof(error);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen) == -1)
+ error = errno;
+ throw std::system_error(error, std::system_category());
+}
+
+bool s_mc_server::handle_events()
+{
+ char buffer[MC_MESSAGE_LENGTH];
+ struct pollfd* socket_pollfd = &fds[SOCKET_FD_INDEX];
+ struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
+
+ while(poll(fds, 2, -1) == -1) {
+ switch(errno) {
+ case EINTR:
+ continue;
+ default:
+ throw std::system_error(errno, std::system_category());
+ }
+ }
+
+ if (socket_pollfd->revents) {
+ if (socket_pollfd->revents & POLLIN) {
+
+ ssize_t size = MC_receive_message(socket_pollfd->fd, buffer, sizeof(buffer), MSG_DONTWAIT);
+ if (size == -1 && errno != EAGAIN)
+ throw std::system_error(errno, std::system_category());
+
+ s_mc_message_t base_message;
+ if (size < (ssize_t) sizeof(base_message))
+ xbt_die("Broken message");
+ memcpy(&base_message, buffer, sizeof(base_message));
+
+ switch(base_message.type) {
+
+ case MC_MESSAGE_IGNORE_HEAP:
+ {
+ s_mc_ignore_heap_message_t message;
+ if (size != sizeof(message))
+ xbt_die("Broken messsage");
+ memcpy(&message, buffer, sizeof(message));
+ mc_heap_ignore_region_t region = xbt_new(s_mc_heap_ignore_region_t, 1);
+ *region = message.region;
+ MC_heap_region_ignore_insert(region);
+ break;
+ }
+
+ case MC_MESSAGE_UNIGNORE_HEAP:
+ {
+ s_mc_ignore_memory_message_t message;
+ if (size != sizeof(message))
+ xbt_die("Broken messsage");
+ memcpy(&message, buffer, sizeof(message));
+ MC_remove_ignore_heap(message.addr, message.size);
+ break;
+ }
+
+ case MC_MESSAGE_IGNORE_MEMORY:
+ {
+ s_mc_ignore_memory_message_t message;
+ if (size != sizeof(message))
+ xbt_die("Broken messsage");
+ memcpy(&message, buffer, sizeof(message));
+ MC_process_ignore_memory(&mc_model_checker->process,
+ message.addr, message.size);
+ break;
+ }
+
+ case MC_MESSAGE_STACK_REGION:
+ {
+ s_mc_stack_region_message_t message;
+ if (size != sizeof(message))
+ xbt_die("Broken messsage");
+ memcpy(&message, buffer, sizeof(message));
+ stack_region_t stack_region = xbt_new(s_stack_region_t, 1);
+ *stack_region = message.stack_region;
+ MC_stack_area_add(stack_region);
+ }
+ break;
+
+ case MC_MESSAGE_REGISTER_SYMBOL:
+ {
+ s_mc_register_symbol_message_t message;
+ if (size != sizeof(message))
+ xbt_die("Broken message");
+ memcpy(&message, buffer, sizeof(message));
+ if (message.callback)
+ xbt_die("Support for callbacks/functions symbols not implemented in client/server mode.");
+ XBT_DEBUG("Received symbol: %s", message.name);
+
+ struct mc_symbol_pointer_callback* callback = xbt_new(struct mc_symbol_pointer_callback, 1);
+ callback->process = &mc_model_checker->process;
+ callback->value = message.data;
+
+ MC_automaton_new_propositional_symbol_callback(message.name,
+ mc_symbol_pointer_callback_evaluate, callback, free);
+ break;
+ }
+
+ case MC_MESSAGE_WAITING:
+ return false;
+
+ case MC_MESSAGE_ASSERTION_FAILED:
+ MC_report_assertion_error();
+ xbt_abort();
+ break;
+
+ default:
+ xbt_die("Unexpected message from model-checked application");
+
+ }
+ return true;
+ }
+ if (socket_pollfd->revents & POLLERR) {
+ throw_socket_error(socket_pollfd->fd);
+ }
+ if (socket_pollfd->revents & POLLHUP)
+ xbt_die("Socket hang up?");
+ }
+
+ if (signalfd_pollfd->revents) {
+ if (signalfd_pollfd->revents & POLLIN) {
+ this->handle_signals();
+ return true;
+ }
+ if (signalfd_pollfd->revents & POLLERR) {
+ throw_socket_error(signalfd_pollfd->fd);
+ }
+ if (signalfd_pollfd->revents & POLLHUP)
+ xbt_die("Signalfd hang up?");
+ }
+
+ return true;
+}
+
+void s_mc_server::loop()
+{
+ while (mc_model_checker->process.running)
+ this->handle_events();
+}
+
+void s_mc_server::handle_signals()
+{
+ struct signalfd_siginfo info;
+ struct pollfd* signalfd_pollfd = &fds[SIGNAL_FD_INDEX];
+ while (1) {
+ ssize_t size = read(signalfd_pollfd->fd, &info, sizeof(info));
+ if (size == -1) {
+ if (errno == EINTR)
+ continue;
+ else
+ throw std::system_error(errno, std::system_category());
+ } else if (size != sizeof(info))
+ return throw std::runtime_error(
+ "Bad communication with model-checked application");
+ else
+ break;
+ }
+ this->on_signal(&info);
+}
+
+void s_mc_server::handle_waitpid()
+{
+ XBT_DEBUG("Check for wait event");
+ int status;
+ pid_t pid;
+ while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
+ if (pid == -1) {
+ if (errno == ECHILD) {
+ // No more children:
+ if (mc_model_checker->process.running)
+ xbt_die("Inconsistent state");
+ else
+ break;
+ } else {
+ XBT_ERROR("Could not wait for pid");
+ throw std::system_error(errno, std::system_category());
+ }
+ }
+
+ if (pid == mc_model_checker->process.pid) {
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ XBT_DEBUG("Child process is over");
+ mc_model_checker->process.status = status;
+ mc_model_checker->process.running = false;
+ }
+ }
+ }
+}
+
+void s_mc_server::on_signal(const struct signalfd_siginfo* info)
+{
+ switch(info->ssi_signo) {
+ case SIGCHLD:
+ this->handle_waitpid();
+ break;
+ default:
+ break;
+ }
+}
+
+void MC_server_wait_client(mc_process_t process)
+{
+ mc_server->resume(process);
+ while (mc_model_checker->process.running) {
+ if (!mc_server->handle_events())
+ return;
+ }
+}
+
+void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value)
+{
+ s_mc_simcall_handle_message m;
+ memset(&m, 0, sizeof(m));
+ m.type = MC_MESSAGE_SIMCALL_HANDLE;
+ m.pid = pid;
+ m.value = value;
+ MC_protocol_send(mc_model_checker->process.socket, &m, sizeof(m));
+ process->cache_flags = (e_mc_process_cache_flags_t) 0;
+ while (mc_model_checker->process.running) {
+ if (!mc_server->handle_events())
+ return;
+ }
+}
+
+void MC_server_loop(mc_server_t server)
+{
+ server->loop();
+}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_SERVER_H
+#define MC_SERVER_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <sys/signalfd.h>
+#include <sys/types.h>
+
+#include <xbt/misc.h>
+
+#include "mc_process.h"
+
+SG_BEGIN_DECL()
+
+#define MC_SERVER_ERROR 127
+
+typedef struct s_mc_server s_mc_server_t, *mc_server_t;
+
+extern mc_server_t mc_server;
+
+void MC_server_wait_client(mc_process_t process);
+void MC_server_simcall_handle(mc_process_t process, unsigned long pid, int value);
+
+void MC_server_loop(mc_server_t server);
+
+SG_END_DECL()
+
+#ifdef __cplusplus
+
+struct s_mc_server {
+private:
+ pid_t pid;
+ int socket;
+ struct pollfd fds[2];
+public:
+ s_mc_server(pid_t pid, int socket);
+ void start();
+ void shutdown();
+ void exit();
+ void resume(mc_process_t process);
+ void loop();
+ bool handle_events();
+protected:
+ void handle_signals();
+ void handle_waitpid();
+ void on_signal(const struct signalfd_siginfo* info);
+};
+
+#endif
+
+#endif
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <assert.h>
+
+#include <xbt/log.h>
+
+#include "simix/smx_private.h"
+
+#include "mc_smx.h"
+#include "mc_model_checker.h"
+
+static
+void MC_smx_process_info_clear(mc_smx_process_info_t p)
+{
+ p->hostname = NULL;
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ free(p->name);
+ mmalloc_set_current_heap(heap);
+
+ p->name = NULL;
+}
+
+xbt_dynar_t MC_smx_process_info_list_new(void)
+{
+ return xbt_dynar_new(
+ sizeof(s_mc_smx_process_info_t),
+ ( void_f_pvoid_t) &MC_smx_process_info_clear);
+}
+
+static inline
+bool is_in_dynar(smx_process_t p, xbt_dynar_t dynar)
+{
+ return (uintptr_t) p >= (uintptr_t) dynar->data
+ && (uintptr_t) p < ((uintptr_t) dynar->data + dynar->used * dynar->elmsize);
+}
+
+static inline
+mc_smx_process_info_t MC_smx_process_get_info(smx_process_t p)
+{
+ assert(is_in_dynar(p, mc_model_checker->process.smx_process_infos)
+ || is_in_dynar(p, mc_model_checker->process.smx_old_process_infos));
+ mc_smx_process_info_t process_info =
+ (mc_smx_process_info_t)
+ ((char*) p - offsetof(s_mc_smx_process_info_t, copy));
+ return process_info;
+}
+
+/** Load the remote swag of processes into a dynar
+ *
+ * @param process MCed process
+ * @param target Local dynar (to be filled with copies of `s_smx_process_t`)
+ * @param remote_swag Address of the process SWAG in the remote list
+ */
+static void MC_process_refresh_simix_process_list(
+ mc_process_t process,
+ xbt_dynar_t target, xbt_swag_t remote_swag)
+{
+ // swag = REMOTE(*simix_global->process_list)
+ s_xbt_swag_t swag;
+ MC_process_read(process, MC_PROCESS_NO_FLAG, &swag, remote_swag, sizeof(swag),
+ MC_PROCESS_INDEX_ANY);
+
+ smx_process_t p;
+ xbt_dynar_reset(target);
+
+ // Load each element of the dynar from the MCed process:
+ int i = 0;
+ for (p = swag.head; p; ++i) {
+
+ s_mc_smx_process_info_t info;
+ info.address = p;
+ info.name = NULL;
+ info.hostname = NULL;
+ MC_process_read(process, MC_PROCESS_NO_FLAG,
+ &info.copy, p, sizeof(info.copy), MC_PROCESS_INDEX_ANY);
+ xbt_dynar_push(target, &info);
+
+ // Lookup next process address:
+ p = xbt_swag_getNext(&info.copy, swag.offset);
+ }
+ assert(i == swag.count);
+}
+
+void MC_process_smx_refresh(mc_process_t process)
+{
+ if (process->cache_flags & MC_PROCESS_CACHE_FLAG_SIMIX_PROCESSES)
+ return;
+
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+
+ // TODO, avoid to reload `&simix_global`, `simix_global`, `*simix_global`
+
+ // simix_global_p = REMOTE(simix_global);
+ smx_global_t simix_global_p;
+ MC_process_read_variable(process, "simix_global", &simix_global_p, sizeof(simix_global_p));
+
+ // simix_global = REMOTE(*simix_global)
+ s_smx_global_t simix_global;
+ MC_process_read(process, MC_PROCESS_NO_FLAG, &simix_global, simix_global_p, sizeof(simix_global),
+ MC_PROCESS_INDEX_ANY);
+
+ MC_process_refresh_simix_process_list(
+ process, process->smx_process_infos, simix_global.process_list);
+ MC_process_refresh_simix_process_list(
+ process, process->smx_old_process_infos, simix_global.process_to_destroy);
+
+ process->cache_flags |= MC_PROCESS_CACHE_FLAG_SIMIX_PROCESSES;
+ mmalloc_set_current_heap(heap);
+}
+
+/** Get the issuer of a simcall (`req->issuer`)
+ *
+ * In split-process mode, it does the black magic necessary to get an address
+ * of a (shallow) copy of the data structure the issuer SIMIX process in the local
+ * address space.
+ *
+ * @param process the MCed process
+ * @param req the simcall (copied in the local process)
+ */
+smx_process_t MC_smx_simcall_get_issuer(smx_simcall_t req)
+{
+ if (MC_process_is_self(&mc_model_checker->process))
+ return req->issuer;
+
+ MC_process_smx_refresh(&mc_model_checker->process);
+
+ // This is the address of the smx_process in the MCed process:
+ void* address = req->issuer;
+
+ unsigned i;
+ mc_smx_process_info_t p;
+
+ // Lookup by address:
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_process_infos, i, p)
+ if (p->address == address)
+ return &p->copy;
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_old_process_infos, i, p)
+ if (p->address == address)
+ return &p->copy;
+
+ xbt_die("Issuer not found");
+}
+
+smx_process_t MC_smx_resolve_process(smx_process_t process_remote_address)
+{
+ if (!process_remote_address)
+ return NULL;
+ if (MC_process_is_self(&mc_model_checker->process))
+ return process_remote_address;
+
+ mc_smx_process_info_t process_info = MC_smx_resolve_process_info(process_remote_address);
+ if (process_info)
+ return &process_info->copy;
+ else
+ return NULL;
+}
+
+mc_smx_process_info_t MC_smx_resolve_process_info(smx_process_t process_remote_address)
+{
+ if (MC_process_is_self(&mc_model_checker->process))
+ xbt_die("No process_info for local process is not enabled.");
+
+ unsigned index;
+ mc_smx_process_info_t process_info;
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_process_infos, index, process_info)
+ if (process_info->address == process_remote_address)
+ return process_info;
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_old_process_infos, index, process_info)
+ if (process_info->address == process_remote_address)
+ return process_info;
+ xbt_die("Process info not found");
+}
+
+const char* MC_smx_process_get_host_name(smx_process_t p)
+{
+ if (MC_process_is_self(&mc_model_checker->process))
+ return SIMIX_host_get_name(p->smx_host);
+
+ mc_process_t process = &mc_model_checker->process;
+
+ // Currently, smx_host_t = xbt_dictelm_t.
+ // TODO, add an static_assert on this if switching to C++
+ // The host name is host->key and the host->key_len==strlen(host->key).
+ s_xbt_dictelm_t host_copy;
+ mc_smx_process_info_t info = MC_smx_process_get_info(p);
+ if (!info->hostname) {
+
+ // Read the hostname from the MCed process:
+ MC_process_read_simple(process, &host_copy, p->smx_host, sizeof(host_copy));
+ int len = host_copy.key_len + 1;
+ char hostname[len];
+ MC_process_read_simple(process, hostname, host_copy.key, len);
+
+ // Lookup the host name in the dictionary (or create it):
+ xbt_dictelm_t elt = xbt_dict_get_elm_or_null(mc_model_checker->hosts, hostname);
+ if (!elt) {
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ xbt_dict_set(mc_model_checker->hosts, hostname, NULL, NULL);
+ elt = xbt_dict_get_elm_or_null(mc_model_checker->hosts, hostname);
+ assert(elt);
+ mmalloc_set_current_heap(heap);
+ }
+
+ info->hostname = elt->key;
+ }
+ return info->hostname;
+}
+
+const char* MC_smx_process_get_name(smx_process_t p)
+{
+ mc_process_t process = &mc_model_checker->process;
+ if (MC_process_is_self(process))
+ return p->name;
+ if (!p->name)
+ return NULL;
+
+ mc_smx_process_info_t info = MC_smx_process_get_info(p);
+ if (!info->name) {
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
+ info->name = MC_process_read_string(process, p->name);
+ mmalloc_set_current_heap(heap);
+ }
+ return info->name;
+}
+
+int MC_smpi_process_count(void)
+{
+ if (MC_process_is_self(&mc_model_checker->process))
+ return smpi_process_count();
+ else {
+ int res;
+ MC_process_read_variable(&mc_model_checker->process, "process_count",
+ &res, sizeof(res));
+ return res;
+ }
+}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_SMX_H
+#define MC_SMX_H
+
+#include <stddef.h>
+
+#include <xbt/log.h>
+#include <simgrid/simix.h>
+
+#include "smpi/private.h"
+
+#include "mc_process.h"
+#include "mc_protocol.h"
+
+/** @file
+ * @brief (Cross-process, MCer/MCed) Access to SMX structures
+ *
+ * We copy some C data structure from the MCed process in the MCer process.
+ * This is implemented by:
+ *
+ * - `model_checker->process.smx_process_infos`
+ * (copy of `simix_global->process_list`);
+ *
+ * - `model_checker->process.smx_old_process_infos`
+ * (copy of `simix_global->process_to_destroy`);
+ *
+ * - `model_checker->hostnames`.
+ *
+ * The process lists are currently refreshed each time MCed code is executed.
+ * We don't try to give a persistent MCer address for a given MCed process.
+ * For this reason, a MCer mc_process_t is currently not reusable after
+ * MCed code.
+ */
+
+SG_BEGIN_DECL()
+
+struct s_mc_smx_process_info {
+ /** MCed address of the process */
+ void* address;
+ /** (Flat) Copy of the process data structure */
+ struct s_smx_process copy;
+ /** Hostname (owned by `mc_modelchecker->hostnames`) */
+ char* hostname;
+ char* name;
+};
+
+xbt_dynar_t MC_smx_process_info_list_new(void);
+
+void MC_process_smx_refresh(mc_process_t process);
+
+/** Get the issuer of a simcall (`req->issuer`)
+ *
+ * In split-process mode, it does the black magic necessary to get an address
+ * of a (shallow) copy of the data structure the issuer SIMIX process in the local
+ * address space.
+ *
+ * @param process the MCed process
+ * @param req the simcall (copied in the local process)
+ */
+smx_process_t MC_smx_simcall_get_issuer(smx_simcall_t req);
+
+const char* MC_smx_process_get_name(smx_process_t p);
+const char* MC_smx_process_get_host_name(smx_process_t p);
+
+#define MC_EACH_SIMIX_PROCESS(process, code) \
+ if (MC_process_is_self(&mc_model_checker->process)) { \
+ xbt_swag_foreach(process, simix_global->process_list) { \
+ code; \
+ } \
+ } else { \
+ MC_process_smx_refresh(&mc_model_checker->process); \
+ unsigned int _smx_process_index; \
+ mc_smx_process_info_t _smx_process_info; \
+ xbt_dynar_foreach_ptr(mc_model_checker->process.smx_process_infos, _smx_process_index, _smx_process_info) { \
+ smx_process_t process = &_smx_process_info->copy; \
+ code; \
+ } \
+ }
+
+/** Execute a given simcall */
+void MC_simcall_handle(smx_simcall_t req, int value);
+
+int MC_smpi_process_count(void);
+
+
+/* ***** Resolve (local/MCer structure from remote/MCed addresses) ***** */
+
+/** Get a local copy of the process from the process remote address */
+smx_process_t MC_smx_resolve_process(smx_process_t process_remote_address);
+
+/** Get the process info structure from the process remote address */
+mc_smx_process_info_t MC_smx_resolve_process_info(smx_process_t process_remote_address);
+
+SG_END_DECL()
+
+#endif
* @param Snapshot region in the snapshot this pointer belongs to
* (or NULL if it does not belong to any snapshot region)
* */
-mc_mem_region_t mc_get_snapshot_region(void* addr, mc_snapshot_t snapshot, int process_index)
+mc_mem_region_t mc_get_snapshot_region(const void* addr, mc_snapshot_t snapshot, int process_index)
{
-#ifdef HAVE_SMPI
- if (snapshot->privatization_regions) {
-
- if (process_index < 0) {
+ size_t n = snapshot->snapshot_regions_count;
+ for (size_t i = 0; i != n; ++i) {
+ mc_mem_region_t region = snapshot->snapshot_regions[i];
+ if (!(region && mc_region_contain(region, addr)))
+ continue;
- mc_mem_region_t region = snapshot->privatization_regions[0];
- if( mc_region_contain(region, addr) ) {
+ if (region->storage_type == MC_REGION_STORAGE_TYPE_PRIVATIZED) {
+#ifdef HAVE_SMPI
+ // Use the current process index of the snapshot:
+ if (process_index == MC_PROCESS_INDEX_DISABLED) {
+ process_index = snapshot->privatization_index;
+ }
+ if (process_index < 0) {
xbt_die("Missing process index");
}
-
- } else {
- if (process_index >= smpi_process_count()) {
+ if (process_index >= region->privatized.regions_count) {
xbt_die("Invalid process index");
}
-
- mc_mem_region_t region = snapshot->privatization_regions[process_index];
- if( mc_region_contain(region, addr) ) {
- return region;
- }
-
- }
- }
+ mc_mem_region_t priv_region = region->privatized.regions[process_index];
+ xbt_assert(mc_region_contain(priv_region, addr));
+ return priv_region;
+#else
+ xbt_die("Privatized region in a non SMPI build (this should not happen)");
#endif
-
- for (size_t i = 0; i != NB_REGIONS; ++i) {
- mc_mem_region_t region = snapshot->regions[i];
- if ( region && mc_region_contain(region, addr) ) {
- return region;
}
+
+ return region;
}
return NULL;
* @param size Size of the data to read in bytes
* @return Pointer where the data is located (target buffer of original location)
*/
-void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size)
+const void* MC_region_read_fragmented(mc_mem_region_t region, void* target, const void* addr, size_t size)
{
// Last byte of the memory area:
void* end = (char*) addr + size - 1;
* @param size Size of the data to read in bytes
* @return Pointer where the data is located (target buffer or original location)
*/
-void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, int process_index, void* target, size_t size)
+const void* MC_snapshot_read(
+ mc_snapshot_t snapshot, e_adress_space_read_flags_t flags,
+ void* target, const void* addr, size_t size, int process_index)
{
- if (snapshot) {
- mc_mem_region_t region = mc_get_snapshot_region(addr, snapshot, process_index);
- return mc_snapshot_read_region(addr, region, target, size);
- } else {
- return addr;
- }
+ mc_mem_region_t region = mc_get_snapshot_region(addr, snapshot, process_index);
+ if (region)
+ return MC_region_read(region, target, addr, size);
+ else
+ return MC_process_read(snapshot->process, flags, target, addr, size, process_index);
}
/** Compare memory between snapshots (with known regions)
* @param snapshot2 Region of the address in the second snapshot
* @return same as memcmp
* */
-int mc_snapshot_region_memcmp(
- void* addr1, mc_mem_region_t region1,
- void* addr2, mc_mem_region_t region2,
+int MC_snapshot_region_memcmp(
+ const void* addr1, mc_mem_region_t region1,
+ const void* addr2, mc_mem_region_t region2,
size_t size)
{
// Using alloca() for large allocations may trigger stack overflow:
// use malloc if the buffer is too big.
bool stack_alloc = size < 64;
- void* buffer1a = (region1==NULL || region1->data) ? NULL : stack_alloc ? alloca(size) : malloc(size);
- void* buffer2a = (region2==NULL || region2->data) ? NULL : stack_alloc ? alloca(size) : malloc(size);
- void* buffer1 = mc_snapshot_read_region(addr1, region1, buffer1a, size);
- void* buffer2 = mc_snapshot_read_region(addr2, region2, buffer2a, size);
+ const bool region1_need_buffer = region1==NULL || region1->storage_type==MC_REGION_STORAGE_TYPE_FLAT;
+ const bool region2_need_buffer = region2==NULL || region2->storage_type==MC_REGION_STORAGE_TYPE_FLAT;
+ void* buffer1a = region1_need_buffer ? NULL : stack_alloc ? alloca(size) : malloc(size);
+ void* buffer2a = region2_need_buffer ? NULL : stack_alloc ? alloca(size) : malloc(size);
+ const void* buffer1 = MC_region_read(region1, buffer1a, addr1, size);
+ const void* buffer2 = MC_region_read(region2, buffer2a, addr2, size);
int res;
if (buffer1 == buffer2) {
res = 0;
* @param snapshot2 Second snapshot
* @return same as memcmp
* */
-int mc_snapshot_memcmp(
- void* addr1, mc_snapshot_t snapshot1,
- void* addr2, mc_snapshot_t snapshot2, int process_index, size_t size)
+int MC_snapshot_memcmp(
+ const void* addr1, mc_snapshot_t snapshot1,
+ const void* addr2, mc_snapshot_t snapshot2, int process_index, size_t size)
{
mc_mem_region_t region1 = mc_get_snapshot_region(addr1, snapshot1, process_index);
mc_mem_region_t region2 = mc_get_snapshot_region(addr2, snapshot2, process_index);
- return mc_snapshot_region_memcmp(addr1, region1, addr2, region2, size);
+ return MC_snapshot_region_memcmp(addr1, region1, addr2, region2, size);
}
#ifdef SIMGRID_TEST
// Init memory and take snapshots:
init_memory(source, byte_size);
- mc_mem_region_t region0 = mc_region_new_sparse(0, source, source, byte_size, NULL);
+ mc_mem_region_t region0 = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
for(int i=0; i<n; i+=2) {
init_memory((char*) source + i*xbt_pagesize, xbt_pagesize);
}
- mc_mem_region_t region = mc_region_new_sparse(0, source, source, byte_size, NULL);
+ mc_mem_region_t region = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
void* destination = mmap(NULL, byte_size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
xbt_assert(source!=MAP_FAILED, "Could not allocate destination memory");
xbt_test_add("Reading whole region data for %i page(s)", n);
- void* read = mc_snapshot_read_region(source, region, destination, byte_size);
- xbt_test_assert(!memcmp(source, read, byte_size), "Mismatch in mc_snapshot_read_region()");
+ const void* read = MC_region_read(region, source, destination, byte_size);
+ xbt_test_assert(!memcmp(source, read, byte_size), "Mismatch in MC_region_read()");
xbt_test_add("Reading parts of region data for %i page(s)", n);
for(int j=0; j!=100; ++j) {
size_t offset = rand() % byte_size;
size_t size = rand() % (byte_size - offset);
- void* read = mc_snapshot_read_region((char*) source+offset, region, destination, size);
+ const void* read = MC_region_read(region, destination, (const char*) source+offset, size);
xbt_test_assert(!memcmp((char*) source+offset, read, size),
- "Mismatch in mc_snapshot_read_region()");
+ "Mismatch in MC_region_read()");
}
xbt_test_add("Compare whole region data for %i page(s)", n);
- xbt_test_assert(!mc_snapshot_region_memcmp(source, NULL, source, region, byte_size),
- "Mismatch in mc_snapshot_region_memcmp() for the whole region");
- xbt_test_assert(mc_snapshot_region_memcmp(source, region0, source, region, byte_size),
- "Unexpected match in mc_snapshot_region_memcmp() with previous snapshot");
+ xbt_test_assert(!MC_snapshot_region_memcmp(source, NULL, source, region, byte_size),
+ "Mismatch in MC_snapshot_region_memcmp() for the whole region");
+ xbt_test_assert(MC_snapshot_region_memcmp(source, region0, source, region, byte_size),
+ "Unexpected match in MC_snapshot_region_memcmp() with previous snapshot");
xbt_test_add("Compare parts of region data for %i page(s) with current value", n);
for(int j=0; j!=100; ++j) {
size_t offset = rand() % byte_size;
size_t size = rand() % (byte_size - offset);
- xbt_test_assert(!mc_snapshot_region_memcmp((char*) source+offset, NULL, (char*) source+offset, region, size),
- "Mismatch in mc_snapshot_region_memcmp()");
+ xbt_test_assert(!MC_snapshot_region_memcmp((char*) source+offset, NULL, (char*) source+offset, region, size),
+ "Mismatch in MC_snapshot_region_memcmp()");
}
xbt_test_add("Compare parts of region data for %i page(s) with itself", n);
for(int j=0; j!=100; ++j) {
size_t offset = rand() % byte_size;
size_t size = rand() % (byte_size - offset);
- xbt_test_assert(!mc_snapshot_region_memcmp((char*) source+offset, region, (char*) source+offset, region, size),
- "Mismatch in mc_snapshot_region_memcmp()");
+ xbt_test_assert(!MC_snapshot_region_memcmp((char*) source+offset, region, (char*) source+offset, region, size),
+ "Mismatch in MC_snapshot_region_memcmp()");
}
if (n==1) {
xbt_test_add("Read pointer for %i page(s)", n);
memcpy(source, &mc_model_checker, sizeof(void*));
- mc_mem_region_t region2 = mc_region_new_sparse(0, source, source, byte_size, NULL);
- xbt_test_assert(mc_snapshot_read_pointer_region(source, region2) == mc_model_checker,
- "Mismtach in mc_snapshot_read_pointer_region()");
+ mc_mem_region_t region2 = mc_region_new_sparse(MC_REGION_TYPE_UNKNOWN, source, source, byte_size, NULL);
+ xbt_test_assert(MC_region_read_pointer(region2, source) == mc_model_checker,
+ "Mismtach in MC_region_read_pointer()");
MC_region_destroy(region2);
}
#include "mc_model_checker.h"
#include "mc_page_store.h"
#include "mc_mmalloc.h"
+#include "mc_address_space.h"
+#include "mc_unw.h"
SG_BEGIN_DECL()
// ***** Snapshot region
-#define NB_REGIONS 3 /* binary data (data + BSS) (type = 2), libsimgrid data (data + BSS) (type = 1), std_heap (type = 0)*/
+typedef enum e_mc_region_type_t {
+ MC_REGION_TYPE_UNKNOWN = 0,
+ MC_REGION_TYPE_HEAP = 1,
+ MC_REGION_TYPE_DATA = 2
+} mc_region_type_t;
+
+// TODO, use OO instead of this
+typedef enum e_mc_region_storeage_type_t {
+ MC_REGION_STORAGE_TYPE_NONE = 0,
+ MC_REGION_STORAGE_TYPE_FLAT = 1,
+ MC_REGION_STORAGE_TYPE_CHUNKED = 2,
+ MC_REGION_STORAGE_TYPE_PRIVATIZED = 3
+} mc_region_storage_type_t;
/** @brief Copy/snapshot of a given memory region
*
- * Two types of region snapshots exist:
+ * Different types of region snapshot storage types exist:
* <ul>
* <li>flat/dense snapshots are a simple copy of the region;</li>
* <li>sparse/per-page snapshots are snaapshots which shared
* identical pages.</li>
+ * <li>privatized (SMPI global variable privatisation).
* </ul>
+ *
+ * This is handled with a variant based approch:
+ *
+ * * `storage_type` identified the type of storage;
+ * * an anonymous enum is used to distinguish the relevant types for
+ * each type.
*/
-typedef struct s_mc_mem_region{
+typedef struct s_mc_mem_region s_mc_mem_region_t, *mc_mem_region_t;
+
+struct s_mc_mem_region {
+ mc_region_type_t region_type;
+ mc_region_storage_type_t storage_type;
+ mc_object_info_t object_info;
+
/** @brief Virtual address of the region in the simulated process */
void *start_addr;
+ /** @brief Size of the data region in bytes */
+ size_t size;
+
/** @brief Permanent virtual address of the region
*
* This is usually the same address as the simuilated process address.
* */
void *permanent_addr;
- /** @brief Copy of the snapshot for flat snapshots regions (NULL otherwise) */
- void *data;
+ union {
+ struct {
+ /** @brief Copy of the snapshot for flat snapshots regions (NULL otherwise) */
+ void *data;
+ } flat;
+ struct {
+ /** @brief Pages indices in the page store for per-page snapshots (NULL otherwise) */
+ size_t* page_numbers;
+ } chunked;
+ struct {
+ size_t regions_count;
+ mc_mem_region_t* regions;
+ } privatized;
+ };
- /** @brief Size of the data region in bytes */
- size_t size;
-
- /** @brief Pages indices in the page store for per-page snapshots (NULL otherwise) */
- size_t* page_numbers;
-
-} s_mc_mem_region_t, *mc_mem_region_t;
+};
-mc_mem_region_t mc_region_new_sparse(int type, void *start_addr, void* data_addr, size_t size, mc_mem_region_t ref_reg);
+mc_mem_region_t mc_region_new_sparse(mc_region_type_t type, void *start_addr, void* data_addr, size_t size, mc_mem_region_t ref_reg);
void MC_region_destroy(mc_mem_region_t reg);
-void mc_region_restore_sparse(mc_mem_region_t reg, mc_mem_region_t ref_reg);
+void mc_region_restore_sparse(mc_process_t process, mc_mem_region_t reg, mc_mem_region_t ref_reg);
static inline __attribute__ ((always_inline))
-bool mc_region_contain(mc_mem_region_t region, void* p)
+bool mc_region_contain(mc_mem_region_t region, const void* p)
{
return p >= region->start_addr &&
p < (void*)((char*) region->start_addr + region->size);
void* mc_translate_address_region(uintptr_t addr, mc_mem_region_t region)
{
size_t pageno = mc_page_number(region->start_addr, (void*) addr);
- size_t snapshot_pageno = region->page_numbers[pageno];
+ size_t snapshot_pageno = region->chunked.page_numbers[pageno];
const void* snapshot_page = mc_page_store_get_page(mc_model_checker->pages, snapshot_pageno);
return (char*) snapshot_page + mc_page_offset((void*) addr);
}
-mc_mem_region_t mc_get_snapshot_region(void* addr, mc_snapshot_t snapshot, int process_index);
+mc_mem_region_t mc_get_snapshot_region(const void* addr, mc_snapshot_t snapshot, int process_index);
/** \brief Translate a pointer from process address space to snapshot address space
*
return (void *) addr;
}
- // Flat snapshot:
- else if (region->data) {
- uintptr_t offset = addr - (uintptr_t) region->start_addr;
- return (void *) ((uintptr_t) region->data + offset);
- }
+ switch (region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ {
+ uintptr_t offset = addr - (uintptr_t) region->start_addr;
+ return (void *) ((uintptr_t) region->flat.data + offset);
+ }
- // Per-page snapshot:
- else if (region->page_numbers) {
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
return mc_translate_address_region(addr, region);
- }
- else {
- xbt_die("No data for this memory region");
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ {
+ xbt_assert(process_index >=0,
+ "Missing process index for privatized region");
+ xbt_assert((size_t) process_index < region->privatized.regions_count,
+ "Out of range process index");
+ mc_mem_region_t subregion = region->privatized.regions[process_index];
+ xbt_assert(subregion, "Missing memory region for process %i", process_index);
+ return mc_translate_address(addr, snapshot, process_index);
+ }
}
}
int flags;
}s_fd_infos_t, *fd_infos_t;
-struct s_mc_snapshot{
+struct s_mc_snapshot {
+ mc_process_t process;
+ int num_state;
+ s_mc_address_space_t address_space;
size_t heap_bytes_used;
- mc_mem_region_t regions[NB_REGIONS];
+ mc_mem_region_t* snapshot_regions;
+ size_t snapshot_regions_count;
xbt_dynar_t enabled_processes;
- mc_mem_region_t* privatization_regions;
int privatization_index;
size_t *stack_sizes;
xbt_dynar_t stacks;
fd_infos_t *current_fd;
};
-/** @brief Process index used when no process is available
- *
- * The expected behaviour is that if a process index is needed it will fail.
- * */
-#define MC_NO_PROCESS_INDEX -1
-
-/** @brief Process index when any process is suitable
- *
- * We could use a special negative value in the future.
- */
-#define MC_ANY_PROCESS_INDEX 0
-
static inline __attribute__ ((always_inline))
mc_mem_region_t mc_get_region_hinted(void* addr, mc_snapshot_t snapshot, int process_index, mc_mem_region_t region)
{
typedef struct s_mc_snapshot_stack{
xbt_dynar_t local_variables;
+ mc_unw_context_t context;
xbt_dynar_t stack_frames; // mc_stack_frame_t
int process_index;
}s_mc_snapshot_stack_t, *mc_snapshot_stack_t;
-typedef struct s_mc_global_t{
+typedef struct s_mc_global_t {
mc_snapshot_t snapshot;
int raw_mem_set;
int prev_pair;
size_t size;
}s_mc_checkpoint_ignore_region_t, *mc_checkpoint_ignore_region_t;
-static void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot);
+static const void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot);
mc_snapshot_t MC_take_snapshot(int num_state);
void MC_restore_snapshot(mc_snapshot_t);
int mc_important_snapshot(mc_snapshot_t snapshot);
-size_t* mc_take_page_snapshot_region(void* data, size_t page_count, uint64_t* pagemap, size_t* reference_pages);
+size_t* mc_take_page_snapshot_region(mc_process_t process,
+ void* data, size_t page_count, uint64_t* pagemap, size_t* reference_pages);
void mc_free_page_snapshot_region(size_t* pagenos, size_t page_count);
-void mc_restore_page_snapshot_region(void* start_addr, size_t page_count, size_t* pagenos, uint64_t* pagemap, size_t* reference_pagenos);
-
-static inline __attribute__((always_inline))
-bool mc_snapshot_region_linear(mc_mem_region_t region) {
- return !region || !region->data;
-}
-
-void* mc_snapshot_read_fragmented(void* addr, mc_mem_region_t region, void* target, size_t size);
-
-void* mc_snapshot_read(void* addr, mc_snapshot_t snapshot, int process_index, void* target, size_t size);
-int mc_snapshot_region_memcmp(
- void* addr1, mc_mem_region_t region1,
- void* addr2, mc_mem_region_t region2, size_t size);
-int mc_snapshot_memcmp(
- void* addr1, mc_snapshot_t snapshot1,
- void* addr2, mc_snapshot_t snapshot2, int process_index, size_t size);
-
-static void* mc_snapshot_read_pointer(void* addr, mc_snapshot_t snapshot, int process_index);
+void mc_restore_page_snapshot_region(
+ mc_process_t process,
+ void* start_addr, size_t page_count, size_t* pagenos,
+ uint64_t* pagemap, size_t* reference_pagenos);
+
+const void* MC_region_read_fragmented(mc_mem_region_t region, void* target, const void* addr, size_t size);
+
+const void* MC_snapshot_read(mc_snapshot_t snapshot, e_adress_space_read_flags_t flags,
+ void* target, const void* addr, size_t size, int process_index);
+int MC_snapshot_region_memcmp(
+ const void* addr1, mc_mem_region_t region1,
+ const void* addr2, mc_mem_region_t region2, size_t size);
+int MC_snapshot_memcmp(
+ const void* addr1, mc_snapshot_t snapshot1,
+ const void* addr2, mc_snapshot_t snapshot2, int process_index, size_t size);
static inline __attribute__ ((always_inline))
-void* mc_snapshot_read_pointer(void* addr, mc_snapshot_t snapshot, int process_index)
+const void* MC_snapshot_read_pointer(mc_snapshot_t snapshot, const void* addr, int process_index)
{
void* res;
- return *(void**) mc_snapshot_read(addr, snapshot, process_index, &res, sizeof(void*));
+ return *(const void**) MC_snapshot_read(snapshot, MC_ADDRESS_SPACE_READ_FLAGS_LAZY,
+ &res, addr, sizeof(void*), process_index);
}
static inline __attribute__ ((always_inline))
- void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot) {
+const void* mc_snapshot_get_heap_end(mc_snapshot_t snapshot)
+{
if(snapshot==NULL)
xbt_die("snapshot is NULL");
- void** addr = &(std_heap->breakval);
- return mc_snapshot_read_pointer(addr, snapshot, MC_ANY_PROCESS_INDEX);
+ return MC_process_get_heap(&mc_model_checker->process)->breakval;
}
/** @brief Read memory from a snapshot region
* @return Pointer where the data is located (target buffer of original location)
*/
static inline __attribute__((always_inline))
-void* mc_snapshot_read_region(void* addr, mc_mem_region_t region, void* target, size_t size)
+const void* MC_region_read(mc_mem_region_t region, void* target, const void* addr, size_t size)
{
if (region==NULL)
+ // Should be deprecated:
return addr;
uintptr_t offset = (char*) addr - (char*) region->start_addr;
xbt_assert(mc_region_contain(region, addr),
"Trying to read out of the region boundary.");
- // Linear memory region:
- if (region->data) {
- return (char*) region->data + offset;
- }
-
- // Fragmented memory region:
- else if (region->page_numbers) {
- // Last byte of the region:
- void* end = (char*) addr + size - 1;
- if( mc_same_page(addr, end) ) {
- // The memory is contained in a single page:
- return mc_translate_address_region((uintptr_t) addr, region);
- } else {
- // The memory spans several pages:
- return mc_snapshot_read_fragmented(addr, region, target, size);
+ switch (region->storage_type) {
+ case MC_REGION_STORAGE_TYPE_NONE:
+ default:
+ xbt_die("Storage type not supported");
+
+ case MC_REGION_STORAGE_TYPE_FLAT:
+ return (char*) region->flat.data + offset;
+
+ case MC_REGION_STORAGE_TYPE_CHUNKED:
+ {
+ // Last byte of the region:
+ void* end = (char*) addr + size - 1;
+ if (mc_same_page(addr, end) ) {
+ // The memory is contained in a single page:
+ return mc_translate_address_region((uintptr_t) addr, region);
+ } else {
+ // The memory spans several pages:
+ return MC_region_read_fragmented(region, target, addr, size);
+ }
}
- }
- else {
- xbt_die("No data available for this region");
+ // We currently do not pass the process_index to this function so we assume
+ // that the privatized region has been resolved in the callers:
+ case MC_REGION_STORAGE_TYPE_PRIVATIZED:
+ xbt_die("Storage type not supported");
}
}
static inline __attribute__ ((always_inline))
-void* mc_snapshot_read_pointer_region(void* addr, mc_mem_region_t region)
+void* MC_region_read_pointer(mc_mem_region_t region, const void* addr)
{
void* res;
- return *(void**) mc_snapshot_read_region(addr, region, &res, sizeof(void*));
+ return *(void**) MC_region_read(region, &res, addr, sizeof(void*));
}
SG_END_DECL()
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <assert.h>
+
#include "../simix/smx_private.h"
#include "xbt/fifo.h"
#include "mc_state.h"
#include "mc_request.h"
#include "mc_private.h"
#include "mc_comm_pattern.h"
+#include "mc_smx.h"
-static void copy_incomplete_communications_pattern(mc_state_t state) {
- int i;
- xbt_dynar_t incomplete_process_comms;
- mc_comm_pattern_t comm;
- unsigned int cursor;
- state->incomplete_comm_pattern = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
- for (i=0; i<simix_process_maxpid; i++) {
- incomplete_process_comms = xbt_dynar_get_as(incomplete_communications_pattern, i, xbt_dynar_t);
- xbt_dynar_t incomplete_process_comms_copy = xbt_dynar_new(sizeof(mc_comm_pattern_t), comm_pattern_free_voidp);
- xbt_dynar_foreach(incomplete_process_comms, cursor, comm) {
- mc_comm_pattern_t copy_comm = xbt_new0(s_mc_comm_pattern_t, 1);
- copy_comm->index = comm->index;
- copy_comm->type = comm->type;
- copy_comm->comm = comm->comm;
- copy_comm->rdv = strdup(comm->rdv);
- copy_comm->data_size = -1;
- copy_comm->data = NULL;
- if(comm->type == SIMIX_COMM_SEND){
- copy_comm->src_proc = comm->src_proc;
- copy_comm->src_host = comm->src_host;
- if (comm->data != NULL) {
- copy_comm->data_size = comm->data_size;
- copy_comm->data = xbt_malloc0(comm->data_size);
- memcpy(copy_comm->data, comm->data, comm->data_size);
- }
- }else{
- copy_comm->dst_proc = comm->dst_proc;
- copy_comm->dst_host = comm->dst_host;
- }
- xbt_dynar_push(incomplete_process_comms_copy, ©_comm);
- }
- xbt_dynar_insert_at(state->incomplete_comm_pattern, i, &incomplete_process_comms_copy);
- }
-}
-
-static void copy_index_communications_pattern(mc_state_t state) {
-
- state->index_comm = xbt_dynar_new(sizeof(unsigned int), NULL);
- mc_list_comm_pattern_t list_process_comm;
- unsigned int cursor;
- xbt_dynar_foreach(initial_communications_pattern, cursor, list_process_comm){
- xbt_dynar_push_as(state->index_comm, unsigned int, list_process_comm->index_comm);
- }
-}
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_state, mc,
+ "Logging specific to MC (state)");
/**
* \brief Creates a state data structure used by the exploration algorithm
*/
mc_state_t MC_state_new()
{
- mc_state_t state = NULL;
+ mc_state_t state = xbt_new0(s_mc_state_t, 1);
- state = xbt_new0(s_mc_state_t, 1);
- state->max_pid = simix_process_maxpid;
+ state->max_pid = MC_smx_get_maxpid();
state->proc_status = xbt_new0(s_mc_procstate_t, state->max_pid);
state->system_state = NULL;
state->num = ++mc_stats->expanded_states;
if((_sg_mc_checkpoint > 0 && (mc_stats->expanded_states % _sg_mc_checkpoint == 0)) || _sg_mc_termination){
state->system_state = MC_take_snapshot(state->num);
if(_sg_mc_comms_determinism || _sg_mc_send_determinism){
- copy_incomplete_communications_pattern(state);
- copy_index_communications_pattern(state);
+ MC_state_copy_incomplete_communications_pattern(state);
+ MC_state_copy_index_communications_pattern(state);
}
}
return state;
void MC_state_interleave_process(mc_state_t state, smx_process_t process)
{
+ assert(state);
state->proc_status[process->pid].state = MC_INTERLEAVE;
state->proc_status[process->pid].interleave_count = 0;
}
{
state->executed_req = *req;
state->req_num = value;
+
smx_process_t process = NULL;
- mc_procstate_t procstate = NULL;
/* The waitany and testany request are transformed into a wait or test request over the
* corresponding communication action so it can be treated later by the dependence
case SIMCALL_COMM_WAITANY:
state->internal_req.call = SIMCALL_COMM_WAIT;
state->internal_req.issuer = req->issuer;
- state->internal_comm =
- *xbt_dynar_get_as(simcall_comm_waitany__get__comms(req), value,
- smx_synchro_t);
+ MC_process_read_dynar_element(&mc_model_checker->process,
+ &state->internal_comm, simcall_comm_waitany__get__comms(req),
+ value, sizeof(state->internal_comm));
simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
simcall_comm_wait__set__timeout(&state->internal_req, 0);
break;
state->internal_req.issuer = req->issuer;
if (value > 0)
- state->internal_comm =
- *xbt_dynar_get_as(simcall_comm_testany__get__comms(req), value,
- smx_synchro_t);
+ MC_process_read_dynar_element(&mc_model_checker->process,
+ &state->internal_comm, simcall_comm_testany__get__comms(req),
+ value, sizeof(state->internal_comm));
simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
simcall_comm_test__set__result(&state->internal_req, value);
case SIMCALL_COMM_WAIT:
state->internal_req = *req;
- state->internal_comm = *(simcall_comm_wait__get__comm(req));
+ MC_process_read_simple(&mc_model_checker->process, &state->internal_comm ,
+ simcall_comm_wait__get__comm(req), sizeof(state->internal_comm));
simcall_comm_wait__set__comm(&state->executed_req, &state->internal_comm);
simcall_comm_wait__set__comm(&state->internal_req, &state->internal_comm);
break;
case SIMCALL_COMM_TEST:
state->internal_req = *req;
- state->internal_comm = *simcall_comm_test__get__comm(req);
+ MC_process_read_simple(&mc_model_checker->process, &state->internal_comm,
+ simcall_comm_test__get__comm(req), sizeof(state->internal_comm));
simcall_comm_test__set__comm(&state->executed_req, &state->internal_comm);
simcall_comm_test__set__comm(&state->internal_req, &state->internal_comm);
break;
case SIMCALL_MC_RANDOM:
state->internal_req = *req;
- if (value != simcall_mc_random__get__max(req)) {
- xbt_swag_foreach(process, simix_global->process_list) {
- procstate = &state->proc_status[process->pid];
- if (process->pid == req->issuer->pid) {
+ int random_max = simcall_mc_random__get__max(req);
+ if (value != random_max) {
+ MC_EACH_SIMIX_PROCESS(process,
+ mc_procstate_t procstate = &state->proc_status[process->pid];
+ const smx_process_t issuer = MC_smx_simcall_get_issuer(req);
+ if (process->pid == issuer->pid) {
procstate->state = MC_MORE_INTERLEAVE;
break;
}
- }
+ );
}
break;
return &state->internal_req;
}
-smx_simcall_t MC_state_get_request(mc_state_t state, int *value)
+static inline smx_simcall_t MC_state_get_request_for_process(
+ mc_state_t state, int*value, smx_process_t process)
{
- smx_process_t process = NULL;
- mc_procstate_t procstate = NULL;
- unsigned int start_count;
- smx_synchro_t act = NULL;
-
- xbt_swag_foreach(process, simix_global->process_list) {
- procstate = &state->proc_status[process->pid];
-
- if (procstate->state == MC_INTERLEAVE
- || procstate->state == MC_MORE_INTERLEAVE) {
- if (MC_process_is_enabled(process)) {
- switch (process->simcall.call) {
- case SIMCALL_COMM_WAITANY:
- *value = -1;
- while (procstate->interleave_count <
- xbt_dynar_length(simcall_comm_waitany__get__comms
- (&process->simcall))) {
- if (MC_request_is_enabled_by_idx
- (&process->simcall, procstate->interleave_count++)) {
- *value = procstate->interleave_count - 1;
- break;
- }
+ mc_procstate_t procstate = &state->proc_status[process->pid];
+
+ if (procstate->state != MC_INTERLEAVE
+ && procstate->state != MC_MORE_INTERLEAVE)
+ return NULL;
+ if (!MC_process_is_enabled(process))
+ return NULL;
+
+ switch (process->simcall.call) {
+
+ case SIMCALL_COMM_WAITANY:
+ *value = -1;
+ while (procstate->interleave_count <
+ MC_process_read_dynar_length(&mc_model_checker->process,
+ simcall_comm_waitany__get__comms(&process->simcall))) {
+ if (MC_request_is_enabled_by_idx
+ (&process->simcall, procstate->interleave_count++)) {
+ *value = procstate->interleave_count - 1;
+ break;
}
+ }
- if (procstate->interleave_count >=
- xbt_dynar_length(simcall_comm_waitany__get__comms
- (&process->simcall)))
- procstate->state = MC_DONE;
-
- if (*value != -1)
- return &process->simcall;
+ if (procstate->interleave_count >=
+ MC_process_read_dynar_length(&mc_model_checker->process,
+ simcall_comm_waitany__get__comms(&process->simcall)))
+ procstate->state = MC_DONE;
- break;
+ if (*value != -1)
+ return &process->simcall;
- case SIMCALL_COMM_TESTANY:
- start_count = procstate->interleave_count;
- *value = -1;
- while (procstate->interleave_count <
- xbt_dynar_length(simcall_comm_testany__get__comms
- (&process->simcall))) {
- if (MC_request_is_enabled_by_idx
- (&process->simcall, procstate->interleave_count++)) {
- *value = procstate->interleave_count - 1;
- break;
- }
+ break;
+
+ case SIMCALL_COMM_TESTANY: {
+ unsigned start_count = procstate->interleave_count;
+ *value = -1;
+ while (procstate->interleave_count <
+ MC_process_read_dynar_length(&mc_model_checker->process,
+ simcall_comm_testany__get__comms(&process->simcall))) {
+ if (MC_request_is_enabled_by_idx
+ (&process->simcall, procstate->interleave_count++)) {
+ *value = procstate->interleave_count - 1;
+ break;
}
+ }
- if (procstate->interleave_count >=
- xbt_dynar_length(simcall_comm_testany__get__comms
- (&process->simcall)))
- procstate->state = MC_DONE;
-
- if (*value != -1 || start_count == 0)
- return &process->simcall;
-
- break;
-
- case SIMCALL_COMM_WAIT:
- act = simcall_comm_wait__get__comm(&process->simcall);
- if (act->comm.src_proc && act->comm.dst_proc) {
- *value = 0;
- } else {
- if (act->comm.src_proc == NULL && act->comm.type == SIMIX_COMM_READY
- && act->comm.detached == 1)
- *value = 0;
- else
- *value = -1;
- }
+ if (procstate->interleave_count >=
+ MC_process_read_dynar_length(&mc_model_checker->process,
+ simcall_comm_testany__get__comms(&process->simcall)))
procstate->state = MC_DONE;
- return &process->simcall;
-
- break;
- case SIMCALL_MC_RANDOM:
- if (procstate->state == MC_INTERLEAVE)
- *value = 0;
- else {
- if (state->req_num < simcall_mc_random__get__max(&process->simcall))
- *value = state->req_num + 1;
- }
- procstate->state = MC_DONE;
+ if (*value != -1 || start_count == 0)
return &process->simcall;
- break;
- default:
- procstate->state = MC_DONE;
+ break;
+ }
+
+ case SIMCALL_COMM_WAIT: {
+ smx_synchro_t remote_act = simcall_comm_wait__get__comm(&process->simcall);
+ s_smx_synchro_t act;
+ MC_process_read_simple(&mc_model_checker->process,
+ &act, remote_act, sizeof(act));
+ if (act.comm.src_proc && act.comm.dst_proc) {
*value = 0;
- return &process->simcall;
- break;
+ } else {
+ if (act.comm.src_proc == NULL && act.comm.type == SIMIX_COMM_READY
+ && act.comm.detached == 1)
+ *value = 0;
+ else
+ *value = -1;
}
+ procstate->state = MC_DONE;
+ return &process->simcall;
}
- }
+
+ case SIMCALL_MC_RANDOM:
+ if (procstate->state == MC_INTERLEAVE)
+ *value = simcall_mc_random__get__min(&process->simcall);
+ else {
+ if (state->req_num < simcall_mc_random__get__max(&process->simcall))
+ *value = state->req_num + 1;
+ }
+ procstate->state = MC_DONE;
+ return &process->simcall;
+
+ default:
+ procstate->state = MC_DONE;
+ *value = 0;
+ return &process->simcall;
}
+ return NULL;
+}
+
+smx_simcall_t MC_state_get_request(mc_state_t state, int *value)
+{
+ smx_process_t process = NULL;
+ MC_EACH_SIMIX_PROCESS(process,
+ smx_simcall_t res = MC_state_get_request_for_process(state, value, process);
+ if (res)
+ return res;
+ );
return NULL;
}
mc_snapshot_t system_state; /* Snapshot of system state */
int num;
int in_visited_states;
- xbt_dynar_t incomplete_comm_pattern; // comm determinism verification
+ // comm determinism verification (xbt_dynar_t<xbt_dynar_t<mc_comm_pattern_t>):
+ xbt_dynar_t incomplete_comm_pattern;
xbt_dynar_t index_comm; // comm determinism verification
} s_mc_state_t, *mc_state_t;
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+/** \file
+ * Libunwind support for mc_address_space objects.
+ */
+
+// We need this for the register indices:
+#define _GNU_SOURCE
+
+#include <string.h>
+
+// On x86_64, libunwind unw_context_t has the same layout as ucontext_t:
+#include <sys/ucontext.h>
+
+#include <libunwind.h>
+
+#include "mc_object_info.h"
+#include "mc_process.h"
+#include "mc_unw.h"
+
+// ***** Implementation
+
+/** Get frame unwind information (libunwind method)
+ *
+ * Delegates to the local/ptrace implementation.
+ */
+static int find_proc_info(unw_addr_space_t as,
+ unw_word_t ip, unw_proc_info_t *pip,
+ int need_unwind_info, void* arg)
+{
+ mc_unw_context_t context = (mc_unw_context_t) arg;
+ return unw_get_accessors(context->process->unw_underlying_addr_space)->find_proc_info(
+ context->process->unw_underlying_addr_space, ip, pip,
+ need_unwind_info, context->process->unw_underlying_context
+ );
+}
+
+/** Release frame unwind information (libunwind method)
+ *
+ * Delegates to the local/ptrace implementation.
+ */
+static void put_unwind_info(unw_addr_space_t as,
+ unw_proc_info_t *pip, void* arg)
+{
+ mc_unw_context_t context = (mc_unw_context_t) arg;
+ return unw_get_accessors(context->process->unw_underlying_addr_space)->put_unwind_info(
+ context->process->unw_underlying_addr_space, pip,
+ context->process->unw_underlying_context
+ );
+}
+
+/** (libunwind method)
+ *
+ * Not implemented.
+ */
+static int get_dyn_info_list_addr(unw_addr_space_t as,
+ unw_word_t *dilap, void* arg)
+{
+ mc_unw_context_t context = (mc_unw_context_t) arg;
+ return unw_get_accessors(context->process->unw_underlying_addr_space)->get_dyn_info_list_addr(
+ context->process->unw_underlying_addr_space,
+ dilap,
+ context->process->unw_underlying_context
+ );
+}
+
+/** Read from the target address space memory (libunwind method)
+ *
+ * Delegates to the `mc_process_t`.
+ */
+static int access_mem(unw_addr_space_t as,
+ unw_word_t addr, unw_word_t *valp,
+ int write, void* arg)
+{
+ mc_unw_context_t context = (mc_unw_context_t) arg;
+ if (write)
+ return -UNW_EREADONLYREG;
+ MC_address_space_read(context->address_space,
+ 0, valp, (void*) addr, sizeof(unw_word_t), MC_PROCESS_INDEX_ANY);
+ // We don't handle failure gracefully.
+ return 0;
+}
+
+static void* get_reg(unw_context_t* context, unw_regnum_t regnum)
+{
+#ifdef __x86_64
+ mcontext_t* mcontext = &context->uc_mcontext;
+ switch (regnum) {
+ case UNW_X86_64_RAX: return &mcontext->gregs[REG_RAX];
+ case UNW_X86_64_RDX: return &mcontext->gregs[REG_RDX];
+ case UNW_X86_64_RCX: return &mcontext->gregs[REG_RCX];
+ case UNW_X86_64_RBX: return &mcontext->gregs[REG_RBX];
+ case UNW_X86_64_RSI: return &mcontext->gregs[REG_RSI];
+ case UNW_X86_64_RDI: return &mcontext->gregs[REG_RDI];
+ case UNW_X86_64_RBP: return &mcontext->gregs[REG_RBP];
+ case UNW_X86_64_RSP: return &mcontext->gregs[REG_RSP];
+ case UNW_X86_64_R8: return &mcontext->gregs[REG_R8];
+ case UNW_X86_64_R9: return &mcontext->gregs[REG_R9];
+ case UNW_X86_64_R10: return &mcontext->gregs[REG_R10];
+ case UNW_X86_64_R11: return &mcontext->gregs[REG_R11];
+ case UNW_X86_64_R12: return &mcontext->gregs[REG_R12];
+ case UNW_X86_64_R13: return &mcontext->gregs[REG_R13];
+ case UNW_X86_64_R14: return &mcontext->gregs[REG_R14];
+ case UNW_X86_64_R15: return &mcontext->gregs[REG_R15];
+ case UNW_X86_64_RIP: return &mcontext->gregs[REG_RIP];
+ default: return NULL;
+ }
+#else
+ return NULL;
+#endif
+}
+
+/** Read a standard register (libunwind method)
+ */
+static int access_reg(unw_addr_space_t as,
+ unw_regnum_t regnum, unw_word_t *valp,
+ int write, void* arg)
+{
+ mc_unw_context_t as_context = (mc_unw_context_t) arg;
+ unw_context_t* context = &as_context->context;
+ if (write)
+ return -UNW_EREADONLYREG;
+ greg_t* preg = get_reg(context, regnum);
+ if (!preg)
+ return -UNW_EBADREG;
+ *valp = *preg;
+ return 0;
+}
+
+/** Read a floating-point register (libunwind method)
+ *
+ * FP registers are caller-saved. The values saved by functions such as
+ * `getcontext()` is not relevant for the caller. It is not really necessary
+ * to save and handle them.
+ */
+static int access_fpreg(unw_addr_space_t as,
+ unw_regnum_t regnum, unw_fpreg_t *fpvalp,
+ int write, void* arg)
+{
+ return -UNW_EBADREG;
+}
+
+/** Resume the execution of the context (libunwind method)
+ *
+ * We don't use this.
+ */
+static int resume(unw_addr_space_t as,
+ unw_cursor_t *cp, void* arg)
+{
+ return -UNW_EUNSPEC;
+}
+
+/** Find informations about a function (libunwind method)
+ */
+static int get_proc_name(unw_addr_space_t as,
+ unw_word_t addr, char *bufp,
+ size_t buf_len, unw_word_t *offp,
+ void* arg)
+{
+ mc_unw_context_t context = (mc_unw_context_t) arg;
+ dw_frame_t frame = MC_process_find_function(context->process, (void*) addr);
+ if (!frame)
+ return - UNW_ENOINFO;
+ *offp = (unw_word_t) frame->low_pc - addr;
+
+ strncpy(bufp, frame->name, buf_len);
+ if (bufp[buf_len - 1]) {
+ bufp[buf_len - 1] = 0;
+ return -UNW_ENOMEM;
+ }
+
+ return 0;
+}
+
+// ***** Init
+
+unw_accessors_t mc_unw_accessors =
+ {
+ .find_proc_info = &find_proc_info,
+ .put_unwind_info = &put_unwind_info,
+ .get_dyn_info_list_addr = &get_dyn_info_list_addr,
+ .access_mem = &access_mem,
+ .access_reg = &access_reg,
+ .access_fpreg = &access_fpreg,
+ .resume = &resume,
+ .get_proc_name = &get_proc_name
+ };
+
+// ***** Context management
+
+int mc_unw_init_context(
+ mc_unw_context_t context, mc_process_t process, unw_context_t* c)
+{
+ context->address_space = (mc_address_space_t) process;
+ context->process = process;
+
+ // Take a copy of the context for our own purpose:
+ context->context = *c;
+#if defined(PROCESSOR_x86_64) || defined(PROCESSOR_i686)
+ // On x86_64, ucontext_t contains a pointer to itself for FP registers.
+ // We don't really need support for FR registers as they are caller saved
+ // and probably never use those fields as libunwind-x86_64 does not read
+ // FP registers from the unw_context_t
+ // but we fix the pointer in order to avoid dangling pointers:
+ context->context.uc_mcontext.fpregs = &(context->context.__fpregs_mem);
+#else
+ // Do we need to do any fixup like this?
+ #error Target CPU type is not handled.
+#endif
+
+ return 0;
+}
+
+int mc_unw_destroy_context(mc_unw_context_t context)
+{
+ context->address_space = NULL;
+ context->process = NULL;
+ return 0;
+}
+
+// ***** Cursor management
+
+int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context)
+{
+ if (!context->process || !context->address_space)
+ return -UNW_EUNSPEC;
+ mc_address_space_t as = context->address_space;
+
+ // Use local unwinding for current process:
+ if (MC_is_process(as) && MC_process_is_self((mc_process_t) as))
+ return unw_init_local(cursor, &context->context);
+
+ return unw_init_remote(cursor, context->process->unw_addr_space, context);
+}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+
+/ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#ifndef MC_UNW_H
+#define MC_UNW_H
+
+/** \file
+ * Libunwind implementation for the model-checker
+ *
+ * Libunwind provides an pluggable stack unwinding API: the way the current
+ * registers and memory is accessed, the way unwinding informations is found
+ * is pluggable.
+ *
+ * This component implements the libunwind API for he model-checker:
+ *
+ * * reading memory from a mc_address_space_t;
+ *
+ * * reading stack registers from a saved snapshot (context).
+ *
+ * Parts of the libunwind information fetching is currently handled by the
+ * standard `libunwind` implementations (either the local one or the ptrace one)
+ * because parsing `.eh_frame` section is not fun and `libdw` does not help
+ * much here.
+ */
+
+#include "mc_process.h"
+
+SG_BEGIN_DECL()
+
+// ***** Libunwind namespace
+
+/** Virtual table for our `libunwind-process_vm_readv` implementation.
+ *
+ * This implementation reuse most the code of `libunwind-ptrace` but
+ * does not use ptrace() to read the target process memory by
+ * `process_vm_readv()` or `/dev/${pid}/mem` if possible.
+ *
+ * Does not support any MC-specific behaviour (privatisation, snapshots)
+ * and `ucontext_t`.
+ *
+ * It works with `void*` contexts allocated with `_UPT_create(pid)`.
+ */
+extern unw_accessors_t mc_unw_vmread_accessors;
+
+/** Virtual table for our `libunwind` implementation
+ *
+ * Stack unwinding on a `mc_process_t` (for memory, unwinding information)
+ * and `ucontext_t` (for processor registers).
+ *
+ * It works with the `s_mc_unw_context_t` context.
+ */
+extern unw_accessors_t mc_unw_accessors;
+
+// ***** Libunwind context
+
+/** A `libunwind` context
+ */
+typedef struct s_mc_unw_context {
+ mc_address_space_t address_space;
+ mc_process_t process;
+ unw_context_t context;
+} s_mc_unw_context_t, *mc_unw_context_t;
+
+/** Initialises an already allocated context */
+int mc_unw_init_context(
+ mc_unw_context_t context, mc_process_t process, unw_context_t* c);
+
+/** Destroys (but not not `free`) a context */
+int mc_unw_destroy_context(mc_unw_context_t context);
+
+// ***** Libunwind cursor
+
+/** Initialises a `libunwind` cursor */
+int mc_unw_init_cursor(unw_cursor_t *cursor, mc_unw_context_t context);
+
+SG_END_DECL()
+
+#endif
--- /dev/null
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <libunwind.h>
+#include <libunwind-ptrace.h>
+
+#include "mc_unw.h"
+
+/** \file
+ * Libunwind namespace implementation using process_vm_readv.
+ *.
+ * This implem
+ */
+
+/** Partial structure of libunwind-ptrace context in order to get the PID
+ *
+ * The context type for libunwind-race is an opaque type. We need to get the
+ * PID which is the first field. This is a hack which might break if the
+ * libunwind-ptrace structure changes.
+ */
+struct _UPT_info {
+ pid_t pid;
+ // Other things;
+};
+
+/** Get the PID of a `libunwind-ptrace` context
+ */
+static inline
+pid_t _UPT_getpid(void* arg)
+{
+ struct _UPT_info* info = arg;
+ return info->pid;
+}
+
+/** Read from the memory, avoid using `ptrace` (libunwind method)
+ */
+static int access_mem(const unw_addr_space_t as,
+ const unw_word_t addr, unw_word_t* const valp,
+ const int write, void* const arg)
+{
+ if (write)
+ return - UNW_EINVAL;
+ ssize_t s;
+ pid_t pid = _UPT_getpid(arg);
+ size_t size = sizeof(unw_word_t);
+
+#ifdef HAVE_PROCESS_VM_READV
+ // process_vm_read implementation.
+ // This is only available since Linux 3.2.
+
+ struct iovec local = { valp, size };
+ struct iovec remote = { (void*) addr, size };
+ s = process_vm_readv(pid, &local, 1, &remote, 1, 0);
+ if (s >= 0) {
+ if (s != size)
+ return - UNW_EINVAL;
+ else
+ return 0;
+ }
+ if (s < 0 && errno != ENOSYS)
+ return - UNW_EINVAL;
+#endif
+
+ // /proc/${pid}/mem implementation.
+ // On recent kernels, we do not need to ptrace the target process.
+ // On older kernels, it is necessary to ptrace the target process.
+ size_t count = size;
+ off_t off = (off_t) addr;
+ char* buf = (char*) valp;
+ int fd = MC_process_vm_open(pid, O_RDONLY);
+ if (fd < 0)
+ return - UNW_EINVAL;
+ while (1) {
+ ssize_t s = pread(fd, buf, count, off);
+ if (s == 0) {
+ close(fd);
+ return - UNW_EINVAL;
+ }
+ if (s == -1)
+ break;
+ count -= s;
+ buf += s;
+ off += s;
+ if (count == 0) {
+ close(fd);
+ return 0;
+ }
+ }
+ close(fd);
+
+ // ptrace implementation.
+ // We need to have PTRACE_ATTACH-ed it before.
+ return _UPT_access_mem(as, addr, valp, write, arg);
+}
+
+unw_accessors_t mc_unw_vmread_accessors =
+ {
+ .find_proc_info = &_UPT_find_proc_info,
+ .put_unwind_info = &_UPT_put_unwind_info,
+ .get_dyn_info_list_addr = &_UPT_get_dyn_info_list_addr,
+ .access_mem = &access_mem,
+ .access_reg = &_UPT_access_reg,
+ .access_fpreg = &_UPT_access_fpreg,
+ .resume = &_UPT_resume,
+ .get_proc_name = &_UPT_get_proc_name
+ };
#include "mc_safety.h"
#include "mc_liveness.h"
#include "mc_private.h"
+#include "mc_process.h"
+#include "mc_smx.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_visited, mc,
"Logging specific to state equaity detection mechanisms");
*/
static mc_visited_state_t visited_state_new()
{
- mc_visited_state_t new_state = NULL;
- new_state = xbt_new0(s_mc_visited_state_t, 1);
- new_state->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
- new_state->nb_processes = xbt_swag_size(simix_global->process_list);
+ mc_process_t process = &(mc_model_checker->process);
+ mc_visited_state_t new_state = xbt_new0(s_mc_visited_state_t, 1);
+ new_state->heap_bytes_used = mmalloc_get_bytes_used_remote(
+ MC_process_get_heap(process)->heaplimit,
+ MC_process_get_malloc_info(process));
+
+ if (MC_process_is_self(&mc_model_checker->process)) {
+ new_state->nb_processes = xbt_swag_size(simix_global->process_list);
+ } else {
+ MC_process_smx_refresh(&mc_model_checker->process);
+ new_state->nb_processes = xbt_dynar_length(
+ mc_model_checker->process.smx_process_infos);
+ }
+
new_state->system_state = MC_take_snapshot(mc_stats->expanded_states);
new_state->num = mc_stats->expanded_states;
new_state->other_num = -1;
mc_visited_pair_t MC_visited_pair_new(int pair_num, xbt_automaton_state_t automaton_state, xbt_dynar_t atomic_propositions, mc_state_t graph_state)
{
+ mc_process_t process = &(mc_model_checker->process);
mc_visited_pair_t pair = NULL;
pair = xbt_new0(s_mc_visited_pair_t, 1);
pair->graph_state = graph_state;
if(pair->graph_state->system_state == NULL)
pair->graph_state->system_state = MC_take_snapshot(pair_num);
- pair->heap_bytes_used = mmalloc_get_bytes_used(std_heap);
- pair->nb_processes = xbt_swag_size(simix_global->process_list);
+ pair->heap_bytes_used = mmalloc_get_bytes_used_remote(
+ MC_process_get_heap(process)->heaplimit,
+ MC_process_get_malloc_info(process));
+ if (MC_process_is_self(&mc_model_checker->process)) {
+ pair->nb_processes = xbt_swag_size(simix_global->process_list);
+ } else {
+ MC_process_smx_refresh(&mc_model_checker->process);
+ pair->nb_processes = xbt_dynar_length(
+ mc_model_checker->process.smx_process_infos);
+ }
pair->automaton_state = automaton_state;
pair->num = pair_num;
pair->other_num = -1;
int get_search_interval(xbt_dynar_t list, void *ref, int *min, int *max)
{
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
int cursor = 0, previous_cursor, next_cursor;
int nb_processes, heap_bytes_used, nb_processes_test, heap_bytes_used_test;
*max = next_cursor;
next_cursor++;
}
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
return -1;
}
}
}
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return cursor;
}
are incomplete and they cannot be analyzed and compared with the initial pattern. */
if (_sg_mc_comms_determinism || _sg_mc_send_determinism) {
int current_process = 1;
- while (current_process < simix_process_maxpid) {
+ while (current_process < MC_smx_get_maxpid()) {
if (!xbt_dynar_is_empty((xbt_dynar_t)xbt_dynar_get_as(incomplete_communications_pattern, current_process, xbt_dynar_t))){
XBT_DEBUG("Some communications are not finished, cannot stop the exploration ! State not visited.");
partial_comm = 1;
}
}
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
mc_visited_state_t new_state = visited_state_new();
graph_state->system_state = new_state->system_state;
if (xbt_dynar_is_empty(visited_states)) {
xbt_dynar_push(visited_states, &new_state);
-
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return NULL;
} else {
return new_state->other_num;
} */
- if(!partial_comm && initial_global_state->initial_communications_pattern_done){
+ if (_sg_mc_safety || (!partial_comm
+ && initial_global_state->initial_communications_pattern_done)) {
cursor = min;
while (cursor <= max) {
xbt_dynar_insert_at(visited_states, cursor, &new_state);
XBT_DEBUG("Replace visited state %d with the new visited state %d", state_test->num, new_state->num);
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
return state_test;
}
cursor++;
XBT_DEBUG("Remove visited state (maximum number of stored states reached)");
}
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return NULL;
-
}
}
if (_sg_mc_visited == 0)
return -1;
- int mc_mem_set = (mmalloc_get_current_heap() == mc_heap);
-
- MC_SET_MC_HEAP;
+ xbt_mheap_t heap = mmalloc_set_current_heap(mc_heap);
mc_visited_pair_t new_visited_pair = NULL;
} else {
MC_visited_pair_delete(pair_test);
}
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
+ mmalloc_set_current_heap(heap);
return new_visited_pair->other_num;
}
}
}
- if (!mc_mem_set)
- MC_SET_STD_HEAP;
-
+ mmalloc_set_current_heap(heap);
return -1;
}
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <stdlib.h>
+
+#include <sys/types.h>
+
#include "mc_memory_map.h"
#include "mc_private.h"
-#include <stdlib.h>
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_memory_map, mc,
"Logging specific to algorithms for memory_map");
-memory_map_t MC_get_memory_map(void)
+memory_map_t MC_get_memory_map(pid_t pid)
{
- FILE *fp; /* File pointer to process's proc maps file */
- char *line = NULL; /* Temporal storage for each line that is readed */
- ssize_t read; /* Number of bytes readed */
- size_t n = 0; /* Amount of bytes to read by xbt_getline */
- memory_map_t ret = NULL; /* The memory map to return */
-
-/* The following variables are used during the parsing of the file "maps" */
- s_map_region_t memreg; /* temporal map region used for creating the map */
- char *lfields[6], *tok, *endptr;
- int i;
-
-/* Open the actual process's proc maps file and create the memory_map_t */
-/* to be returned. */
- fp = fopen("/proc/self/maps", "r");
-
+ /* Open the actual process's proc maps file and create the memory_map_t */
+ /* to be returned. */
+ char* path = bprintf("/proc/%i/maps", (int) pid);
+ FILE *fp = fopen(path, "r");
+ free(path);
if(fp == NULL)
perror("fopen failed");
-
xbt_assert(fp,
- "Cannot open /proc/self/maps to investigate the memory map of the process. Please report this bug.");
-
+ "Cannot open %s to investigate the memory map of the process.", path);
setbuf(fp, NULL);
- ret = xbt_new0(s_memory_map_t, 1);
+ memory_map_t ret = xbt_new0(s_memory_map_t, 1);
/* Read one line at the time, parse it and add it to the memory map to be returned */
+ ssize_t read; /* Number of bytes readed */
+ char* line = NULL;
+ size_t n = 0; /* Amount of bytes to read by xbt_getline */
while ((read = xbt_getline(&line, &n, fp)) != -1) {
//fprintf(stderr,"%s", line);
/* Tokenize the line using spaces as delimiters and store each token */
/* in lfields array. We expect 5 tokens/fields */
+ char* lfields[6];
lfields[0] = strtok(line, " ");
+ int i;
for (i = 1; i < 6 && lfields[i - 1] != NULL; i++) {
lfields[i] = strtok(NULL, " ");
}
/* Ok we are good enough to try to get the info we need */
/* First get the start and the end address of the map */
- tok = strtok(lfields[0], "-");
+ char *tok = strtok(lfields[0], "-");
if (tok == NULL)
xbt_abort();
+ s_map_region_t memreg; /* temporal map region used for creating the map */
+ char *endptr;
memreg.start_addr = (void *) strtoul(tok, &endptr, 16);
/* Make sure that the entire string was an hex number */
if (*endptr != '\0')
/* Create space for a new map region in the region's array and copy the */
/* parsed stuff from the temporal memreg variable */
+ XBT_DEBUG("Found region for %s",
+ memreg.pathname ? memreg.pathname : "(null)");
ret->regions =
xbt_realloc(ret->regions, sizeof(memreg) * (ret->mapsize + 1));
memcpy(ret->regions + ret->mapsize, &memreg, sizeof(memreg));
}
free(line);
-
fclose(fp);
-
return ret;
}
--- /dev/null
+/* Copyright (c) 2015. The SimGrid Team.
+ * All rights reserved. */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include <exception>
+
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+
+#include <signal.h>
+#include <poll.h>
+
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+
+#include <xbt/log.h>
+
+#include "simgrid/sg_config.h"
+#include "xbt_modinter.h"
+
+#include "mc_base.h"
+#include "mc_private.h"
+#include "mc_protocol.h"
+#include "mc_server.h"
+#include "mc_model_checker.h"
+#include "mc_safety.h"
+
+XBT_LOG_NEW_DEFAULT_SUBCATEGORY(mc_main, mc, "Entry point for simgrid-mc");
+
+static const bool trace = true;
+
+static int do_child(int socket, char** argv)
+{
+ XBT_DEBUG("Inside the child process PID=%i", (int) getpid());
+ if (prctl(PR_SET_PDEATHSIG, SIGHUP) != 0) {
+ std::perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+ }
+ int res;
+
+ // Remove CLOEXEC in order to pass the socket to the exec-ed program:
+ int fdflags = fcntl(socket, F_GETFD, 0);
+ if (fdflags == -1) {
+ std::perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+ }
+ if (fcntl(socket, F_SETFD, fdflags & ~FD_CLOEXEC) == -1) {
+ std::perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+ }
+
+ XBT_DEBUG("CLOEXEC removed on socket %i", socket);
+
+ // Set environment:
+ setenv(MC_ENV_VARIABLE, "1", 1);
+
+ char buffer[64];
+ res = std::snprintf(buffer, sizeof(buffer), "%i", socket);
+ if ((size_t) res >= sizeof(buffer) || res == -1)
+ return MC_SERVER_ERROR;
+ setenv(MC_ENV_SOCKET_FD, buffer, 1);
+
+ execvp(argv[1], argv+1);
+ std::perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+}
+
+static int do_parent(int socket, pid_t child)
+{
+ XBT_DEBUG("Inside the parent process");
+ if (mc_server)
+ xbt_die("MC server already present");
+ try {
+ mc_mode = MC_MODE_SERVER;
+ mc_server = new s_mc_server(child, socket);
+ mc_server->start();
+ MC_init_pid(child, socket);
+ MC_do_the_modelcheck_for_real();
+ mc_server->shutdown();
+ mc_server->exit();
+ }
+ catch(std::exception& e) {
+ XBT_ERROR(e.what());
+ }
+ exit(MC_SERVER_ERROR);
+}
+
+static char** argvdup(int argc, char** argv)
+{
+ char** argv_copy = xbt_new(char*, argc+1);
+ std::memcpy(argv_copy, argv, sizeof(char*) * argc);
+ argv_copy[argc] = NULL;
+ return argv_copy;
+}
+
+int main(int argc, char** argv)
+{
+ // We need to keep the original parameters in order to pass them to the
+ // model-checked process:
+ int argc_copy = argc;
+ char** argv_copy = argvdup(argc, argv);
+ xbt_log_init(&argc_copy, argv_copy);
+ sg_config_init(&argc_copy, argv_copy);
+
+ if (argc < 2)
+ xbt_die("Missing arguments.\n");
+
+ bool server_mode = true;
+ char* env = std::getenv("SIMGRID_MC_MODE");
+ if (env) {
+ if (std::strcmp(env, "server") == 0)
+ server_mode = true;
+ else if (std::strcmp(env, "standalone") == 0)
+ server_mode = false;
+ else
+ xbt_die("Unrecognised value for SIMGRID_MC_MODE (server/standalone)");
+ }
+
+ if (!server_mode) {
+ setenv(MC_ENV_VARIABLE, "1", 1);
+ execvp(argv[1], argv+1);
+
+ std::perror("simgrid-mc");
+ return 127;
+ }
+
+ // Create a AF_LOCAL socketpair:
+ int res;
+
+ int sockets[2];
+ res = socketpair(AF_LOCAL, SOCK_DGRAM | SOCK_CLOEXEC, 0, sockets);
+ if (res == -1) {
+ perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+ }
+
+ XBT_DEBUG("Created socketpair");
+
+ pid_t pid = fork();
+ if (pid < 0) {
+ perror("simgrid-mc");
+ return MC_SERVER_ERROR;
+ } else if (pid == 0) {
+ close(sockets[1]);
+ return do_child(sockets[0], argv);
+ } else {
+ close(sockets[0]);
+ return do_parent(sockets[1], pid);
+ }
+
+ return 0;
+}
MSG_mailbox_put_with_timeout(msg_mailbox_t mailbox, msg_task_t task,
double timeout)
{
- xbt_ex_t e;
msg_error_t ret = MSG_OK;
simdata_task_t t_simdata = NULL;
msg_process_t process = MSG_process_self();
p_simdata->waiting_task = task;
+ xbt_ex_t e;
/* Try to send it by calling SIMIX network layer */
TRY {
smx_synchro_t comm = NULL; /* MC needs the comm to be set to NULL during the simix call */
xbt_cfgelm_boolean, 1, 1, _mc_cfg_cb_hash, NULL);
xbt_cfg_setdefault_boolean(_sg_cfg_set, "model-check/hash", "no");
+ /* Set max depth exploration */
+ xbt_cfg_register(&_sg_cfg_set, "model-check/snapshot_fds",
+ "Whether file descriptors must be snapshoted",
+ xbt_cfgelm_boolean, 1, 1, _mc_cfg_cb_snapshot_fds, NULL);
+ xbt_cfg_setdefault_boolean(_sg_cfg_set, "model-check/snapshot_fds", "no");
+
/* Set max depth exploration */
xbt_cfg_register(&_sg_cfg_set, "model-check/max_depth",
"Specify the max depth of exploration (default : 1000)",
#include "smx_private.h"
#ifdef HAVE_MC
+#include "mc/mc_process.h"
+#include "mc/mc_model_checker.h"
#endif
XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_popping);
*/
void SIMIX_simcall_handle(smx_simcall_t simcall, int value) {
XBT_DEBUG("Handling simcall %p: %s", simcall, SIMIX_simcall_name(simcall->call));
+ #ifdef HAVE_MC
+ if (mc_model_checker) {
+ mc_model_checker->process.cache_flags = 0;
+ }
+ #endif
SIMCALL_SET_MC_VALUE(simcall, value);
if (simcall->issuer->context->iwannadie && simcall->call != SIMCALL_PROCESS_CLEANUP)
return;
fd.write('#include "smx_private.h"\n');
fd.write('#ifdef HAVE_MC\n');
- # fd.write('#include "mc/mc_private.h"\n');
+ fd.write('#include "mc/mc_process.h"\n');
+ fd.write('#include "mc/mc_model_checker.h"\n');
fd.write('#endif\n');
fd.write('\n');
fd.write('XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_popping);\n\n');
fd.write(' */\n');
fd.write('void SIMIX_simcall_handle(smx_simcall_t simcall, int value) {\n');
fd.write(' XBT_DEBUG("Handling simcall %p: %s", simcall, SIMIX_simcall_name(simcall->call));\n');
+ fd.write(' #ifdef HAVE_MC\n');
+ fd.write(' if (mc_model_checker) {\n');
+ fd.write(' mc_model_checker->process.cache_flags = 0;\n');
+ fd.write(' }\n');
+ fd.write(' #endif\n');
fd.write(' SIMCALL_SET_MC_VALUE(simcall, value);\n');
fd.write(' if (simcall->issuer->context->iwannadie && simcall->call != SIMCALL_PROCESS_CLEANUP)\n');
fd.write(' return;\n');
/* This program is free software; you can redistribute it and/or modify it
* under the terms of the license (GNU LGPL) which comes with this package. */
+#include <stdlib.h>
+
#include "smx_private.h"
#include "xbt/heap.h"
#include "xbt/sysdep.h"
#ifdef HAVE_MC
#include "mc/mc_private.h"
+#include "mc/mc_model_checker.h"
+#include "mc/mc_protocol.h"
+#include "mc/mc_client.h"
#endif
#include "mc/mc_record.h"
if (sg_cfg_get_boolean("clean_atexit"))
atexit(SIMIX_clean);
+#ifdef HAVE_MC
+ // The communication initialisation is done ASAP.
+ // We need to commuicate initialisation of the different layers to the model-checker.
+ if (mc_mode == MC_MODE_NONE) {
+ if (getenv(MC_ENV_SOCKET_FD)) {
+ mc_mode = MC_MODE_CLIENT;
+ MC_client_init();
+ MC_client_hello();
+ MC_client_handle_messages();
+ } else {
+ mc_mode = MC_MODE_STANDALONE;
+ }
+ }
+#endif
+
if (_sg_cfg_exit_asap)
exit(0);
}
#include "xbt/log.h"
#include "xbt/dict.h"
#include "mc/mc.h"
+#include "mc/mc_client.h"
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_process, simix,
"Logging specific to SIMIX (process)");
extern double smpi_cpu_threshold;
extern double smpi_running_power;
extern int smpi_privatize_global_variables;
-extern char* start_data_exe; //start of the data+bss segment of the executable
-extern int size_data_exe; //size of the data+bss segment of the executable
+extern char* smpi_start_data_exe; //start of the data+bss segment of the executable
+extern int smpi_size_data_exe; //size of the data+bss segment of the executable
void smpi_switch_data_segment(int dest);
typedef struct s_smpi_privatisation_region {
void* address;
int file_descriptor;
-} *smpi_privatisation_region_t;
+} s_smpi_privatisation_region_t, *smpi_privatisation_region_t;
extern smpi_privatisation_region_t smpi_privatisation_regions;
-
extern int smpi_loaded_page;
int SIMIX_process_get_PID(smx_process_t self);
oldbuf = request->buf;
if (!smpi_process_get_replaying() && oldbuf && request->size!=0){
if((smpi_privatize_global_variables)
- && ((char*)request->buf >= start_data_exe)
- && ((char*)request->buf < start_data_exe + size_data_exe )){
+ && ((char*) request->buf >= smpi_start_data_exe)
+ && ((char*)request->buf < smpi_start_data_exe + smpi_size_data_exe )){
XBT_DEBUG("Privatization : We are sending from a zone inside global memory. Switch data segment ");
- smpi_switch_data_segment(request->src);
- }
+ smpi_switch_data_segment(request->src);
+ }
buf = xbt_malloc(request->size);
memcpy(buf,oldbuf,request->size);
XBT_DEBUG("buf %p copied into %p",oldbuf,buf);
if((req->flags & ACCUMULATE) || (datatype->has_subtype == 1)){
if (!smpi_process_get_replaying()){
if( smpi_privatize_global_variables
- && ((char*)req->old_buf >= start_data_exe)
- && ((char*)req->old_buf < start_data_exe + size_data_exe )
+ && ((char*)req->old_buf >= smpi_start_data_exe)
+ && ((char*)req->old_buf < smpi_start_data_exe + smpi_size_data_exe )
){
XBT_VERB("Privatization : We are unserializing to a zone in global memory - Switch data segment ");
smpi_switch_data_segment(smpi_process_index());
double smpi_running_power;
int smpi_loaded_page = -1;
-char* start_data_exe = NULL;
-int size_data_exe = 0;
+char* smpi_start_data_exe = NULL;
+int smpi_size_data_exe = 0;
int smpi_privatize_global_variables;
double smpi_total_benched_time = 0;
-
-
smpi_privatisation_region_t smpi_privatisation_regions;
typedef struct {
*/
void smpi_really_switch_data_segment(int dest) {
- if(size_data_exe == 0)//no need to switch
+ if(smpi_size_data_exe == 0)//no need to switch
return;
#ifdef HAVE_MMAP
int i;
if(smpi_loaded_page==-1){//initial switch, do the copy from the real page here
for (i=0; i< SIMIX_process_count(); i++){
- memcpy(smpi_privatisation_regions[i].address,TOPAGE(start_data_exe),size_data_exe);
+ memcpy(smpi_privatisation_regions[i].address,
+ TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
}
}
+ // FIXME, cross-process support (mmap across process when necessary)
int current = smpi_privatisation_regions[dest].file_descriptor;
XBT_DEBUG("Switching data frame to the one of process %d", dest);
- void* tmp = mmap (TOPAGE(start_data_exe), size_data_exe, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0);
- if (tmp != TOPAGE(start_data_exe))
+ void* tmp = mmap (TOPAGE(smpi_start_data_exe), smpi_size_data_exe,
+ PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, current, 0);
+ if (tmp != TOPAGE(smpi_start_data_exe))
xbt_die("Couldn't map the new region");
- smpi_loaded_page=dest;
+ smpi_loaded_page = dest;
#endif
}
if(i>=6){
if(strcmp(lfields[1], ".data") == 0){
size_data_binary = strtoul(lfields[2], NULL, 16);
- start_data_exe = (char*) strtoul(lfields[4], NULL, 16);
+ smpi_start_data_exe = (char*) strtoul(lfields[4], NULL, 16);
found++;
}else if(strcmp(lfields[1], ".bss") == 0){
//the beginning of bss is not exactly the end of data if not aligned, grow bss reported size accordingly
//TODO : check if this is OK, as some segments may be inserted between them..
- size_bss_binary = ((char*) strtoul(lfields[4], NULL, 16) - (start_data_exe + size_data_binary))
+ size_bss_binary = ((char*) strtoul(lfields[4], NULL, 16) - (smpi_start_data_exe + size_data_binary))
+ strtoul(lfields[2], NULL, 16);
found++;
}
}
- size_data_exe =(unsigned long)start_data_exe - (unsigned long)TOPAGE(start_data_exe)+ size_data_binary+size_bss_binary;
+ smpi_size_data_exe = (unsigned long) smpi_start_data_exe
+ - (unsigned long) TOPAGE(smpi_start_data_exe)
+ + size_data_binary+size_bss_binary;
xbt_free(command);
xbt_free(line);
pclose(fp);
unsigned int i = 0;
smpi_get_executable_global_size();
- XBT_DEBUG ("bss+data segment found : size %d starting at %p",size_data_exe, start_data_exe );
+ XBT_DEBUG ("bss+data segment found : size %d starting at %p",
+ smpi_size_data_exe, smpi_start_data_exe );
- if(size_data_exe == 0){//no need to switch
+ if (smpi_size_data_exe == 0){//no need to switch
smpi_privatize_global_variables=0;
return;
}
if (status)
xbt_die("Impossible to unlink temporary file for memory mapping");
- status = ftruncate(file_descriptor, size_data_exe);
+ status = ftruncate(file_descriptor, smpi_size_data_exe);
if(status)
xbt_die("Impossible to set the size of the temporary file for memory mapping");
/* Ask for a free region */
- address = mmap (NULL, size_data_exe, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0);
+ address = mmap (NULL, smpi_size_data_exe, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0);
if (address == MAP_FAILED)
xbt_die("Couldn't find a free region for memory mapping");
//initialize the values
- memcpy(address,TOPAGE(start_data_exe),size_data_exe);
+ memcpy(address, TOPAGE(smpi_start_data_exe), smpi_size_data_exe);
//store the address of the mapping for further switches
smpi_privatisation_regions[i].file_descriptor = file_descriptor;
}
void smpi_destroy_global_memory_segments(){
- if(size_data_exe == 0)//no need to switch
+ if (smpi_size_data_exe == 0)//no need to switch
return;
#ifdef HAVE_MMAP
int i;
for (i=0; i< smpi_process_count(); i++){
- if(munmap(smpi_privatisation_regions[i].address,size_data_exe) < 0) {
+ if(munmap(smpi_privatisation_regions[i].address, smpi_size_data_exe) < 0) {
XBT_WARN("Unmapping of fd %d failed: %s",
smpi_privatisation_regions[i].file_descriptor, strerror(errno));
}
void* tmpbuff=buff;
if((smpi_privatize_global_variables)
- && ((char*)buff >= start_data_exe)
- && ((char*)buff < start_data_exe + size_data_exe )
+ && ((char*)buff >= smpi_start_data_exe)
+ && ((char*)buff < smpi_start_data_exe + smpi_size_data_exe )
){
XBT_DEBUG("Privatization : We are copying from a zone inside global memory... Saving data to temp buffer !");
smpi_switch_data_segment(((smpi_process_data_t)SIMIX_process_get_data(comm->comm.src_proc))->index);
if((smpi_privatize_global_variables)
- && ((char*)comm->comm.dst_buff >= start_data_exe)
- && ((char*)comm->comm.dst_buff < start_data_exe + size_data_exe )
+ && ((char*)comm->comm.dst_buff >= smpi_start_data_exe)
+ && ((char*)comm->comm.dst_buff < smpi_start_data_exe + smpi_size_data_exe )
){
XBT_DEBUG("Privatization : We are copying to a zone inside global memory - Switch data segment");
smpi_switch_data_segment(((smpi_process_data_t)SIMIX_process_get_data(comm->comm.dst_proc))->index);
xbt_die("could not find dst node active comms !");
// act_dst->rate=rate;
- ((NetworkIBModel*)surf_network_model)->active_comms[action]=make_pair<IBNode*,IBNode*>(act_src, act_dst);
+ ((NetworkIBModel*)surf_network_model)->active_comms[action]=make_pair(act_src, act_dst);
//post the action in the second dist, to retrieve in the other callback
XBT_DEBUG("IB callback - action %p init", action);
m_lastUpdate = now;
m_lastValue = lmm_variable_getvalue(getVariable());
}
-
#include "xbt/automaton.h"
#include <stdio.h> /* printf */
+struct xbt_automaton_propositional_symbol{
+ char* pred;
+ /** Callback used to evaluate the value of the symbol */
+ int (*callback)(void*);
+ /** Additional data for the callback.
+ Alternatively it can be used as a pointer to the data. */
+ void* data;
+ //** Optional callback used to free the data field */
+ void (*free_function)(void*);
+};
+
xbt_automaton_t xbt_automaton_new(){
xbt_automaton_t automaton = NULL;
automaton = xbt_new0(struct xbt_automaton, 1);
return a->current_state;
}
-xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(xbt_automaton_t a, const char* id, void* fct){
+static int call_simple_function(void* function)
+{
+ return ((int (*)(void)) function)();
+}
+
+xbt_automaton_propositional_symbol_t xbt_automaton_propositional_symbol_new(xbt_automaton_t a, const char* id, int(*fct)(void)){
xbt_automaton_propositional_symbol_t prop_symb = NULL;
prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
prop_symb->pred = strdup(id);
- prop_symb->function = fct;
+ prop_symb->callback = call_simple_function;
+ prop_symb->data = fct;
+ prop_symb->free_function = NULL;
xbt_dynar_push(a->propositional_symbols, &prop_symb);
return prop_symb;
}
+XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new_pointer(xbt_automaton_t a, const char* id, int* value)
+{
+ xbt_automaton_propositional_symbol_t prop_symb = NULL;
+ prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
+ prop_symb->pred = strdup(id);
+ prop_symb->callback = NULL;
+ prop_symb->data = value;
+ prop_symb->free_function = NULL;
+ xbt_dynar_push(a->propositional_symbols, &prop_symb);
+ return prop_symb;
+}
+
+XBT_PUBLIC(xbt_automaton_propositional_symbol_t) xbt_automaton_propositional_symbol_new_callback(
+ xbt_automaton_t a, const char* id,
+ xbt_automaton_propositional_symbol_callback_type callback,
+ void* data, xbt_automaton_propositional_symbol_free_function_type free_function)
+{
+ xbt_automaton_propositional_symbol_t prop_symb = NULL;
+ prop_symb = xbt_new0(struct xbt_automaton_propositional_symbol, 1);
+ prop_symb->pred = strdup(id);
+ prop_symb->callback = callback;
+ prop_symb->data = data;
+ prop_symb->free_function = free_function;
+ xbt_dynar_push(a->propositional_symbols, &prop_symb);
+ return prop_symb;
+}
+
+XBT_PUBLIC(int) xbt_automaton_propositional_symbol_evaluate(xbt_automaton_propositional_symbol_t symbol)
+{
+ if (symbol->callback)
+ return (symbol->callback)(symbol->data);
+ else
+ return *(int*) symbol->data;
+}
+
+XBT_PUBLIC(xbt_automaton_propositional_symbol_callback_type) xbt_automaton_propositional_symbol_get_callback(xbt_automaton_propositional_symbol_t symbol)
+{
+ return symbol->callback;
+}
+
+XBT_PUBLIC(void*) xbt_automaton_propositional_symbol_get_data(xbt_automaton_propositional_symbol_t symbol)
+{
+ return symbol->data;
+}
+
+XBT_PUBLIC(const char*) xbt_automaton_propositional_symbol_get_name(xbt_automaton_propositional_symbol_t symbol)
+{
+ return symbol->pred;
+}
+
int xbt_automaton_state_compare(xbt_automaton_state_t s1, xbt_automaton_state_t s2){
/* single id for each state, id and type sufficient for comparison*/
}
void xbt_automaton_propositional_symbol_free_voidp(void *ps){
- xbt_automaton_propositional_symbol_free((xbt_automaton_propositional_symbol_t) * (void **) ps);
+ xbt_automaton_propositional_symbol_t symbol = (xbt_automaton_propositional_symbol_t) * (void **) ps;
+ if (symbol->free_function)
+ symbol->free_function(symbol->data);
+ xbt_free(symbol->pred);
+ xbt_automaton_propositional_symbol_free(symbol);
}
void xbt_automaton_free(xbt_automaton_t a){
xbt_test_log("Pop %d, length=%lu", cpt, xbt_dynar_length(d));
}
+ int* pi;
+ xbt_dynar_foreach_ptr(d, cursor, pi) {
+ *pi = 0;
+ }
+ xbt_dynar_foreach(d, cursor, i) {
+ xbt_test_assert(i == 0, "The value is not the same as the expected one.");
+ }
+ xbt_dynar_foreach_ptr(d, cursor, pi) {
+ *pi = 1;
+ }
+ xbt_dynar_foreach(d, cursor, i) {
+ xbt_test_assert(i == 1, "The value is not the same as the expected one.");
+ }
+
/* 5. Free the resources */
xbt_dynar_free(&d); /* This code is used both as example and as regression test, so we try to */
xbt_dynar_free(&d); /* free the struct twice here to check that it's ok, but freeing it only once */
* under the terms of the license (GNU LGPL) which comes with this package. */
/* Redefine the classical malloc/free/realloc functions so that they fit well in the mmalloc framework */
+#define _GNU_SOURCE
+#include <stdlib.h>
+
+#include <dlfcn.h>
+
+#include "../../mc/mc_base.h"
#include "mmprivate.h"
#include "xbt_modinter.h"
#include "internal_config.h"
#include <math.h>
+#include "../mc/mc_protocol.h"
//#define MM_LEGACY_VERBOSE 1 /* define this to see which version of malloc gets used */
backwards compatibility with the non-mmap'd version. */
xbt_mheap_t __mmalloc_default_mdp = NULL;
+static int __malloc_use_mmalloc;
+
+int malloc_use_mmalloc(void)
+{
+ return __malloc_use_mmalloc;
+}
static xbt_mheap_t __mmalloc_current_heap = NULL; /* The heap we are currently using. */
return __mmalloc_current_heap;
}
-void mmalloc_set_current_heap(xbt_mheap_t new_heap)
+xbt_mheap_t mmalloc_set_current_heap(xbt_mheap_t new_heap)
{
+ xbt_mheap_t heap = __mmalloc_current_heap;
__mmalloc_current_heap = new_heap;
+ return heap;
}
-
#ifdef MMALLOC_WANT_OVERRIDE_LEGACY
-#if 0 && defined(HAVE_GNU_LD)
-#undef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#include <dlfcn.h>
-
-static void * (*real_malloc) (size_t) = NULL;
-static void * (*real_realloc) (void*,size_t) = NULL;
-static void * (*real_free) (void*) = NULL;
+/* Fake implementations, they are used to fool dlsym:
+ * dlsym used calloc and falls back to some other mechanism
+ * if this fails.
+ */
+static void* mm_fake_calloc(size_t nmemb, size_t size) { return NULL; }
+static void* mm_fake_malloc(size_t n) { return NULL; }
+static void* mm_fake_realloc(void *p, size_t s) { return NULL; }
-static void mm_gnuld_legacy_init(void) { /* This function is called from mmalloc_preinit(); it works even if it's static because all mm is in mm.c */
- real_malloc = (void * (*) (size_t)) dlsym(RTLD_NEXT, "malloc");
- real_realloc = (void * (*) (void*,size_t)) dlsym(RTLD_NEXT, "realloc");
- real_free = (void * (*) (void*)) dlsym(RTLD_NEXT, "free");
- __mmalloc_current_heap = __mmalloc_default_mdp;
-}
+/* Function signatures for the main malloc functions: */
+typedef void* (*mm_malloc_t)(size_t size);
+typedef void (*mm_free_t)(void*);
+typedef void* (*mm_calloc_t)(size_t nmemb, size_t size);
+typedef void* (*mm_realloc_t)(void *ptr, size_t size);
-/* Hello pimple!
- * DL needs some memory while resolving the malloc symbol, that is somehow problematic
- * To that extend, we have a little area here living in .BSS that we return if asked for memory before the malloc is resolved.
- */
-static int allocated_junk = 0; /* keep track of many blocks of our little area was already given to someone */
-#define JUNK_SIZE 8
-#define MAX_JUNK_AREAS (64 * 1024 / JUNK_SIZE)
-static char junkareas[MAX_JUNK_AREAS][JUNK_SIZE];
-
-/* This version use mmalloc if there is a current heap, or the legacy implem if not */
-static void *malloc_or_calloc(size_t n, int setzero) {
- xbt_mheap_t mdp = __mmalloc_current_heap;
- void *ret;
-#ifdef MM_LEGACY_VERBOSE
- static int warned_raw = 0;
- static int warned_mmalloc = 0;
-#endif
-
- if (mdp) {
- LOCK(mdp);
- ret = mmalloc(mdp, n);
- UNLOCK(mdp);
- // This was already done by mmalloc:
- if (mdp->options & XBT_MHEAP_OPTION_MEMSET) {
- setzero = 0;
- }
-#ifdef MM_LEGACY_VERBOSE
- if (!warned_mmalloc) {
- fprintf(stderr,"Using mmalloc; enabling the model-checker in cmake may have a bad impact on your simulation performance\n");
- warned_mmalloc = 1;
- }
-#endif
- } else if (!real_malloc) {
- size_t needed_areas = n / JUNK_SIZE;
- if(needed_areas * JUNK_SIZE != n) needed_areas++;
- if (allocated_junk+needed_areas>=MAX_JUNK_AREAS) {
- fprintf(stderr,
- "Panic: real malloc symbol not resolved yet, and I already gave my little private memory chunk away.\n");
- exit(1);
- } else {
- size_t i = allocated_junk;
- allocated_junk += needed_areas;
- ret = junkareas[i];
- }
- }
- else {
-#ifdef MM_LEGACY_VERBOSE
- if (!warned_raw) {
- fprintf(stderr,"Using system malloc after interception; you seem to be currently model-checking\n");
- warned_raw = 1;
- }
-#endif
- ret = real_malloc(n);
- }
- if (ret && setzero) {
- memset(ret, 0, n);
- }
- return ret;
-}
+/* Function pointers to the real/next implementations: */
+static mm_malloc_t mm_real_malloc = mm_fake_malloc;
+static mm_free_t mm_real_free;
+static mm_calloc_t mm_real_calloc = mm_fake_calloc;
+static mm_realloc_t mm_real_realloc = mm_fake_realloc;
-void *malloc(size_t n)
-{
- return malloc_or_calloc(n, 0);
-}
+#define GET_HEAP() __mmalloc_current_heap
-void *calloc(size_t nmemb, size_t size)
+/** Constructor functions used to initialize the malloc implementation
+ */
+static void __attribute__((constructor(101))) mm_legacy_constructor()
{
- return malloc_or_calloc(nmemb*size, 1);
+ __malloc_use_mmalloc = getenv(MC_ENV_VARIABLE) ? 1 : 0;
+ if (__malloc_use_mmalloc) {
+ __mmalloc_current_heap = mmalloc_preinit();
+ } else {
+ mm_real_realloc = (mm_realloc_t) dlsym(RTLD_NEXT, "realloc");
+ mm_real_malloc = (mm_malloc_t) dlsym(RTLD_NEXT, "malloc");
+ mm_real_free = (mm_free_t) dlsym(RTLD_NEXT, "free");
+ mm_real_calloc = (mm_calloc_t) dlsym(RTLD_NEXT, "calloc");
+ }
}
-void *realloc(void *p, size_t s)
+void* malloc_no_memset(size_t n)
{
- xbt_mheap_t mdp = __mmalloc_current_heap;
- void *ret;
-
- if (mdp) {
- LOCK(mdp);
- ret = mrealloc(mdp, p, s);
- UNLOCK(mdp);
- } else {
- ret = real_realloc(p,s);
+ if (!__malloc_use_mmalloc) {
+ return mm_real_malloc(n);
}
+ xbt_mheap_t mdp = GET_HEAP();
+ if (!mdp)
+ return NULL;
+
+ LOCK(mdp);
+ void *ret = mmalloc_no_memset(mdp, n);
+ UNLOCK(mdp);
return ret;
}
-void free(void *p)
+void *malloc(size_t n)
{
- if (p==NULL)
- return;
- if (p<(void*)junkareas || p>=(void*)(junkareas[MAX_JUNK_AREAS]) ) {
- // main use case
-
- xbt_mheap_t mdp = __mmalloc_current_heap;
-
- if (mdp) {
- LOCK(mdp);
- mfree(mdp, p);
- UNLOCK(mdp);
- } else {
- real_free(p);
- }
- } else {
- // We are in the junkarea.
- // This area is used to allocate memory at initilization time.
-
- if(allocated_junk && p==junkareas[allocated_junk-1]) {
- // Last junkarea. We can reuse it.
- allocated_junk--;
- } else {
- // We currently cannot reuse freed junkareas in the general case.
- }
+ if (!__malloc_use_mmalloc) {
+ return mm_real_malloc(n);
}
-}
-
-#else /* NO GNU_LD */
-void *malloc(size_t n)
-{
- xbt_mheap_t mdp = __mmalloc_current_heap ?: (xbt_mheap_t) mmalloc_preinit();
+ xbt_mheap_t mdp = GET_HEAP();
+ if (!mdp)
+ return NULL;
LOCK(mdp);
void *ret = mmalloc(mdp, n);
UNLOCK(mdp);
-
-
return ret;
}
void *calloc(size_t nmemb, size_t size)
{
- xbt_mheap_t mdp = __mmalloc_current_heap ?: (xbt_mheap_t) mmalloc_preinit();
+ if (!__malloc_use_mmalloc) {
+ return mm_real_calloc(nmemb, size);
+ }
+
+ xbt_mheap_t mdp = GET_HEAP();
+ if (!mdp)
+ return NULL;
LOCK(mdp);
void *ret = mmalloc(mdp, nmemb*size);
UNLOCK(mdp);
-
// This was already done in the callee:
if(!(mdp->options & XBT_MHEAP_OPTION_MEMSET)) {
memset(ret, 0, nmemb * size);
}
-
return ret;
}
void *realloc(void *p, size_t s)
{
- void *ret = NULL;
- xbt_mheap_t mdp = __mmalloc_current_heap ?: (xbt_mheap_t) mmalloc_preinit();
+ if (!__malloc_use_mmalloc) {
+ return mm_real_realloc(p, s);
+ }
+
+ xbt_mheap_t mdp = GET_HEAP();
+ if (!mdp)
+ return NULL;
LOCK(mdp);
- ret = mrealloc(mdp, p, s);
+ void* ret = mrealloc(mdp, p, s);
UNLOCK(mdp);
-
return ret;
}
void free(void *p)
{
- if (p != NULL) {
- xbt_mheap_t mdp = __mmalloc_current_heap ?: (xbt_mheap_t) mmalloc_preinit();
-
- LOCK(mdp);
- mfree(mdp, p);
- UNLOCK(mdp);
+ if (!__malloc_use_mmalloc) {
+ mm_real_free(p);
+ return;
}
+
+ if (!p)
+ return;
+
+ xbt_mheap_t mdp = GET_HEAP();
+ LOCK(mdp);
+ mfree(mdp, p);
+ UNLOCK(mdp);
}
-#endif /* NO GNU_LD */
#endif /* WANT_MALLOC_OVERRIDE */
}
xbt_assert(__mmalloc_default_mdp != NULL);
-#if 0 && defined(HAVE_GNU_LD) && defined(MMALLOC_WANT_OVERRIDE_LEGACY)
- mm_gnuld_legacy_init();
-#endif
-
return __mmalloc_default_mdp;
}
// xbt_mheap_destroy_no_free(__mmalloc_default_mdp);
}
-size_t mmalloc_get_bytes_used(xbt_mheap_t heap){
- int i = 0, j = 0;
+// This is the underlying implementation of mmalloc_get_bytes_used_remote.
+// Is it used directly in order to evaluate the bytes used from a different
+// process.
+size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo)
+{
int bytes = 0;
-
- while(i<=((struct mdesc *)heap)->heaplimit){
- if(((struct mdesc *)heap)->heapinfo[i].type == MMALLOC_TYPE_UNFRAGMENTED){
- if(((struct mdesc *)heap)->heapinfo[i].busy_block.busy_size > 0)
- bytes += ((struct mdesc *)heap)->heapinfo[i].busy_block.busy_size;
-
- } else if(((struct mdesc *)heap)->heapinfo[i].type > 0){
- for(j=0; j < (size_t) (BLOCKSIZE >> ((struct mdesc *)heap)->heapinfo[i].type); j++){
- if(((struct mdesc *)heap)->heapinfo[i].busy_frag.frag_size[j] > 0)
- bytes += ((struct mdesc *)heap)->heapinfo[i].busy_frag.frag_size[j];
+ for (size_t i=0; i<=heaplimit; ++i){
+ if (heapinfo[i].type == MMALLOC_TYPE_UNFRAGMENTED){
+ if (heapinfo[i].busy_block.busy_size > 0)
+ bytes += heapinfo[i].busy_block.busy_size;
+ } else if (heapinfo[i].type > 0) {
+ for (size_t j=0; j < (size_t) (BLOCKSIZE >> heapinfo[i].type); j++){
+ if(heapinfo[i].busy_frag.frag_size[j] > 0)
+ bytes += heapinfo[i].busy_frag.frag_size[j];
}
}
- i++;
}
-
return bytes;
}
+size_t mmalloc_get_bytes_used(const xbt_mheap_t heap){
+ const struct mdesc* heap_data = (const struct mdesc *) heap;
+ return mmalloc_get_bytes_used_remote(heap_data->heaplimit, heap_data->heapinfo);
+}
+
ssize_t mmalloc_get_busy_size(xbt_mheap_t heap, void *ptr){
ssize_t block = ((char*)ptr - (char*)(heap->heapbase)) / BLOCKSIZE + 1;
void mmcheck(xbt_mheap_t heap);
+int malloc_use_mmalloc(void);
+
+int mmalloc_exec_using_mm(int argc, const char** argv);
+void mmalloc_ensure_using_mm(int argc, const char** argv);
+
+size_t mmalloc_get_bytes_used_remote(size_t heaplimit, const malloc_info* heapinfo);
+
#endif /* __MMPRIVATE_H */
++xbt_pagebits;
}
-#ifdef MMALLOC_WANT_OVERRIDE_LEGACY
- mmalloc_preinit();
-#endif
#ifdef _TWO_DIGIT_EXPONENT
/* Even printf behaves differently on Windows... */
_set_output_format(_TWO_DIGIT_EXPONENT);
#define XBT_MODINTER_H
#include "xbt/misc.h"
+SG_BEGIN_DECL()
+
/* Modules definitions */
void xbt_backtrace_preinit(void);
void xbt_backtrace_postexit(void);
void *mmalloc_preinit(void);
void mmalloc_postexit(void);
+SG_END_DECL()
#endif /* XBT_MODINTER_H */
#include "../../src/include/mc/datatypes.h"
#include "../../src/mc/mc_object_info.h"
#include "../../src/mc/mc_private.h"
+#include "../../src/mc/mc_model_checker.h"
int test_some_array[4][5][6];
struct some_struct { int first; int second[4][5]; } test_some_struct;
return NULL;
}
-static dw_variable_t find_global_variable_by_name(mc_object_info_t info, const char* name) {
- unsigned int cursor = 0;
- dw_variable_t variable;
- xbt_dynar_foreach(info->global_variables, cursor, variable){
- if(!strcmp(name, variable->name))
- return variable;
- }
-
- return NULL;
-}
-
static dw_frame_t find_function_by_name(mc_object_info_t info, const char* name) {
xbt_dict_cursor_t cursor = 0;
dw_frame_t subprogram;
}
-static dw_variable_t test_global_variable(mc_object_info_t info, const char* name, void* address, long byte_size) {
- dw_variable_t variable = find_global_variable_by_name(info, name);
+static dw_variable_t test_global_variable(mc_process_t process, mc_object_info_t info, const char* name, void* address, long byte_size) {
+
+ dw_variable_t variable = MC_file_object_info_find_variable_by_name(info, name);
xbt_assert(variable, "Global variable %s was not found", name);
xbt_assert(!strcmp(variable->name, name), "Name mismatch for %s", name);
xbt_assert(variable->global, "Variable %s is not global", name);
xbt_assert(variable->address == address,
"Address mismatch for %s : %p expected but %p found", name, address, variable->address);
- dw_type_t type = xbt_dict_get_or_null(mc_binary_info->types, variable->type_origin);
+ dw_type_t type = xbt_dict_get_or_null(process->binary_info->types, variable->type_origin);
xbt_assert(type!=NULL, "Missing type for %s", name);
xbt_assert(type->byte_size = byte_size, "Byte size mismatch for %s", name);
return variable;
typedef struct foo {int i;} s_foo;
-static void test_type_by_name(s_foo my_foo) {
- assert(xbt_dict_get_or_null(mc_binary_info->full_types_by_name, "struct foo"));
+static void test_type_by_name(mc_process_t process, s_foo my_foo) {
+ assert(xbt_dict_get_or_null(process->binary_info->full_types_by_name, "struct foo"));
}
-int main(int argc, char** argv) {
-
- // xbt_init(&argc, argv);
+int main(int argc, char** argv)
+{
SIMIX_global_init(&argc, argv);
- MC_memory_init();
- MC_init();
dw_variable_t var;
dw_type_t type;
+
+ s_mc_process_t p;
+ mc_process_t process = &p;
+ MC_process_init(&p, getpid(), -1);
- test_global_variable(mc_binary_info, "some_local_variable", &some_local_variable, sizeof(int));
+ test_global_variable(process, process->binary_info, "some_local_variable", &some_local_variable, sizeof(int));
- var = test_global_variable(mc_binary_info, "test_some_array", &test_some_array, sizeof(test_some_array));
- type = xbt_dict_get_or_null(mc_binary_info->types, var->type_origin);
+ var = test_global_variable(process, process->binary_info, "test_some_array", &test_some_array, sizeof(test_some_array));
+ type = xbt_dict_get_or_null(process->binary_info->types, var->type_origin);
xbt_assert(type->element_count == 6*5*4, "element_count mismatch in test_some_array : %i / %i", type->element_count, 6*5*4);
- var = test_global_variable(mc_binary_info, "test_some_struct", &test_some_struct, sizeof(test_some_struct));
- type = xbt_dict_get_or_null(mc_binary_info->types, var->type_origin);
- assert(find_member(mc_binary_info, "first", type)->offset == 0);
- assert(find_member(mc_binary_info, "second", type)->offset
+ var = test_global_variable(process, process->binary_info, "test_some_struct", &test_some_struct, sizeof(test_some_struct));
+ type = xbt_dict_get_or_null(process->binary_info->types, var->type_origin);
+ assert(find_member(process->binary_info, "first", type)->offset == 0);
+ assert(find_member(process->binary_info, "second", type)->offset
== ((const char*)&test_some_struct.second) - (const char*)&test_some_struct);
unw_context_t context;
unw_getcontext(&context);
unw_init_local(&cursor, &context);
- test_local_variable(mc_binary_info, "main", "argc", &argc, &cursor);
+ test_local_variable(process->binary_info, "main", "argc", &argc, &cursor);
{
int lexical_block_variable = 50;
- test_local_variable(mc_binary_info, "main", "lexical_block_variable", &lexical_block_variable, &cursor);
+ test_local_variable(process->binary_info, "main", "lexical_block_variable", &lexical_block_variable, &cursor);
}
s_foo my_foo;
- test_type_by_name(my_foo);
+ test_type_by_name(process, my_foo);
_exit(0);
}
#! ./tesh
$ $SG_TEST_EXENV ${bindir:=.}/dwarf
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
#include "../src/mc/mc_private.h"
#include "../src/mc/mc_object_info.h"
+static s_mc_process_t process;
+
static
uintptr_t eval_binary_operation(mc_expression_state_t state, int op, uintptr_t a, uintptr_t b) {
state->stack_size = 0;
}
int main(int argc, char** argv) {
+ MC_process_init(&process, getpid(), -1);
+
s_mc_expression_state_t state;
memset(&state, 0, sizeof(s_mc_expression_state_t));
+ state.address_space = (mc_address_space_t) &process;
basic_test(&state);
#include <stdio.h>
+#include <xbt/log.h>
#include <simgrid/msg.h>
#include <simgrid/modelchecker.h>
+XBT_LOG_NEW_DEFAULT_CATEGORY(random_bug, "Application");
+
/** An (fake) application with a bug occuring for some random values
*/
static int app(int argc, char *argv[])
MSG_function_register("app", &app);
MSG_create_environment(argv[1]);
MSG_launch_application(argv[2]);
- return (int) MSG_main();
+ return MSG_main();
}
#!/usr/bin/env tesh
!expect signal SIGABRT
-$ ${bindir:=.}/random_bug ${srcdir:=.}/../../../examples/platforms/small_platform.xml ${srcdir:=.}/random_bug.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --cfg=model-check:1 --cfg=model-check/record:1
-> [ 0.000000] (0:@) Configuration change: Set 'model-check' to '1'
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/record' to '1'
+$ ${bindir:=.}/../../../bin/simgrid-mc ${bindir:=.}/random_bug ${srcdir:=.}/../../../examples/platforms/small_platform.xml ${srcdir:=.}/random_bug.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" --log=xbt_cfg.thresh:warning --cfg=model-check:1 --cfg=model-check/record:1
> [ 0.000000] (0:@) Check a safety property
-> [ 0.000000] (0:@) Get debug information ...
-> [ 0.000000] (0:@) Get debug information done !
-> [ 0.000000] (1:app@Tremblay) **************************
-> [ 0.000000] (1:app@Tremblay) *** PROPERTY NOT VALID ***
-> [ 0.000000] (1:app@Tremblay) **************************
-> [ 0.000000] (1:app@Tremblay) Counter-example execution trace:
-> [ 0.000000] (1:app@Tremblay) Path = 1/3;1/4
-> [ 0.000000] (1:app@Tremblay) [(1)Tremblay (app)] MC_RANDOM(3)
-> [ 0.000000] (1:app@Tremblay) [(1)Tremblay (app)] MC_RANDOM(4)
-> [ 0.000000] (1:app@Tremblay) Expanded states = 27
-> [ 0.000000] (1:app@Tremblay) Visited states = 68
-> [ 0.000000] (1:app@Tremblay) Executed transitions = 46
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) *** PROPERTY NOT VALID ***
+> [ 0.000000] (0:@) **************************
+> [ 0.000000] (0:@) Counter-example execution trace:
+> [ 0.000000] (0:@) Path = 1/3;1/4
+> [ 0.000000] (0:@) [(1)Tremblay (app)] MC_RANDOM(3)
+> [ 0.000000] (0:@) [(1)Tremblay (app)] MC_RANDOM(4)
+> [ 0.000000] (0:@) Expanded states = 27
+> [ 0.000000] (0:@) Visited states = 68
+> [ 0.000000] (0:@) Executed transitions = 46
#!/usr/bin/env tesh
-$ ${bindir:=.}/random_bug ${srcdir:=.}/../../../examples/platforms/small_platform.xml ${srcdir:=.}/random_bug.xml "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" "--cfg=model-check/replay:1/3;1/4"
-> [ 0.000000] (0:@) Configuration change: Set 'model-check/replay' to '1/3;1/4'
+$ ${bindir:=.}/random_bug ${srcdir:=.}/../../../examples/platforms/small_platform.xml ${srcdir:=.}/random_bug.xml --log=xbt_cfg.thresh:warning "--log=root.fmt:[%10.6r]%e(%i:%P@%h)%e%m%n" "--cfg=model-check/replay:1/3;1/4"
> [ 0.000000] (0:@) path=1/3;1/4
> Error reached
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock10
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --log=xbt_cfg.thresh:warning --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock10
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 26
> [0.000000] [mc_global/INFO] Executed transitions = 25
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock4
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --log=xbt_cfg.thresh:warning --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock4
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock5
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --log=xbt_cfg.thresh:warning --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock5
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 26
> [0.000000] [mc_global/INFO] Executed transitions = 25
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock6
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-can-deadlock6
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 26
> [0.000000] [mc_global/INFO] Executed transitions = 25
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-wait-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-wait-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 23
> [0.000000] [mc_global/INFO] Executed transitions = 22
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitall-deadlock2
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitall-deadlock2
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 26
> [0.000000] [mc_global/INFO] Executed transitions = 25
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitall-deadlock3
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitall-deadlock3
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 29
> [0.000000] [mc_global/INFO] Executed transitions = 28
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitany-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitany-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 24
> [0.000000] [mc_global/INFO] Executed transitions = 23
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitany-deadlock2
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/any_src-waitany-deadlock2
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 29
> [0.000000] [mc_global/INFO] Executed transitions = 28
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_create
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun --log=xbt_cfg.thresh:warning -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_create
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Executed transitions = 22
> (1) Got MPI_COMM_NULL
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_dup
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_dup
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 23
> [0.000000] [mc_global/INFO] Executed transitions = 22
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_split
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock-comm_split
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Executed transitions = 34
> (1) Derived communicator too small (size = 1)
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/basic-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 23
> [0.000000] [mc_global/INFO] Executed transitions = 22
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/bcast-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/bcast-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 4
> [0.000000] [mc_global/INFO] Executed transitions = 3
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/collective-misorder-allreduce
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/collective-misorder-allreduce
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 23
> [0.000000] [mc_global/INFO] Executed transitions = 22
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/collective-misorder
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/collective-misorder
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 45
> [0.000000] [mc_global/INFO] Executed transitions = 44
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/complex-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/complex-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 26
> [0.000000] [mc_global/INFO] Executed transitions = 25
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/deadlock-config
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/deadlock-config
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> WARNING: This test depends on the MPI's eager limit. Set it appropriately.
> Initializing (0 of 3)
> (0) is alive on Tremblay
> [0.000000] [mc_global/INFO] Visited states = 4
> [0.000000] [mc_global/INFO] Executed transitions = 3
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/finalize-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/finalize-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> (1) Finished normally
> (2) Finished normally
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/irecv-deadlock
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/irecv-deadlock
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> [0.000000] [mc_global/INFO] Visited states = 22
> [0.000000] [mc_global/INFO] Executed transitions = 21
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> (0) Finished normally
> (1) Finished normally
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error2
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error2
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> (2) Finished normally
> (0) Finished normally
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error3-any_src
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error3-any_src
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> (2) Finished normally
> (0) Finished normally
> Aborted
-
#! ./tesh
! expect return 134
-$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error3
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'surf/precision' to '1e-9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/model' to 'SMPI'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'network/TCP_gamma' to '4194304'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'model-check' to '1'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/running_power' to '1e9'
-> [0.000000] [xbt_cfg/INFO] Configuration change: Set 'smpi/coll_selector' to 'mpich'
+$ ${bindir:=.}/../../../../bin/smpirun -hostfile ../../hostfile -platform ../../../../examples/platforms/small_platform.xml --log=xbt_cfg.thresh:warning -np 3 --cfg=model-check:1 --cfg=smpi/running_power:1e9 --cfg=smpi/coll_selector:mpich ${bindir:=.}/no-error3
> [0.000000] [surf_config/INFO] Switching workstation model to compound since you changed the network and/or cpu model(s)
> [0.000000] [mc_global/INFO] Check a safety property
-> [0.000000] [mc_global/INFO] Get debug information ...
-> [0.000000] [mc_global/INFO] Get debug information done !
> (0) is alive on Tremblay
> (1) is alive on Jupiter
> (2) is alive on Fafard
> (2) Finished normally
> (0) Finished normally
> Aborted
-