Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
63d7a58a7feb135d01d3a88fc6134c006dbe1a23
[simgrid.git] / src / mc / mc_base.c
1 /* Copyright (c) 2008-2014. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include <simgrid/simix.h>
8
9 #include "mc_base.h"
10 #include "../simix/smx_private.h"
11 #include "mc_record.h"
12
13 #ifdef HAVE_MC
14 #include "mc_process.h"
15 #include "mc_model_checker.h"
16 #include "mc_protocol.h"
17 #endif
18
19 XBT_LOG_NEW_CATEGORY(mc, "All MC categories");
20
21 void MC_wait_for_requests(void)
22 {
23   smx_process_t process;
24   smx_simcall_t req;
25   unsigned int iter;
26
27   while (!xbt_dynar_is_empty(simix_global->process_to_run)) {
28     SIMIX_process_runall();
29     xbt_dynar_foreach(simix_global->process_that_ran, iter, process) {
30       req = &process->simcall;
31       if (req->call != SIMCALL_NONE && !MC_request_is_visible(req))
32         SIMIX_simcall_handle(req, 0);
33     }
34   }
35 }
36
37 int MC_request_is_enabled(smx_simcall_t req)
38 {
39   unsigned int index = 0;
40   smx_synchro_t act = 0;
41 #ifdef HAVE_MC
42   s_smx_synchro_t temp_synchro;
43 #endif
44   smx_mutex_t mutex = NULL;
45
46   switch (req->call) {
47   case SIMCALL_NONE:
48     return FALSE;
49
50   case SIMCALL_COMM_WAIT:
51     /* FIXME: check also that src and dst processes are not suspended */
52     act = simcall_comm_wait__get__comm(req);
53
54 #ifdef HAVE_MC
55     // Fetch from MCed memory:
56     if (!MC_process_is_self(&mc_model_checker->process)) {
57       MC_process_read(&mc_model_checker->process, MC_PROCESS_NO_FLAG,
58         &temp_synchro, act, sizeof(temp_synchro),
59         MC_PROCESS_INDEX_ANY);
60       act = &temp_synchro;
61     }
62 #endif
63
64     if (simcall_comm_wait__get__timeout(req) >= 0) {
65       /* If it has a timeout it will be always be enabled, because even if the
66        * communication is not ready, it can timeout and won't block. */
67       if (_sg_mc_timeout == 1)
68         return TRUE;
69     } else {
70       /* On the other hand if it hasn't a timeout, check if the comm is ready.*/
71       if (act->comm.detached && act->comm.src_proc == NULL
72           && act->comm.type == SIMIX_COMM_READY)
73         return (act->comm.dst_proc != NULL);
74     }
75     return (act->comm.src_proc && act->comm.dst_proc);
76
77   case SIMCALL_COMM_WAITANY:
78     /* Check if it has at least one communication ready */
79     xbt_dynar_foreach(simcall_comm_waitany__get__comms(req), index, act) {
80
81 #ifdef HAVE_MC
82       // Fetch from MCed memory:
83       if (!MC_process_is_self(&mc_model_checker->process)) {
84         MC_process_read(&mc_model_checker->process, MC_PROCESS_NO_FLAG,
85           &temp_synchro, act, sizeof(temp_synchro),
86           MC_PROCESS_INDEX_ANY);
87         act = &temp_synchro;
88       }
89 #endif
90
91       if (act->comm.src_proc && act->comm.dst_proc)
92         return TRUE;
93     }
94     return FALSE;
95
96   case SIMCALL_MUTEX_LOCK:
97     mutex = simcall_mutex_lock__get__mutex(req);
98     if(mutex->owner == NULL)
99       return TRUE;
100     else
101       return (mutex->owner->pid == req->issuer->pid);
102
103   default:
104     /* The rest of the requests are always enabled */
105     return TRUE;
106   }
107 }
108
109 int MC_request_is_visible(smx_simcall_t req)
110 {
111   return req->call == SIMCALL_COMM_ISEND
112       || req->call == SIMCALL_COMM_IRECV
113       || req->call == SIMCALL_COMM_WAIT
114       || req->call == SIMCALL_COMM_WAITANY
115       || req->call == SIMCALL_COMM_TEST
116       || req->call == SIMCALL_COMM_TESTANY
117       || req->call == SIMCALL_MC_RANDOM
118       || req->call == SIMCALL_MUTEX_LOCK
119 #ifdef HAVE_MC
120       || req->call == SIMCALL_MC_SNAPSHOT
121       || req->call == SIMCALL_MC_COMPARE_SNAPSHOTS
122 #endif
123       ;
124 }
125
126 int MC_random(int min, int max)
127 {
128   /*FIXME: return mc_current_state->executed_transition->random.value; */
129   return simcall_mc_random(min, max);
130 }
131
132 static int prng_random(int min, int max)
133 {
134   unsigned long output_size = ((unsigned long) max - (unsigned long) min) + 1;
135   unsigned long input_size = (unsigned long) RAND_MAX + 1;
136   unsigned long reject_size = input_size % output_size;
137   unsigned long accept_size = input_size - reject_size; // module*accept_size
138
139   // Use rejection in order to avoid skew
140   long x;
141   do {
142 #ifndef _XBT_WIN32
143     x = random();
144 #else
145     x = rand();
146 #endif
147   } while( x >= accept_size );
148   return min + (x % output_size);
149 }
150
151 int simcall_HANDLER_mc_random(smx_simcall_t simcall, int min, int max)
152 {
153   if (!MC_is_active() && !MC_record_path){
154     return prng_random(min, max);
155   }
156
157   return simcall->mc_value;
158 }