From d55f961768e13c12ab9d7b6a4f7f1490748f18c5 Mon Sep 17 00:00:00 2001 From: weiyu Date: Fri, 6 Sep 2019 11:43:03 -0700 Subject: [PATCH] Modify the implementation of wait and timed wait operation --- action.cc | 5 +++-- action.h | 1 + execution.cc | 26 +++++++++++++++++++++----- fuzzer.h | 1 + newfuzzer.cc | 8 +++++++- newfuzzer.h | 5 +++-- pthread.cc | 14 ++++++++------ 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/action.cc b/action.cc index f6d536ee..92bb30eb 100644 --- a/action.cc +++ b/action.cc @@ -236,7 +236,7 @@ bool ModelAction::is_thread_join() const bool ModelAction::is_mutex_op() const { - return type == ATOMIC_LOCK || type == ATOMIC_TRYLOCK || type == ATOMIC_UNLOCK || type == ATOMIC_WAIT || type == ATOMIC_NOTIFY_ONE || type == ATOMIC_NOTIFY_ALL; + return type == ATOMIC_LOCK || type == ATOMIC_TRYLOCK || type == ATOMIC_UNLOCK || type == ATOMIC_WAIT || type == ATOMIC_TIMEDWAIT || type == ATOMIC_NOTIFY_ONE || type == ATOMIC_NOTIFY_ALL; } bool ModelAction::is_lock() const @@ -250,7 +250,7 @@ bool ModelAction::is_sleep() const } bool ModelAction::is_wait() const { - return type == ATOMIC_WAIT; + return type == ATOMIC_WAIT || type == ATOMIC_TIMEDWAIT; } bool ModelAction::is_notify() const { @@ -701,6 +701,7 @@ const char * ModelAction::get_type_str() const case ATOMIC_UNLOCK: return "unlock"; case ATOMIC_TRYLOCK: return "trylock"; case ATOMIC_WAIT: return "wait"; + case ATOMIC_TIMEDWAIT: return "timed wait"; case ATOMIC_NOTIFY_ONE: return "notify one"; case ATOMIC_NOTIFY_ALL: return "notify all"; case ATOMIC_ANNOTATION: return "annotation"; diff --git a/action.h b/action.h index 21d46e5b..a8233eb7 100644 --- a/action.h +++ b/action.h @@ -73,6 +73,7 @@ typedef enum action_type { ATOMIC_NOTIFY_ONE, // < A notify_one action ATOMIC_NOTIFY_ALL, // < A notify all action ATOMIC_WAIT, // < A wait action + ATOMIC_TIMEDWAIT, // < A timed wait action ATOMIC_ANNOTATION, // < An annotation action to pass information to a trace analysis NOOP // no operation, which returns control to scheduler } action_type_t; diff --git a/execution.cc b/execution.cc index c193f229..ee9358f9 100644 --- a/execution.cc +++ b/execution.cc @@ -373,7 +373,27 @@ bool ModelExecution::process_mutex(ModelAction *curr) } break; } - case ATOMIC_WAIT: + case ATOMIC_WAIT: { + /* wake up the other threads */ + for (unsigned int i = 0;i < get_num_threads();i++) { + Thread *t = get_thread(int_to_id(i)); + Thread *curr_thrd = get_thread(curr); + if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock()) + scheduler->wake(t); + } + + /* unlock the lock - after checking who was waiting on it */ + state->locked = NULL; + + if (fuzzer->shouldWait(curr)) { + /* disable this thread */ + get_safe_ptr_action(&condvar_waiters_map, curr->get_location())->push_back(curr); + scheduler->sleep(get_thread(curr)); + } + + break; + } + case ATOMIC_TIMEDWAIT: case ATOMIC_UNLOCK: { //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... @@ -387,10 +407,6 @@ bool ModelExecution::process_mutex(ModelAction *curr) /* unlock the lock - after checking who was waiting on it */ state->locked = NULL; - - if (!curr->is_wait()) - break;/* The rest is only for ATOMIC_WAIT */ - break; } case ATOMIC_NOTIFY_ALL: { diff --git a/fuzzer.h b/fuzzer.h index 29d31eda..64875f2d 100644 --- a/fuzzer.h +++ b/fuzzer.h @@ -15,6 +15,7 @@ public: Thread * selectNotify(action_list_t * waiters); bool shouldSleep(const ModelAction *sleep); bool shouldWake(const ModelAction *sleep); + virtual bool shouldWait(const ModelAction *wait) = 0; virtual void register_engine(ModelHistory * history, ModelExecution * execution) = 0; SNAPSHOTALLOC private: diff --git a/newfuzzer.cc b/newfuzzer.cc index 68efd37d..98d56f21 100644 --- a/newfuzzer.cc +++ b/newfuzzer.cc @@ -52,8 +52,9 @@ int NewFuzzer::selectWrite(ModelAction *read, SnapVector * rf_set Thread * read_thread = execution->get_thread(tid); model_print("the %d read action of thread %d is unsuccessful\n", read->get_seq_number(), read_thread->get_id()); + // reset thread pending action and revert sequence numbers read_thread->set_pending(read); - read->reset_seq_number(); // revert some operations + read->reset_seq_number(); execution->restore_last_seq_num(); conditional_sleep(read_thread); @@ -243,3 +244,8 @@ void NewFuzzer::wake_up_paused_threads(int * threadlist, int * numthreads) threadlist[*numthreads] = thread->get_id(); (*numthreads)++; } + +bool NewFuzzer::shouldWait(const ModelAction * act) +{ + return random() & 1; +} diff --git a/newfuzzer.h b/newfuzzer.h index 7de4cd76..db25cfd8 100644 --- a/newfuzzer.h +++ b/newfuzzer.h @@ -19,8 +19,9 @@ public: Thread * selectThread(int * threadlist, int numthreads); Thread * selectNotify(action_list_t * waiters); - bool shouldSleep(const ModelAction *sleep); - bool shouldWake(const ModelAction *sleep); + bool shouldSleep(const ModelAction * sleep); + bool shouldWake(const ModelAction * sleep); + bool shouldWait(const ModelAction * wait); void register_engine(ModelHistory * history, ModelExecution * execution); diff --git a/pthread.cc b/pthread.cc index 63060d89..d48d34b0 100644 --- a/pthread.cc +++ b/pthread.cc @@ -189,6 +189,8 @@ int pthread_cond_wait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex) { ModelExecution *execution = model->get_execution(); if ( !execution->getCondMap()->contains(p_cond) ) pthread_cond_init(p_cond, NULL); + if ( !execution->getMutexMap()->contains(p_mutex) ) + pthread_mutex_init(p_mutex, NULL); cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond); cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex); @@ -198,8 +200,7 @@ int pthread_cond_wait(pthread_cond_t *p_cond, pthread_mutex_t *p_mutex) { } int pthread_cond_timedwait(pthread_cond_t *p_cond, - pthread_mutex_t *p_mutex, const struct timespec *abstime) { -// implement cond_timedwait as a noop and let the scheduler decide which thread goes next + pthread_mutex_t *p_mutex, const struct timespec *abstime) { ModelExecution *execution = model->get_execution(); if ( !execution->getCondMap()->contains(p_cond) ) @@ -208,11 +209,12 @@ int pthread_cond_timedwait(pthread_cond_t *p_cond, pthread_mutex_init(p_mutex, NULL); cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond); -// cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex); + cdsc::snapmutex *m = execution->getMutexMap()->get(p_mutex); + + model->switch_to_master(new ModelAction(ATOMIC_TIMEDWAIT, std::memory_order_seq_cst, v, (uint64_t) m)); + m->lock(); - model->switch_to_master(new ModelAction(NOOP, std::memory_order_seq_cst, v)); -// v->wait(*m); -// printf("timed_wait called\n"); + // model_print("Timed_wait is called\n"); return 0; } -- 2.34.1