model: implement, use schedule_next_thread()
[c11tester.git] / model.cc
1 #include <stdio.h>
2
3 #include "model.h"
4 #include "schedule.h"
5 #include "common.h"
6
7 ModelChecker *model;
8
9 ModelChecker::ModelChecker()
10 {
11         /* First thread created (system_thread) will have id 1 */
12         this->used_thread_id = 0;
13         /* Initialize default scheduler */
14         this->scheduler = new Scheduler();
15
16         this->current_action = NULL;
17         this->exploring = NULL;
18         this->nextThread = THREAD_ID_T_NONE;
19
20         rootNode = new TreeNode(NULL);
21         currentNode = rootNode;
22         action_trace = new action_list_t();
23 }
24
25 ModelChecker::~ModelChecker()
26 {
27         delete action_trace;
28         delete this->scheduler;
29         delete rootNode;
30 }
31
32 void ModelChecker::assign_id(Thread *t)
33 {
34         t->set_id(++used_thread_id);
35 }
36
37 void ModelChecker::add_system_thread(Thread *t)
38 {
39         this->system_thread = t;
40 }
41
42 Thread *ModelChecker::schedule_next_thread()
43 {
44         Thread *t;
45         if (nextThread == THREAD_ID_T_NONE)
46                 return NULL;
47         t = thread_map[nextThread];
48         if (t == NULL)
49                 DEBUG("*** error: thread not in thread_map: id = %d\n", nextThread);
50         return t;
51 }
52
53 ModelAction *ModelChecker::get_last_conflict(ModelAction *act)
54 {
55         void *loc = act->get_location();
56         action_type type = act->get_type();
57         thread_id_t id = act->get_tid();
58
59         switch (type) {
60                 case THREAD_CREATE:
61                 case THREAD_YIELD:
62                 case THREAD_JOIN:
63                         return NULL;
64                 case ATOMIC_READ:
65                 case ATOMIC_WRITE:
66                 default:
67                         break;
68         }
69         action_list_t::reverse_iterator rit;
70         for (rit = action_trace->rbegin(); rit != action_trace->rend(); rit++) {
71                 ModelAction *prev = *rit;
72                 if (prev->get_location() != loc)
73                         continue;
74                 if (type == ATOMIC_READ && prev->get_type() != ATOMIC_WRITE)
75                         continue;
76                 /* Conflict from the same thread is not really a conflict */
77                 if (id == prev->get_tid())
78                         return NULL;
79                 return prev;
80         }
81         return NULL;
82 }
83
84 void ModelChecker::set_backtracking(ModelAction *act)
85 {
86         ModelAction *prev;
87         TreeNode *node;
88
89         prev = get_last_conflict(act);
90         if (prev == NULL)
91                 return;
92
93         node = prev->get_node();
94
95         /* Check if this has been explored already */
96         if (node->hasBeenExplored(act->get_tid()))
97                 return;
98         /* If this is a new backtracking point, mark the tree */
99         if (node->setBacktrack(act->get_tid()) != 0)
100                 return;
101
102         printf("Setting backtrack: conflict = %d, instead tid = %d\n",
103                         prev->get_tid(), act->get_tid());
104         prev->print();
105         act->print();
106
107         Backtrack *back = new Backtrack(prev, action_trace);
108         backtrack_list.push_back(back);
109 }
110
111 void ModelChecker::check_current_action(void)
112 {
113         ModelAction *next = this->current_action;
114
115         if (!next) {
116                 DEBUG("trying to push NULL action...\n");
117                 return;
118         }
119         next->set_node(currentNode);
120         set_backtracking(next);
121         currentNode = currentNode->exploreChild(next->get_tid());
122         this->action_trace->push_back(next);
123 }
124
125 void ModelChecker::print_trace(void)
126 {
127         action_list_t::iterator it;
128
129         printf("\n");
130         printf("---------------------------------------------------------------------\n");
131         printf("Total nodes created: %d\n\n", TreeNode::getTotalNodes());
132
133         for (it = action_trace->begin(); it != action_trace->end(); it++) {
134                 DBG();
135                 (*it)->print();
136         }
137         printf("---------------------------------------------------------------------\n");
138 }
139
140 int ModelChecker::add_thread(Thread *t)
141 {
142         thread_map[t->get_id()] = t;
143         return 0;
144 }
145
146 int ModelChecker::switch_to_master(ModelAction *act)
147 {
148         Thread *old, *next;
149
150         DBG();
151         old = thread_current();
152         set_current_action(act);
153         old->set_state(THREAD_READY);
154         next = system_thread;
155         return old->swap(next);
156 }
157
158 ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, int value)
159 {
160         Thread *t = thread_current();
161         ModelAction *act = this;
162
163         act->type = type;
164         act->order = order;
165         act->location = loc;
166         act->tid = t->get_id();
167         act->value = value;
168 }
169
170 void ModelAction::print(void)
171 {
172         const char *type_str;
173         switch (this->type) {
174         case THREAD_CREATE:
175                 type_str = "thread create";
176                 break;
177         case THREAD_YIELD:
178                 type_str = "thread yield";
179                 break;
180         case THREAD_JOIN:
181                 type_str = "thread join";
182                 break;
183         case ATOMIC_READ:
184                 type_str = "atomic read";
185                 break;
186         case ATOMIC_WRITE:
187                 type_str = "atomic write";
188                 break;
189         default:
190                 type_str = "unknown type";
191         }
192
193         printf("Thread: %d\tAction: %s\tMO: %d\tLoc: %#014zx\tValue: %d\n", tid, type_str, order, (size_t)location, value);
194 }