order(order),
location(loc),
value(value),
+ reads_from(NULL),
cv(NULL)
{
Thread *t = thread_current();
ASSERT(cv);
if (act->is_release() && this->is_acquire())
cv->merge(act->cv);
+ reads_from = act;
value = act->value;
}
type_str = "unknown type";
}
- printf("(%3d) Thread: %-2d Action: %-13s MO: %d Loc: %14p Value: %d",
+ printf("(%3d) Thread: %-2d Action: %-13s MO: %d Loc: %14p Value: %-4d",
seq_number, id_to_int(tid), type_str, order, location, value);
+ if (reads_from)
+ printf(" Rf: %d", reads_from->get_seq_number());
if (cv) {
printf("\t");
cv->print();
void * get_location() const { return location; }
modelclock_t get_seq_number() const { return seq_number; }
int get_value() const { return value; }
+ const ModelAction * get_reads_from() const { return reads_from; }
Node * get_node() const { return node; }
void set_node(Node *n) { node = n; }
- void set_value(int val) { value = val; }
bool is_read() const;
bool is_write() const;
* should probably be something longer. */
int value;
+ /** The action that this action reads from. Only valid for reads */
+ const ModelAction *reads_from;
+
/** A back reference to a Node in NodeStack, if this ModelAction is
* saved on the NodeStack. */
Node *node;
}
/**
- * Merge a clock vector into this vector, using a pairwise vector. The
+ * Merge a clock vector into this vector, using a pairwise comparison. The
* resulting vector length will be the maximum length of the two being merged.
* @param cv is the ClockVector being merged into this vector.
*/
-void ClockVector::merge(ClockVector *cv)
+void ClockVector::merge(const ClockVector *cv)
{
modelclock_t *clk = clock;
bool resize = false;
public:
ClockVector(ClockVector *parent = NULL, ModelAction *act = NULL);
~ClockVector();
- void merge(ClockVector *cv);
+ void merge(const ClockVector *cv);
bool synchronized_since(const ModelAction *act) const;
void print() const;
int atomic_load_explicit(struct atomic_object *obj, memory_order order)
{
- int value = obj->value;
DBG();
- model->switch_to_master(new ModelAction(ATOMIC_READ, order, obj, value));
- return value;
+ model->switch_to_master(new ModelAction(ATOMIC_READ, order, obj));
+ return thread_current()->get_return_value();
}
void atomic_init(struct atomic_object *obj, int value)
/** The real_main function contains the main model checking loop. */
-void real_main() {
+static void real_main() {
thrd_t user_thread;
ucontext_t main_context;
set_backtracking(curr);
add_action_to_lists(curr);
+
+ /* Assign reads_from values */
+ /* TODO: perform release/acquire synchronization here; include
+ * reads_from as ModelAction member? */
+ Thread *th = get_thread(curr->get_tid());
+ int value = VALUE_NONE;
+ if (curr->is_read()) {
+ const ModelAction *reads_from = curr->get_node()->get_next_read_from();
+ value = reads_from->get_value();
+ /* Assign reads_from, perform release/acquire synchronization */
+ curr->read_from(reads_from);
+ }
+ th->set_return_value(value);
}
/**
may_read_from.push_back(act);
}
+/**
+ * Gets the next 'may_read_from' action from this Node. Only valid for a node
+ * where this->action is a 'read'.
+ * @todo Perform reads_from backtracking/replay properly, so that this function
+ * may remove elements from may_read_from
+ * @return The first element in may_read_from
+ */
+const ModelAction * Node::get_next_read_from() {
+ const ModelAction *act;
+ ASSERT(!may_read_from.empty());
+ act = may_read_from.front();
+ /* TODO: perform reads_from replay properly */
+ /* may_read_from.pop_front(); */
+ return act;
+}
+
void Node::explore(thread_id_t tid)
{
int i = id_to_int(tid);
Node * get_parent() const { return parent; }
void add_read_from(const ModelAction *act);
+ const ModelAction * get_next_read_from();
void print();
void print_may_read_from();