11 #include "clockvector.h"
12 #include "cyclegraph.h"
14 #include "threads-model.h"
15 #include "bugmessage.h"
18 #include "newfuzzer.h"
20 #define INITIAL_THREAD_ID 0
23 * Structure for holding small ModelChecker members that should be snapshotted
25 struct model_snapshot_members {
26 model_snapshot_members() :
27 /* First thread created will have id INITIAL_THREAD_ID */
28 next_thread_id(INITIAL_THREAD_ID),
29 used_sequence_numbers(0),
31 bad_synchronization(false),
35 ~model_snapshot_members() {
36 for (unsigned int i = 0;i < bugs.size();i++)
41 unsigned int next_thread_id;
42 modelclock_t used_sequence_numbers;
43 SnapVector<bug_message *> bugs;
44 /** @brief Incorrectly-ordered synchronization was made */
45 bool bad_synchronization;
51 /** @brief Constructor */
52 ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
57 thread_map(2), /* We'll always need at least 2 threads */
61 condvar_waiters_map(),
65 thrd_last_fence_release(),
66 priv(new struct model_snapshot_members ()),
67 mo_graph(new CycleGraph()),
68 fuzzer(new NewFuzzer()),
70 thrd_func_act_lists(),
73 /* Initialize a model-checker thread, for special ModelActions */
74 model_thread = new Thread(get_next_id());
75 add_thread(model_thread);
76 scheduler->register_engine(this);
77 fuzzer->register_engine(m->get_history(), this);
80 /** @brief Destructor */
81 ModelExecution::~ModelExecution()
83 for (unsigned int i = 0;i < get_num_threads();i++)
84 delete get_thread(int_to_id(i));
90 int ModelExecution::get_execution_number() const
92 return model->get_execution_number();
95 static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t *, uintptr_t, 2> * hash, void * ptr)
97 action_list_t *tmp = hash->get(ptr);
99 tmp = new action_list_t();
105 static SnapVector<action_list_t> * get_safe_ptr_vect_action(HashTable<const void *, SnapVector<action_list_t> *, uintptr_t, 2> * hash, void * ptr)
107 SnapVector<action_list_t> *tmp = hash->get(ptr);
109 tmp = new SnapVector<action_list_t>();
115 /** @return a thread ID for a new Thread */
116 thread_id_t ModelExecution::get_next_id()
118 return priv->next_thread_id++;
121 /** @return the number of user threads created during this execution */
122 unsigned int ModelExecution::get_num_threads() const
124 return priv->next_thread_id;
127 /** @return a sequence number for a new ModelAction */
128 modelclock_t ModelExecution::get_next_seq_num()
130 return ++priv->used_sequence_numbers;
133 /** Restore the last used sequence number when actions of a thread are postponed by Fuzzer */
134 void ModelExecution::restore_last_seq_num()
136 priv->used_sequence_numbers--;
140 * @brief Should the current action wake up a given thread?
142 * @param curr The current action
143 * @param thread The thread that we might wake up
144 * @return True, if we should wake up the sleeping thread; false otherwise
146 bool ModelExecution::should_wake_up(const ModelAction *curr, const Thread *thread) const
148 const ModelAction *asleep = thread->get_pending();
149 /* Don't allow partial RMW to wake anyone up */
152 /* Synchronizing actions may have been backtracked */
153 if (asleep->could_synchronize_with(curr))
155 /* All acquire/release fences and fence-acquire/store-release */
156 if (asleep->is_fence() && asleep->is_acquire() && curr->is_release())
158 /* Fence-release + store can awake load-acquire on the same location */
159 if (asleep->is_read() && asleep->is_acquire() && curr->same_var(asleep) && curr->is_write()) {
160 ModelAction *fence_release = get_last_fence_release(curr->get_tid());
161 if (fence_release && *(get_last_action(thread->get_id())) < *fence_release)
164 if (asleep->is_sleep()) {
165 if (fuzzer->shouldWake(asleep))
172 void ModelExecution::wake_up_sleeping_actions(ModelAction *curr)
174 for (unsigned int i = 0;i < get_num_threads();i++) {
175 Thread *thr = get_thread(int_to_id(i));
176 if (scheduler->is_sleep_set(thr)) {
177 if (should_wake_up(curr, thr)) {
178 /* Remove this thread from sleep set */
179 scheduler->remove_sleep(thr);
180 if (thr->get_pending()->is_sleep())
181 thr->set_pending(NULL);
187 /** @brief Alert the model-checker that an incorrectly-ordered
188 * synchronization was made */
189 void ModelExecution::set_bad_synchronization()
191 priv->bad_synchronization = true;
194 bool ModelExecution::assert_bug(const char *msg)
196 priv->bugs.push_back(new bug_message(msg));
198 if (isfeasibleprefix()) {
205 /** @return True, if any bugs have been reported for this execution */
206 bool ModelExecution::have_bug_reports() const
208 return priv->bugs.size() != 0;
211 SnapVector<bug_message *> * ModelExecution::get_bugs() const
217 * Check whether the current trace has triggered an assertion which should halt
220 * @return True, if the execution should be aborted; false otherwise
222 bool ModelExecution::has_asserted() const
224 return priv->asserted;
228 * Trigger a trace assertion which should cause this execution to be halted.
229 * This can be due to a detected bug or due to an infeasibility that should
232 void ModelExecution::set_assert()
234 priv->asserted = true;
238 * Check if we are in a deadlock. Should only be called at the end of an
239 * execution, although it should not give false positives in the middle of an
240 * execution (there should be some ENABLED thread).
242 * @return True if program is in a deadlock; false otherwise
244 bool ModelExecution::is_deadlocked() const
246 bool blocking_threads = false;
247 for (unsigned int i = 0;i < get_num_threads();i++) {
248 thread_id_t tid = int_to_id(i);
251 Thread *t = get_thread(tid);
252 if (!t->is_model_thread() && t->get_pending())
253 blocking_threads = true;
255 return blocking_threads;
259 * Check if this is a complete execution. That is, have all thread completed
260 * execution (rather than exiting because sleep sets have forced a redundant
263 * @return True if the execution is complete.
265 bool ModelExecution::is_complete_execution() const
267 for (unsigned int i = 0;i < get_num_threads();i++)
268 if (is_enabled(int_to_id(i)))
273 ModelAction * ModelExecution::convertNonAtomicStore(void * location) {
274 uint64_t value = *((const uint64_t *) location);
275 modelclock_t storeclock;
276 thread_id_t storethread;
277 getStoreThreadAndClock(location, &storethread, &storeclock);
278 setAtomicStoreFlag(location);
279 ModelAction * act = new ModelAction(NONATOMIC_WRITE, memory_order_relaxed, location, value, get_thread(storethread));
280 act->set_seq_number(storeclock);
281 add_normal_write_to_lists(act);
282 add_write_to_lists(act);
283 w_modification_order(act);
284 model->get_history()->process_action(act, act->get_tid());
289 * Processes a read model action.
290 * @param curr is the read model action to process.
291 * @param rf_set is the set of model actions we can possibly read from
292 * @return True if processing this read updates the mo_graph.
294 bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set)
296 SnapVector<const ModelAction *> * priorset = new SnapVector<const ModelAction *>();
297 bool hasnonatomicstore = hasNonAtomicStore(curr->get_location());
298 if (hasnonatomicstore) {
299 ModelAction * nonatomicstore = convertNonAtomicStore(curr->get_location());
300 rf_set->push_back(nonatomicstore);
304 int index = fuzzer->selectWrite(curr, rf_set);
305 if (index == -1) // no feasible write exists
308 ModelAction *rf = (*rf_set)[index];
311 bool canprune = false;
312 if (r_modification_order(curr, rf, priorset, &canprune)) {
313 for(unsigned int i=0;i<priorset->size();i++) {
314 mo_graph->addEdge((*priorset)[i], rf);
317 get_thread(curr)->set_return_value(curr->get_return_value());
319 if (canprune && curr->get_type() == ATOMIC_READ) {
320 int tid = id_to_int(curr->get_tid());
321 (*obj_thrd_map.get(curr->get_location()))[tid].pop_back();
326 (*rf_set)[index] = rf_set->back();
332 * Processes a lock, trylock, or unlock model action. @param curr is
333 * the read model action to process.
335 * The try lock operation checks whether the lock is taken. If not,
336 * it falls to the normal lock operation case. If so, it returns
339 * The lock operation has already been checked that it is enabled, so
340 * it just grabs the lock and synchronizes with the previous unlock.
342 * The unlock operation has to re-enable all of the threads that are
343 * waiting on the lock.
345 * @return True if synchronization was updated; false otherwise
347 bool ModelExecution::process_mutex(ModelAction *curr)
349 cdsc::mutex *mutex = curr->get_mutex();
350 struct cdsc::mutex_state *state = NULL;
353 state = mutex->get_state();
355 switch (curr->get_type()) {
356 case ATOMIC_TRYLOCK: {
357 bool success = !state->locked;
358 curr->set_try_lock(success);
360 get_thread(curr)->set_return_value(0);
363 get_thread(curr)->set_return_value(1);
365 //otherwise fall into the lock case
367 //TODO: FIND SOME BETTER WAY TO CHECK LOCK INITIALIZED OR NOT
368 //if (curr->get_cv()->getClock(state->alloc_tid) <= state->alloc_clock)
369 // assert_bug("Lock access before initialization");
370 state->locked = get_thread(curr);
371 ModelAction *unlock = get_last_unlock(curr);
372 //synchronize with the previous unlock statement
373 if (unlock != NULL) {
374 synchronize(unlock, curr);
380 /* wake up the other threads */
381 for (unsigned int i = 0;i < get_num_threads();i++) {
382 Thread *t = get_thread(int_to_id(i));
383 Thread *curr_thrd = get_thread(curr);
384 if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock())
388 /* unlock the lock - after checking who was waiting on it */
389 state->locked = NULL;
391 if (fuzzer->shouldWait(curr)) {
392 /* disable this thread */
393 get_safe_ptr_action(&condvar_waiters_map, curr->get_location())->push_back(curr);
394 scheduler->sleep(get_thread(curr));
399 case ATOMIC_TIMEDWAIT:
400 case ATOMIC_UNLOCK: {
401 //TODO: FIX WAIT SITUATION...WAITS CAN SPURIOUSLY FAIL...TIMED WAITS SHOULD PROBABLY JUST BE THE SAME AS NORMAL WAITS...THINK ABOUT PROBABILITIES THOUGH....AS IN TIMED WAIT MUST FAIL TO GUARANTEE PROGRESS...NORMAL WAIT MAY FAIL...SO NEED NORMAL WAIT TO WORK CORRECTLY IN THE CASE IT SPURIOUSLY FAILS AND IN THE CASE IT DOESN'T... TIMED WAITS MUST EVENMTUALLY RELEASE...
403 /* wake up the other threads */
404 for (unsigned int i = 0;i < get_num_threads();i++) {
405 Thread *t = get_thread(int_to_id(i));
406 Thread *curr_thrd = get_thread(curr);
407 if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock())
411 /* unlock the lock - after checking who was waiting on it */
412 state->locked = NULL;
415 case ATOMIC_NOTIFY_ALL: {
416 action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
417 //activate all the waiting threads
418 for (sllnode<ModelAction *> * rit = waiters->begin();rit != NULL;rit=rit->getNext()) {
419 scheduler->wake(get_thread(rit->getVal()));
424 case ATOMIC_NOTIFY_ONE: {
425 action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
426 if (waiters->size() != 0) {
427 Thread * thread = fuzzer->selectNotify(waiters);
428 scheduler->wake(thread);
440 * Process a write ModelAction
441 * @param curr The ModelAction to process
442 * @return True if the mo_graph was updated or promises were resolved
444 void ModelExecution::process_write(ModelAction *curr)
446 w_modification_order(curr);
447 get_thread(curr)->set_return_value(VALUE_NONE);
451 * Process a fence ModelAction
452 * @param curr The ModelAction to process
453 * @return True if synchronization was updated
455 bool ModelExecution::process_fence(ModelAction *curr)
458 * fence-relaxed: no-op
459 * fence-release: only log the occurence (not in this function), for
460 * use in later synchronization
461 * fence-acquire (this function): search for hypothetical release
463 * fence-seq-cst: MO constraints formed in {r,w}_modification_order
465 bool updated = false;
466 if (curr->is_acquire()) {
467 action_list_t *list = &action_trace;
468 sllnode<ModelAction *> * rit;
469 /* Find X : is_read(X) && X --sb-> curr */
470 for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
471 ModelAction *act = rit->getVal();
474 if (act->get_tid() != curr->get_tid())
476 /* Stop at the beginning of the thread */
477 if (act->is_thread_start())
479 /* Stop once we reach a prior fence-acquire */
480 if (act->is_fence() && act->is_acquire())
484 /* read-acquire will find its own release sequences */
485 if (act->is_acquire())
488 /* Establish hypothetical release sequences */
489 ClockVector *cv = get_hb_from_write(act->get_reads_from());
490 if (cv != NULL && curr->get_cv()->merge(cv))
498 * @brief Process the current action for thread-related activity
500 * Performs current-action processing for a THREAD_* ModelAction. Proccesses
501 * may include setting Thread status, completing THREAD_FINISH/THREAD_JOIN
502 * synchronization, etc. This function is a no-op for non-THREAD actions
503 * (e.g., ATOMIC_{READ,WRITE,RMW,LOCK}, etc.)
505 * @param curr The current action
506 * @return True if synchronization was updated or a thread completed
508 void ModelExecution::process_thread_action(ModelAction *curr)
510 switch (curr->get_type()) {
511 case THREAD_CREATE: {
512 thrd_t *thrd = (thrd_t *)curr->get_location();
513 struct thread_params *params = (struct thread_params *)curr->get_value();
514 Thread *th = new Thread(get_next_id(), thrd, params->func, params->arg, get_thread(curr));
515 curr->set_thread_operand(th);
517 th->set_creation(curr);
520 case PTHREAD_CREATE: {
521 (*(uint32_t *)curr->get_location()) = pthread_counter++;
523 struct pthread_params *params = (struct pthread_params *)curr->get_value();
524 Thread *th = new Thread(get_next_id(), NULL, params->func, params->arg, get_thread(curr));
525 curr->set_thread_operand(th);
527 th->set_creation(curr);
529 if ( pthread_map.size() < pthread_counter )
530 pthread_map.resize( pthread_counter );
531 pthread_map[ pthread_counter-1 ] = th;
536 Thread *blocking = curr->get_thread_operand();
537 ModelAction *act = get_last_action(blocking->get_id());
538 synchronize(act, curr);
542 Thread *blocking = curr->get_thread_operand();
543 ModelAction *act = get_last_action(blocking->get_id());
544 synchronize(act, curr);
545 break; // WL: to be add (modified)
548 case THREADONLY_FINISH:
549 case THREAD_FINISH: {
550 Thread *th = get_thread(curr);
551 if (curr->get_type() == THREAD_FINISH &&
552 th == model->getInitThread()) {
558 /* Wake up any joining threads */
559 for (unsigned int i = 0;i < get_num_threads();i++) {
560 Thread *waiting = get_thread(int_to_id(i));
561 if (waiting->waiting_on() == th &&
562 waiting->get_pending()->is_thread_join())
563 scheduler->wake(waiting);
572 Thread *th = get_thread(curr);
573 th->set_pending(curr);
574 scheduler->add_sleep(th);
583 * Initialize the current action by performing one or more of the following
584 * actions, as appropriate: merging RMWR and RMWC/RMW actions,
585 * manipulating backtracking sets, allocating and
586 * initializing clock vectors, and computing the promises to fulfill.
588 * @param curr The current action, as passed from the user context; may be
589 * freed/invalidated after the execution of this function, with a different
590 * action "returned" its place (pass-by-reference)
591 * @return True if curr is a newly-explored action; false otherwise
593 bool ModelExecution::initialize_curr_action(ModelAction **curr)
595 if ((*curr)->is_rmwc() || (*curr)->is_rmw()) {
596 ModelAction *newcurr = process_rmw(*curr);
602 ModelAction *newcurr = *curr;
604 newcurr->set_seq_number(get_next_seq_num());
605 /* Always compute new clock vector */
606 newcurr->create_cv(get_parent_action(newcurr->get_tid()));
608 /* Assign most recent release fence */
609 newcurr->set_last_fence_release(get_last_fence_release(newcurr->get_tid()));
611 return true; /* This was a new ModelAction */
616 * @brief Establish reads-from relation between two actions
618 * Perform basic operations involved with establishing a concrete rf relation,
619 * including setting the ModelAction data and checking for release sequences.
621 * @param act The action that is reading (must be a read)
622 * @param rf The action from which we are reading (must be a write)
624 * @return True if this read established synchronization
627 void ModelExecution::read_from(ModelAction *act, ModelAction *rf)
630 ASSERT(rf->is_write());
632 act->set_read_from(rf);
633 if (act->is_acquire()) {
634 ClockVector *cv = get_hb_from_write(rf);
637 act->get_cv()->merge(cv);
642 * @brief Synchronizes two actions
644 * When A synchronizes with B (or A --sw-> B), B inherits A's clock vector.
645 * This function performs the synchronization as well as providing other hooks
646 * for other checks along with synchronization.
648 * @param first The left-hand side of the synchronizes-with relation
649 * @param second The right-hand side of the synchronizes-with relation
650 * @return True if the synchronization was successful (i.e., was consistent
651 * with the execution order); false otherwise
653 bool ModelExecution::synchronize(const ModelAction *first, ModelAction *second)
655 if (*second < *first) {
656 set_bad_synchronization();
659 return second->synchronize_with(first);
663 * @brief Check whether a model action is enabled.
665 * Checks whether an operation would be successful (i.e., is a lock already
666 * locked, or is the joined thread already complete).
668 * For yield-blocking, yields are never enabled.
670 * @param curr is the ModelAction to check whether it is enabled.
671 * @return a bool that indicates whether the action is enabled.
673 bool ModelExecution::check_action_enabled(ModelAction *curr) {
674 if (curr->is_lock()) {
675 cdsc::mutex *lock = curr->get_mutex();
676 struct cdsc::mutex_state *state = lock->get_state();
679 } else if (curr->is_thread_join()) {
680 Thread *blocking = curr->get_thread_operand();
681 if (!blocking->is_complete()) {
684 } else if (curr->is_sleep()) {
685 if (!fuzzer->shouldSleep(curr))
693 * This is the heart of the model checker routine. It performs model-checking
694 * actions corresponding to a given "current action." Among other processes, it
695 * calculates reads-from relationships, updates synchronization clock vectors,
696 * forms a memory_order constraints graph, and handles replay/backtrack
697 * execution when running permutations of previously-observed executions.
699 * @param curr The current action to process
700 * @return The ModelAction that is actually executed; may be different than
703 ModelAction * ModelExecution::check_current_action(ModelAction *curr)
706 bool second_part_of_rmw = curr->is_rmwc() || curr->is_rmw();
707 bool newly_explored = initialize_curr_action(&curr);
711 wake_up_sleeping_actions(curr);
713 /* Add uninitialized actions to lists */
714 if (!second_part_of_rmw)
715 add_uninit_action_to_lists(curr);
717 SnapVector<ModelAction *> * rf_set = NULL;
718 /* Build may_read_from set for newly-created actions */
719 if (newly_explored && curr->is_read())
720 rf_set = build_may_read_from(curr);
722 if (curr->is_read() && !second_part_of_rmw) {
723 process_read(curr, rf_set);
726 /* bool success = process_read(curr, rf_set);
729 return curr; // Do not add action to lists
732 ASSERT(rf_set == NULL);
734 /* Add the action to lists */
735 if (!second_part_of_rmw)
736 add_action_to_lists(curr);
738 if (curr->is_write())
739 add_write_to_lists(curr);
741 process_thread_action(curr);
743 if (curr->is_write())
746 if (curr->is_fence())
749 if (curr->is_mutex_op())
756 * This is the strongest feasibility check available.
757 * @return whether the current trace (partial or complete) must be a prefix of
760 bool ModelExecution::isfeasibleprefix() const
762 return !is_infeasible();
766 * Print disagnostic information about an infeasible execution
767 * @param prefix A string to prefix the output with; if NULL, then a default
768 * message prefix will be provided
770 void ModelExecution::print_infeasibility(const char *prefix) const
774 if (priv->bad_synchronization)
775 ptr += sprintf(ptr, "[bad sw ordering]");
777 model_print("%s: %s", prefix ? prefix : "Infeasible", buf);
781 * Check if the current partial trace is infeasible. Does not check any
782 * end-of-execution flags, which might rule out the execution. Thus, this is
783 * useful only for ruling an execution as infeasible.
784 * @return whether the current partial trace is infeasible.
786 bool ModelExecution::is_infeasible() const
788 return priv->bad_synchronization;
791 /** Close out a RMWR by converting previous RMWR into a RMW or READ. */
792 ModelAction * ModelExecution::process_rmw(ModelAction *act) {
793 ModelAction *lastread = get_last_action(act->get_tid());
794 lastread->process_rmw(act);
796 mo_graph->addRMWEdge(lastread->get_reads_from(), lastread);
802 * @brief Updates the mo_graph with the constraints imposed from the current
805 * Basic idea is the following: Go through each other thread and find
806 * the last action that happened before our read. Two cases:
808 * -# The action is a write: that write must either occur before
809 * the write we read from or be the write we read from.
810 * -# The action is a read: the write that that action read from
811 * must occur before the write we read from or be the same write.
813 * @param curr The current action. Must be a read.
814 * @param rf The ModelAction or Promise that curr reads from. Must be a write.
815 * @return True if modification order edges were added; false otherwise
818 bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf, SnapVector<const ModelAction *> * priorset, bool * canprune)
820 SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
822 ASSERT(curr->is_read());
824 /* Last SC fence in the current thread */
825 ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
827 int tid = curr->get_tid();
828 ModelAction *prev_same_thread = NULL;
829 /* Iterate over all threads */
830 for (i = 0;i < thrd_lists->size();i++, tid = (((unsigned int)(tid+1)) == thrd_lists->size()) ? 0 : tid + 1) {
831 /* Last SC fence in thread tid */
832 ModelAction *last_sc_fence_thread_local = NULL;
834 last_sc_fence_thread_local = get_last_seq_cst_fence(int_to_id(tid), NULL);
836 /* Last SC fence in thread tid, before last SC fence in current thread */
837 ModelAction *last_sc_fence_thread_before = NULL;
838 if (last_sc_fence_local)
839 last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(tid), last_sc_fence_local);
841 //Only need to iterate if either hb has changed for thread in question or SC fence after last operation...
842 if (prev_same_thread != NULL &&
843 (prev_same_thread->get_cv()->getClock(tid) == curr->get_cv()->getClock(tid)) &&
844 (last_sc_fence_thread_local == NULL || *last_sc_fence_thread_local < *prev_same_thread)) {
848 /* Iterate over actions in thread, starting from most recent */
849 action_list_t *list = &(*thrd_lists)[tid];
850 sllnode<ModelAction *> * rit;
851 for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
852 ModelAction *act = rit->getVal();
857 /* Don't want to add reflexive edges on 'rf' */
858 if (act->equals(rf)) {
859 if (act->happens_before(curr))
865 if (act->is_write()) {
866 /* C++, Section 29.3 statement 5 */
867 if (curr->is_seqcst() && last_sc_fence_thread_local &&
868 *act < *last_sc_fence_thread_local) {
869 if (mo_graph->checkReachable(rf, act))
871 priorset->push_back(act);
874 /* C++, Section 29.3 statement 4 */
875 else if (act->is_seqcst() && last_sc_fence_local &&
876 *act < *last_sc_fence_local) {
877 if (mo_graph->checkReachable(rf, act))
879 priorset->push_back(act);
882 /* C++, Section 29.3 statement 6 */
883 else if (last_sc_fence_thread_before &&
884 *act < *last_sc_fence_thread_before) {
885 if (mo_graph->checkReachable(rf, act))
887 priorset->push_back(act);
893 * Include at most one act per-thread that "happens
896 if (act->happens_before(curr)) {
898 if (last_sc_fence_local == NULL ||
899 (*last_sc_fence_local < *act)) {
900 prev_same_thread = act;
903 if (act->is_write()) {
904 if (mo_graph->checkReachable(rf, act))
906 priorset->push_back(act);
908 const ModelAction *prevrf = act->get_reads_from();
909 if (!prevrf->equals(rf)) {
910 if (mo_graph->checkReachable(rf, prevrf))
912 priorset->push_back(prevrf);
914 if (act->get_tid() == curr->get_tid()) {
915 //Can prune curr from obj list
928 * Updates the mo_graph with the constraints imposed from the current write.
930 * Basic idea is the following: Go through each other thread and find
931 * the lastest action that happened before our write. Two cases:
933 * (1) The action is a write => that write must occur before
936 * (2) The action is a read => the write that that action read from
937 * must occur before the current write.
939 * This method also handles two other issues:
941 * (I) Sequential Consistency: Making sure that if the current write is
942 * seq_cst, that it occurs after the previous seq_cst write.
944 * (II) Sending the write back to non-synchronizing reads.
946 * @param curr The current action. Must be a write.
947 * @param send_fv A vector for stashing reads to which we may pass our future
948 * value. If NULL, then don't record any future values.
949 * @return True if modification order edges were added; false otherwise
951 void ModelExecution::w_modification_order(ModelAction *curr)
953 SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
955 ASSERT(curr->is_write());
957 SnapList<ModelAction *> edgeset;
959 if (curr->is_seqcst()) {
960 /* We have to at least see the last sequentially consistent write,
961 so we are initialized. */
962 ModelAction *last_seq_cst = get_last_seq_cst_write(curr);
963 if (last_seq_cst != NULL) {
964 edgeset.push_back(last_seq_cst);
966 //update map for next query
967 obj_last_sc_map.put(curr->get_location(), curr);
970 /* Last SC fence in the current thread */
971 ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL);
973 /* Iterate over all threads */
974 for (i = 0;i < thrd_lists->size();i++) {
975 /* Last SC fence in thread i, before last SC fence in current thread */
976 ModelAction *last_sc_fence_thread_before = NULL;
977 if (last_sc_fence_local && int_to_id((int)i) != curr->get_tid())
978 last_sc_fence_thread_before = get_last_seq_cst_fence(int_to_id(i), last_sc_fence_local);
980 /* Iterate over actions in thread, starting from most recent */
981 action_list_t *list = &(*thrd_lists)[i];
982 sllnode<ModelAction*>* rit;
983 for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
984 ModelAction *act = rit->getVal();
987 * 1) If RMW and it actually read from something, then we
988 * already have all relevant edges, so just skip to next
991 * 2) If RMW and it didn't read from anything, we should
992 * whatever edge we can get to speed up convergence.
994 * 3) If normal write, we need to look at earlier actions, so
995 * continue processing list.
997 if (curr->is_rmw()) {
998 if (curr->get_reads_from() != NULL)
1006 /* C++, Section 29.3 statement 7 */
1007 if (last_sc_fence_thread_before && act->is_write() &&
1008 *act < *last_sc_fence_thread_before) {
1009 edgeset.push_back(act);
1014 * Include at most one act per-thread that "happens
1017 if (act->happens_before(curr)) {
1019 * Note: if act is RMW, just add edge:
1021 * The following edge should be handled elsewhere:
1022 * readfrom(act) --mo--> act
1024 if (act->is_write())
1025 edgeset.push_back(act);
1026 else if (act->is_read()) {
1027 //if previous read accessed a null, just keep going
1028 edgeset.push_back(act->get_reads_from());
1034 mo_graph->addEdges(&edgeset, curr);
1039 * Arbitrary reads from the future are not allowed. Section 29.3 part 9 places
1040 * some constraints. This method checks one the following constraint (others
1041 * require compiler support):
1043 * If X --hb-> Y --mo-> Z, then X should not read from Z.
1044 * If X --hb-> Y, A --rf-> Y, and A --mo-> Z, then X should not read from Z.
1046 bool ModelExecution::mo_may_allow(const ModelAction *writer, const ModelAction *reader)
1048 SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(reader->get_location());
1050 /* Iterate over all threads */
1051 for (i = 0;i < thrd_lists->size();i++) {
1052 const ModelAction *write_after_read = NULL;
1054 /* Iterate over actions in thread, starting from most recent */
1055 action_list_t *list = &(*thrd_lists)[i];
1056 sllnode<ModelAction *>* rit;
1057 for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
1058 ModelAction *act = rit->getVal();
1060 /* Don't disallow due to act == reader */
1061 if (!reader->happens_before(act) || reader == act)
1063 else if (act->is_write())
1064 write_after_read = act;
1065 else if (act->is_read() && act->get_reads_from() != NULL)
1066 write_after_read = act->get_reads_from();
1069 if (write_after_read && write_after_read != writer && mo_graph->checkReachable(write_after_read, writer))
1076 * Computes the clock vector that happens before propagates from this write.
1078 * @param rf The action that might be part of a release sequence. Must be a
1080 * @return ClockVector of happens before relation.
1083 ClockVector * ModelExecution::get_hb_from_write(ModelAction *rf) const {
1084 SnapVector<ModelAction *> * processset = NULL;
1085 for ( ;rf != NULL;rf = rf->get_reads_from()) {
1086 ASSERT(rf->is_write());
1087 if (!rf->is_rmw() || (rf->is_acquire() && rf->is_release()) || rf->get_rfcv() != NULL)
1089 if (processset == NULL)
1090 processset = new SnapVector<ModelAction *>();
1091 processset->push_back(rf);
1094 int i = (processset == NULL) ? 0 : processset->size();
1096 ClockVector * vec = NULL;
1098 if (rf->get_rfcv() != NULL) {
1099 vec = rf->get_rfcv();
1100 } else if (rf->is_acquire() && rf->is_release()) {
1102 } else if (rf->is_release() && !rf->is_rmw()) {
1104 } else if (rf->is_release()) {
1105 //have rmw that is release and doesn't have a rfcv
1106 (vec = new ClockVector(vec, NULL))->merge(rf->get_cv());
1109 //operation that isn't release
1110 if (rf->get_last_fence_release()) {
1112 vec = rf->get_last_fence_release()->get_cv();
1114 (vec=new ClockVector(vec, NULL))->merge(rf->get_last_fence_release()->get_cv());
1120 rf = (*processset)[i];
1124 if (processset != NULL)
1130 * Performs various bookkeeping operations for the current ModelAction when it is
1131 * the first atomic action occurred at its memory location.
1133 * For instance, adds uninitialized action to the per-object, per-thread action vector
1134 * and to the action trace list of all thread actions.
1136 * @param act is the ModelAction to process.
1138 void ModelExecution::add_uninit_action_to_lists(ModelAction *act)
1140 int tid = id_to_int(act->get_tid());
1141 ModelAction *uninit = NULL;
1143 action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
1144 if (list->empty() && act->is_atomic_var()) {
1145 uninit = get_uninitialized_action(act);
1146 uninit_id = id_to_int(uninit->get_tid());
1147 list->push_front(uninit);
1148 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_wr_thrd_map, act->get_location());
1149 if ((int)vec->size() <= uninit_id) {
1150 int oldsize = (int) vec->size();
1151 vec->resize(uninit_id + 1);
1152 for(int i = oldsize; i < uninit_id + 1; i++) {
1153 new (&(*vec)[i]) action_list_t();
1156 (*vec)[uninit_id].push_front(uninit);
1159 // Update action trace, a total order of all actions
1161 action_trace.push_front(uninit);
1163 // Update obj_thrd_map, a per location, per thread, order of actions
1164 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
1165 if ((int)vec->size() <= tid) {
1166 uint oldsize = vec->size();
1167 vec->resize(priv->next_thread_id);
1168 for(uint i = oldsize; i < priv->next_thread_id; i++)
1169 new (&(*vec)[i]) action_list_t();
1172 (*vec)[uninit_id].push_front(uninit);
1174 // Update thrd_last_action, the last action taken by each thrad
1175 if ((int)thrd_last_action.size() <= tid)
1176 thrd_last_action.resize(get_num_threads());
1178 thrd_last_action[uninit_id] = uninit;
1183 * Performs various bookkeeping operations for the current ModelAction. For
1184 * instance, adds action to the per-object, per-thread action vector and to the
1185 * action trace list of all thread actions.
1187 * @param act is the ModelAction to add.
1189 void ModelExecution::add_action_to_lists(ModelAction *act)
1191 int tid = id_to_int(act->get_tid());
1192 action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
1193 list->push_back(act);
1195 // Update action trace, a total order of all actions
1196 action_trace.push_back(act);
1198 // Update obj_thrd_map, a per location, per thread, order of actions
1199 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
1200 if ((int)vec->size() <= tid) {
1201 uint oldsize = vec->size();
1202 vec->resize(priv->next_thread_id);
1203 for(uint i = oldsize; i < priv->next_thread_id; i++)
1204 new (&(*vec)[i]) action_list_t();
1206 (*vec)[tid].push_back(act);
1208 // Update thrd_last_action, the last action taken by each thrad
1209 if ((int)thrd_last_action.size() <= tid)
1210 thrd_last_action.resize(get_num_threads());
1211 thrd_last_action[tid] = act;
1213 // Update thrd_last_fence_release, the last release fence taken by each thread
1214 if (act->is_fence() && act->is_release()) {
1215 if ((int)thrd_last_fence_release.size() <= tid)
1216 thrd_last_fence_release.resize(get_num_threads());
1217 thrd_last_fence_release[tid] = act;
1220 if (act->is_wait()) {
1221 void *mutex_loc = (void *) act->get_value();
1222 get_safe_ptr_action(&obj_map, mutex_loc)->push_back(act);
1224 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, mutex_loc);
1225 if ((int)vec->size() <= tid) {
1226 uint oldsize = vec->size();
1227 vec->resize(priv->next_thread_id);
1228 for(uint i = oldsize; i < priv->next_thread_id; i++)
1229 new (&(*vec)[i]) action_list_t();
1231 (*vec)[tid].push_back(act);
1235 void insertIntoActionList(action_list_t *list, ModelAction *act) {
1236 sllnode<ModelAction*> * rit = list->end();
1237 modelclock_t next_seq = act->get_seq_number();
1238 if (rit == NULL || (rit->getVal()->get_seq_number() == next_seq))
1239 list->push_back(act);
1241 for(;rit != NULL;rit=rit->getPrev()) {
1242 if (rit->getVal()->get_seq_number() == next_seq) {
1243 list->insertAfter(rit, act);
1250 void insertIntoActionListAndSetCV(action_list_t *list, ModelAction *act) {
1251 sllnode<ModelAction*> * rit = list->end();
1252 modelclock_t next_seq = act->get_seq_number();
1254 act->create_cv(NULL);
1255 } else if (rit->getVal()->get_seq_number() == next_seq) {
1256 act->create_cv(rit->getVal());
1257 list->push_back(act);
1259 for(;rit != NULL;rit=rit->getPrev()) {
1260 if (rit->getVal()->get_seq_number() == next_seq) {
1261 act->create_cv(rit->getVal());
1262 list->insertAfter(rit, act);
1270 * Performs various bookkeeping operations for a normal write. The
1271 * complication is that we are typically inserting a normal write
1272 * lazily, so we need to insert it into the middle of lists.
1274 * @param act is the ModelAction to add.
1277 void ModelExecution::add_normal_write_to_lists(ModelAction *act)
1279 int tid = id_to_int(act->get_tid());
1280 insertIntoActionListAndSetCV(&action_trace, act);
1282 action_list_t *list = get_safe_ptr_action(&obj_map, act->get_location());
1283 insertIntoActionList(list, act);
1285 // Update obj_thrd_map, a per location, per thread, order of actions
1286 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_thrd_map, act->get_location());
1287 if (tid >= (int)vec->size()) {
1288 uint oldsize =vec->size();
1289 vec->resize(priv->next_thread_id);
1290 for(uint i=oldsize;i<priv->next_thread_id;i++)
1291 new (&(*vec)[i]) action_list_t();
1293 insertIntoActionList(&(*vec)[tid],act);
1295 // Update thrd_last_action, the last action taken by each thrad
1296 if (thrd_last_action[tid]->get_seq_number() == act->get_seq_number())
1297 thrd_last_action[tid] = act;
1301 void ModelExecution::add_write_to_lists(ModelAction *write) {
1302 SnapVector<action_list_t> *vec = get_safe_ptr_vect_action(&obj_wr_thrd_map, write->get_location());
1303 int tid = id_to_int(write->get_tid());
1304 if (tid >= (int)vec->size()) {
1305 uint oldsize =vec->size();
1306 vec->resize(priv->next_thread_id);
1307 for(uint i=oldsize;i<priv->next_thread_id;i++)
1308 new (&(*vec)[i]) action_list_t();
1310 (*vec)[tid].push_back(write);
1314 * @brief Get the last action performed by a particular Thread
1315 * @param tid The thread ID of the Thread in question
1316 * @return The last action in the thread
1318 ModelAction * ModelExecution::get_last_action(thread_id_t tid) const
1320 int threadid = id_to_int(tid);
1321 if (threadid < (int)thrd_last_action.size())
1322 return thrd_last_action[id_to_int(tid)];
1328 * @brief Get the last fence release performed by a particular Thread
1329 * @param tid The thread ID of the Thread in question
1330 * @return The last fence release in the thread, if one exists; NULL otherwise
1332 ModelAction * ModelExecution::get_last_fence_release(thread_id_t tid) const
1334 int threadid = id_to_int(tid);
1335 if (threadid < (int)thrd_last_fence_release.size())
1336 return thrd_last_fence_release[id_to_int(tid)];
1342 * Gets the last memory_order_seq_cst write (in the total global sequence)
1343 * performed on a particular object (i.e., memory location), not including the
1345 * @param curr The current ModelAction; also denotes the object location to
1347 * @return The last seq_cst write
1349 ModelAction * ModelExecution::get_last_seq_cst_write(ModelAction *curr) const
1351 void *location = curr->get_location();
1352 return obj_last_sc_map.get(location);
1356 * Gets the last memory_order_seq_cst fence (in the total global sequence)
1357 * performed in a particular thread, prior to a particular fence.
1358 * @param tid The ID of the thread to check
1359 * @param before_fence The fence from which to begin the search; if NULL, then
1360 * search for the most recent fence in the thread.
1361 * @return The last prior seq_cst fence in the thread, if exists; otherwise, NULL
1363 ModelAction * ModelExecution::get_last_seq_cst_fence(thread_id_t tid, const ModelAction *before_fence) const
1365 /* All fences should have location FENCE_LOCATION */
1366 action_list_t *list = obj_map.get(FENCE_LOCATION);
1371 sllnode<ModelAction*>* rit = list->end();
1374 for (;rit != NULL;rit=rit->getPrev())
1375 if (rit->getVal() == before_fence)
1378 ASSERT(rit->getVal() == before_fence);
1382 for (;rit != NULL;rit=rit->getPrev()) {
1383 ModelAction *act = rit->getVal();
1384 if (act->is_fence() && (tid == act->get_tid()) && act->is_seqcst())
1391 * Gets the last unlock operation performed on a particular mutex (i.e., memory
1392 * location). This function identifies the mutex according to the current
1393 * action, which is presumed to perform on the same mutex.
1394 * @param curr The current ModelAction; also denotes the object location to
1396 * @return The last unlock operation
1398 ModelAction * ModelExecution::get_last_unlock(ModelAction *curr) const
1400 void *location = curr->get_location();
1402 action_list_t *list = obj_map.get(location);
1403 /* Find: max({i in dom(S) | isUnlock(t_i) && samevar(t_i, t)}) */
1404 sllnode<ModelAction*>* rit;
1405 for (rit = list->end();rit != NULL;rit=rit->getPrev())
1406 if (rit->getVal()->is_unlock() || rit->getVal()->is_wait())
1407 return rit->getVal();
1411 ModelAction * ModelExecution::get_parent_action(thread_id_t tid) const
1413 ModelAction *parent = get_last_action(tid);
1415 parent = get_thread(tid)->get_creation();
1420 * Returns the clock vector for a given thread.
1421 * @param tid The thread whose clock vector we want
1422 * @return Desired clock vector
1424 ClockVector * ModelExecution::get_cv(thread_id_t tid) const
1426 ModelAction *firstaction=get_parent_action(tid);
1427 return firstaction != NULL ? firstaction->get_cv() : NULL;
1430 bool valequals(uint64_t val1, uint64_t val2, int size) {
1433 return ((uint8_t)val1) == ((uint8_t)val2);
1435 return ((uint16_t)val1) == ((uint16_t)val2);
1437 return ((uint32_t)val1) == ((uint32_t)val2);
1447 * Build up an initial set of all past writes that this 'read' action may read
1448 * from, as well as any previously-observed future values that must still be valid.
1450 * @param curr is the current ModelAction that we are exploring; it must be a
1453 SnapVector<ModelAction *> * ModelExecution::build_may_read_from(ModelAction *curr)
1455 SnapVector<action_list_t> *thrd_lists = obj_wr_thrd_map.get(curr->get_location());
1457 ASSERT(curr->is_read());
1459 ModelAction *last_sc_write = NULL;
1461 if (curr->is_seqcst())
1462 last_sc_write = get_last_seq_cst_write(curr);
1464 SnapVector<ModelAction *> * rf_set = new SnapVector<ModelAction *>();
1466 /* Iterate over all threads */
1467 for (i = 0;i < thrd_lists->size();i++) {
1468 /* Iterate over actions in thread, starting from most recent */
1469 action_list_t *list = &(*thrd_lists)[i];
1470 sllnode<ModelAction *> * rit;
1471 for (rit = list->end();rit != NULL;rit=rit->getPrev()) {
1472 ModelAction *act = rit->getVal();
1477 /* Don't consider more than one seq_cst write if we are a seq_cst read. */
1478 bool allow_read = true;
1480 if (curr->is_seqcst() && (act->is_seqcst() || (last_sc_write != NULL && act->happens_before(last_sc_write))) && act != last_sc_write)
1483 /* Need to check whether we will have two RMW reading from the same value */
1484 if (curr->is_rmwr()) {
1485 /* It is okay if we have a failing CAS */
1486 if (!curr->is_rmwrcas() ||
1487 valequals(curr->get_value(), act->get_value(), curr->getSize())) {
1488 //Need to make sure we aren't the second RMW
1489 CycleNode * node = mo_graph->getNode_noCreate(act);
1490 if (node != NULL && node->getRMW() != NULL) {
1491 //we are the second RMW
1498 /* Only add feasible reads */
1499 rf_set->push_back(act);
1502 /* Include at most one act per-thread that "happens before" curr */
1503 if (act->happens_before(curr))
1508 if (DBG_ENABLED()) {
1509 model_print("Reached read action:\n");
1511 model_print("End printing read_from_past\n");
1517 * @brief Get an action representing an uninitialized atomic
1519 * This function may create a new one.
1521 * @param curr The current action, which prompts the creation of an UNINIT action
1522 * @return A pointer to the UNINIT ModelAction
1524 ModelAction * ModelExecution::get_uninitialized_action(ModelAction *curr) const
1526 ModelAction *act = curr->get_uninit_action();
1528 act = new ModelAction(ATOMIC_UNINIT, std::memory_order_relaxed, curr->get_location(), params->uninitvalue, model_thread);
1529 curr->set_uninit_action(act);
1531 act->create_cv(NULL);
1535 static void print_list(action_list_t *list)
1537 sllnode<ModelAction*> *it;
1539 model_print("------------------------------------------------------------------------------------\n");
1540 model_print("# t Action type MO Location Value Rf CV\n");
1541 model_print("------------------------------------------------------------------------------------\n");
1543 unsigned int hash = 0;
1545 for (it = list->begin();it != NULL;it=it->getNext()) {
1546 const ModelAction *act = it->getVal();
1547 if (act->get_seq_number() > 0)
1549 hash = hash^(hash<<3)^(it->getVal()->hash());
1551 model_print("HASH %u\n", hash);
1552 model_print("------------------------------------------------------------------------------------\n");
1555 #if SUPPORT_MOD_ORDER_DUMP
1556 void ModelExecution::dumpGraph(char *filename)
1559 sprintf(buffer, "%s.dot", filename);
1560 FILE *file = fopen(buffer, "w");
1561 fprintf(file, "digraph %s {\n", filename);
1562 mo_graph->dumpNodes(file);
1563 ModelAction **thread_array = (ModelAction **)model_calloc(1, sizeof(ModelAction *) * get_num_threads());
1565 for (sllnode<ModelAction*>* it = action_trace.begin();it != NULL;it=it->getNext()) {
1566 ModelAction *act = it->getVal();
1567 if (act->is_read()) {
1568 mo_graph->dot_print_node(file, act);
1569 mo_graph->dot_print_edge(file,
1570 act->get_reads_from(),
1572 "label=\"rf\", color=red, weight=2");
1574 if (thread_array[act->get_tid()]) {
1575 mo_graph->dot_print_edge(file,
1576 thread_array[id_to_int(act->get_tid())],
1578 "label=\"sb\", color=blue, weight=400");
1581 thread_array[act->get_tid()] = act;
1583 fprintf(file, "}\n");
1584 model_free(thread_array);
1589 /** @brief Prints an execution trace summary. */
1590 void ModelExecution::print_summary()
1592 #if SUPPORT_MOD_ORDER_DUMP
1593 char buffername[100];
1594 sprintf(buffername, "exec%04u", get_execution_number());
1595 mo_graph->dumpGraphToFile(buffername);
1596 sprintf(buffername, "graph%04u", get_execution_number());
1597 dumpGraph(buffername);
1600 model_print("Execution trace %d:", get_execution_number());
1601 if (isfeasibleprefix()) {
1602 if (scheduler->all_threads_sleeping())
1603 model_print(" SLEEP-SET REDUNDANT");
1604 if (have_bug_reports())
1605 model_print(" DETECTED BUG(S)");
1607 print_infeasibility(" INFEASIBLE");
1610 print_list(&action_trace);
1616 * Add a Thread to the system for the first time. Should only be called once
1618 * @param t The Thread to add
1620 void ModelExecution::add_thread(Thread *t)
1622 unsigned int i = id_to_int(t->get_id());
1623 if (i >= thread_map.size())
1624 thread_map.resize(i + 1);
1626 if (!t->is_model_thread())
1627 scheduler->add_thread(t);
1631 * @brief Get a Thread reference by its ID
1632 * @param tid The Thread's ID
1633 * @return A Thread reference
1635 Thread * ModelExecution::get_thread(thread_id_t tid) const
1637 unsigned int i = id_to_int(tid);
1638 if (i < thread_map.size())
1639 return thread_map[i];
1644 * @brief Get a reference to the Thread in which a ModelAction was executed
1645 * @param act The ModelAction
1646 * @return A Thread reference
1648 Thread * ModelExecution::get_thread(const ModelAction *act) const
1650 return get_thread(act->get_tid());
1654 * @brief Get a Thread reference by its pthread ID
1655 * @param index The pthread's ID
1656 * @return A Thread reference
1658 Thread * ModelExecution::get_pthread(pthread_t pid) {
1664 uint32_t thread_id = x.v;
1665 if (thread_id < pthread_counter + 1) return pthread_map[thread_id];
1670 * @brief Check if a Thread is currently enabled
1671 * @param t The Thread to check
1672 * @return True if the Thread is currently enabled
1674 bool ModelExecution::is_enabled(Thread *t) const
1676 return scheduler->is_enabled(t);
1680 * @brief Check if a Thread is currently enabled
1681 * @param tid The ID of the Thread to check
1682 * @return True if the Thread is currently enabled
1684 bool ModelExecution::is_enabled(thread_id_t tid) const
1686 return scheduler->is_enabled(tid);
1690 * @brief Select the next thread to execute based on the curren action
1692 * RMW actions occur in two parts, and we cannot split them. And THREAD_CREATE
1693 * actions should be followed by the execution of their child thread. In either
1694 * case, the current action should determine the next thread schedule.
1696 * @param curr The current action
1697 * @return The next thread to run, if the current action will determine this
1698 * selection; otherwise NULL
1700 Thread * ModelExecution::action_select_next_thread(const ModelAction *curr) const
1702 /* Do not split atomic RMW */
1703 if (curr->is_rmwr() && !paused_by_fuzzer(curr))
1704 return get_thread(curr);
1705 /* Follow CREATE with the created thread */
1706 /* which is not needed, because model.cc takes care of this */
1707 if (curr->get_type() == THREAD_CREATE)
1708 return curr->get_thread_operand();
1709 if (curr->get_type() == PTHREAD_CREATE) {
1710 return curr->get_thread_operand();
1715 /** @param act A read atomic action */
1716 bool ModelExecution::paused_by_fuzzer(const ModelAction * act) const
1718 ASSERT(act->is_read());
1720 // Actions paused by fuzzer have their sequence number reset to 0
1721 return act->get_seq_number() == 0;
1725 * Takes the next step in the execution, if possible.
1726 * @param curr The current step to take
1727 * @return Returns the next Thread to run, if any; NULL if this execution
1730 Thread * ModelExecution::take_step(ModelAction *curr)
1732 Thread *curr_thrd = get_thread(curr);
1733 ASSERT(curr_thrd->get_state() == THREAD_READY);
1735 ASSERT(check_action_enabled(curr)); /* May have side effects? */
1736 curr = check_current_action(curr);
1739 /* Process this action in ModelHistory for records */
1740 model->get_history()->process_action( curr, curr->get_tid() );
1742 if (curr_thrd->is_blocked() || curr_thrd->is_complete())
1743 scheduler->remove_thread(curr_thrd);
1745 return action_select_next_thread(curr);
1748 Fuzzer * ModelExecution::getFuzzer() {