+ uint64_t value;
+ bool updated = false;
+ while (true) {
+ const ModelAction *reads_from = curr->get_node()->get_read_from();
+ if (reads_from != NULL) {
+ mo_graph->startChanges();
+
+ value = reads_from->get_value();
+ bool r_status = false;
+
+ if (!second_part_of_rmw) {
+ check_recency(curr);
+ r_status = r_modification_order(curr, reads_from);
+ }
+
+
+ if (!second_part_of_rmw&&!isfeasible()&&(curr->get_node()->increment_read_from()||curr->get_node()->increment_future_value())) {
+ mo_graph->rollbackChanges();
+ too_many_reads = false;
+ continue;
+ }
+
+ curr->read_from(reads_from);
+ mo_graph->commitChanges();
+ updated |= r_status;
+ } else if (!second_part_of_rmw) {
+ /* Read from future value */
+ value = curr->get_node()->get_future_value();
+ modelclock_t expiration = curr->get_node()->get_future_value_expiration();
+ curr->read_from(NULL);
+ Promise *valuepromise = new Promise(curr, value, expiration);
+ promises->push_back(valuepromise);
+ }
+ get_thread(curr)->set_return_value(value);
+ return updated;
+ }
+}
+
+/**
+ * Processes a lock, trylock, or unlock model action. @param curr is
+ * the read model action to process.
+ *
+ * The try lock operation checks whether the lock is taken. If not,
+ * it falls to the normal lock operation case. If so, it returns
+ * fail.
+ *
+ * The lock operation has already been checked that it is enabled, so
+ * it just grabs the lock and synchronizes with the previous unlock.
+ *
+ * The unlock operation has to re-enable all of the threads that are
+ * waiting on the lock.
+ */
+void ModelChecker::process_mutex(ModelAction *curr) {
+ std::mutex *mutex = (std::mutex *)curr->get_location();
+ struct std::mutex_state *state = mutex->get_state();
+ switch (curr->get_type()) {
+ case ATOMIC_TRYLOCK: {
+ bool success = !state->islocked;
+ curr->set_try_lock(success);
+ if (!success) {
+ get_thread(curr)->set_return_value(0);
+ break;
+ }
+ get_thread(curr)->set_return_value(1);
+ }
+ //otherwise fall into the lock case
+ case ATOMIC_LOCK: {
+ if (curr->get_cv()->getClock(state->alloc_tid) <= state->alloc_clock) {
+ printf("Lock access before initialization\n");
+ set_assert();
+ }
+ state->islocked = true;
+ ModelAction *unlock = get_last_unlock(curr);
+ //synchronize with the previous unlock statement
+ if (unlock != NULL)
+ curr->synchronize_with(unlock);
+ break;
+ }
+ case ATOMIC_UNLOCK: {
+ //unlock the lock
+ state->islocked = false;
+ //wake up the other threads
+ action_list_t *waiters = lock_waiters_map->get_safe_ptr(curr->get_location());
+ //activate all the waiting threads
+ for (action_list_t::iterator rit = waiters->begin(); rit != waiters->end(); rit++) {
+ scheduler->add_thread(get_thread((*rit)->get_tid()));
+ }
+ waiters->clear();
+ break;
+ }
+ default:
+ ASSERT(0);