changes
[model-checker.git] / action.cc
1 #include <stdio.h>
2 #define __STDC_FORMAT_MACROS
3 #include <inttypes.h>
4 #include <vector>
5
6 #include "model.h"
7 #include "action.h"
8 #include "clockvector.h"
9 #include "common.h"
10
11 ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, uint64_t value) :
12         type(type),
13         order(order),
14         location(loc),
15         value(value),
16         reads_from(NULL),
17         cv(NULL)
18 {
19         Thread *t = thread_current();
20         this->tid = t->get_id();
21         this->seq_number = model->get_next_seq_num();
22 }
23
24 ModelAction::~ModelAction()
25 {
26         if (cv)
27                 delete cv;
28 }
29
30 bool ModelAction::is_read() const
31 {
32         return type == ATOMIC_READ || type == ATOMIC_RMWR || type == ATOMIC_RMW;
33 }
34
35 bool ModelAction::is_write() const
36 {
37         return type == ATOMIC_WRITE || type == ATOMIC_RMW || type == ATOMIC_INIT;
38 }
39
40 bool ModelAction::is_rmwr() const
41 {
42         return type == ATOMIC_RMWR;
43 }
44
45 bool ModelAction::is_rmw() const
46 {
47         return type == ATOMIC_RMW;
48 }
49
50 bool ModelAction::is_rmwc() const
51 {
52         return type == ATOMIC_RMWC;
53 }
54
55 bool ModelAction::is_initialization() const
56 {
57         return type == ATOMIC_INIT;
58 }
59
60 bool ModelAction::is_acquire() const
61 {
62         switch (order) {
63         case std::memory_order_acquire:
64         case std::memory_order_acq_rel:
65         case std::memory_order_seq_cst:
66                 return true;
67         default:
68                 return false;
69         }
70 }
71
72 bool ModelAction::is_release() const
73 {
74         switch (order) {
75         case std::memory_order_release:
76         case std::memory_order_acq_rel:
77         case std::memory_order_seq_cst:
78                 return true;
79         default:
80                 return false;
81         }
82 }
83
84 bool ModelAction::is_seqcst() const
85 {
86         return order==std::memory_order_seq_cst;
87 }
88
89 bool ModelAction::same_var(const ModelAction *act) const
90 {
91         return location == act->location;
92 }
93
94 bool ModelAction::same_thread(const ModelAction *act) const
95 {
96         return tid == act->tid;
97 }
98
99 void ModelAction::copy_typeandorder(ModelAction * act) {
100         this->type=act->type;
101         this->order=act->order;
102 }
103
104 /** This method changes an existing read part of an RMW action into either:
105  *  (1) a full RMW action in case of the completed write or
106  *  (2) a READ action in case a failed action.
107  * @todo  If the memory_order changes, we may potentially need to update our
108  * clock vector.
109  */
110 void ModelAction::process_rmw(ModelAction * act) {
111         this->order=act->order;
112         if (act->is_rmwc())
113                 this->type=ATOMIC_READ;
114         else if (act->is_rmw()) {
115                 this->type=ATOMIC_RMW;
116                 this->value=act->value;
117         }
118 }
119
120 /** The is_synchronizing method should only explore interleavings if:
121  *  (1) the operations are seq_cst and don't commute or
122  *  (2) the reordering may establish or break a synchronization relation.
123  *  Other memory operations will be dealt with by using the reads_from
124  *  relation.
125  *
126  *  @param act is the action to consider exploring a reordering.
127  *  @return tells whether we have to explore a reordering.
128  */
129 bool ModelAction::is_synchronizing(const ModelAction *act) const
130 {
131         //Same thread can't be reordered
132         if (same_thread(act))
133                 return false;
134
135         // Different locations commute
136         if (!same_var(act))
137                 return false;
138
139         // Explore interleavings of seqcst writes to guarantee total order
140         // of seq_cst operations that don't commute
141         if (is_write() && is_seqcst() && act->is_write() && act->is_seqcst())
142                 return true;
143
144         // Explore synchronizing read/write pairs
145         if (is_read() && is_acquire() && act->is_write() && act->is_release())
146                 return true;
147         if (is_write() && is_release() && act->is_read() && act->is_acquire())
148                 return true;
149
150         // Otherwise handle by reads_from relation
151         return false;
152 }
153
154 void ModelAction::create_cv(const ModelAction *parent)
155 {
156         if (cv)
157                 delete cv;
158
159         if (parent)
160                 cv = new ClockVector(parent->cv, this);
161         else
162                 cv = new ClockVector(NULL, this);
163 }
164
165 /** Update the model action's read_from action */
166 void ModelAction::read_from(const ModelAction *act)
167 {
168         ASSERT(cv);
169         reads_from = act;
170         if (act != NULL && this->is_acquire()) {
171                 std::vector<const ModelAction *> release_heads;
172                 model->get_release_seq_heads(this, &release_heads);
173                 for (unsigned int i = 0; i < release_heads.size(); i++)
174                         synchronize_with(release_heads[i]);
175         }
176 }
177
178 /**
179  * Synchronize the current thread with the thread corresponding to the
180  * ModelAction parameter.
181  * @param act The ModelAction to synchronize with
182  */
183 void ModelAction::synchronize_with(const ModelAction *act) {
184         ASSERT(*act < *this);
185         model->check_promises(cv, act->cv);
186         cv->merge(act->cv);
187 }
188
189 bool ModelAction::has_synchronized_with(const ModelAction *act) const
190 {
191         return cv->has_synchronized_with(act->cv);
192 }
193
194 /**
195  * Check whether 'this' happens before act, according to the memory-model's
196  * happens before relation. This is checked via the ClockVector constructs.
197  * @return true if this action's thread has synchronized with act's thread
198  * since the execution of act, false otherwise.
199  */
200 bool ModelAction::happens_before(const ModelAction *act) const
201 {
202         return act->cv->synchronized_since(this);
203 }
204
205 void ModelAction::print(void) const
206 {
207         const char *type_str, *mo_str;
208         switch (this->type) {
209         case THREAD_CREATE:
210                 type_str = "thread create";
211                 break;
212         case THREAD_START:
213                 type_str = "thread start";
214                 break;
215         case THREAD_YIELD:
216                 type_str = "thread yield";
217                 break;
218         case THREAD_JOIN:
219                 type_str = "thread join";
220                 break;
221         case THREAD_FINISH:
222                 type_str = "thread finish";
223                 break;
224         case ATOMIC_READ:
225                 type_str = "atomic read";
226                 break;
227         case ATOMIC_WRITE:
228                 type_str = "atomic write";
229                 break;
230         case ATOMIC_RMW:
231                 type_str = "atomic rmw";
232                 break;
233         case ATOMIC_RMWR:
234                 type_str = "atomic rmwr";
235                 break;
236         case ATOMIC_RMWC:
237                 type_str = "atomic rmwc";
238                 break;
239         case ATOMIC_INIT:
240                 type_str = "init atomic";
241                 break;
242         default:
243                 type_str = "unknown type";
244         }
245
246         uint64_t valuetoprint=type==ATOMIC_READ?(reads_from!=NULL?reads_from->value:VALUE_NONE):value;
247
248         switch (this->order) {
249         case std::memory_order_relaxed:
250                 mo_str = "relaxed";
251                 break;
252         case std::memory_order_acquire:
253                 mo_str = "acquire";
254                 break;
255         case std::memory_order_release:
256                 mo_str = "release";
257                 break;
258         case std::memory_order_acq_rel:
259                 mo_str = "acq_rel";
260                 break;
261         case std::memory_order_seq_cst:
262                 mo_str = "seq_cst";
263                 break;
264         default:
265                 mo_str = "unknown";
266                 break;
267         }
268
269         printf("(%3d) Thread: %-2d   Action: %-13s   MO: %7s  Loc: %14p  Value: %-12" PRIu64,
270                         seq_number, id_to_int(tid), type_str, mo_str, location, valuetoprint);
271         if (is_read()) {
272                 if (reads_from)
273                         printf(" Rf: %d", reads_from->get_seq_number());
274                 else
275                         printf(" Rf: ?");
276         }
277         if (cv) {
278                 printf("\t");
279                 cv->print();
280         } else
281                 printf("\n");
282 }