Implement timedwait
[c11tester.git] / execution.cc
index 4b8461e8f678c38302e6551f1ec56ecdc69d11ac..4953718d360499b85dfa8eed8bc6d8415bc1e33a 100644 (file)
@@ -2,6 +2,7 @@
 #include <algorithm>
 #include <new>
 #include <stdarg.h>
+#include <errno.h>
 
 #include "model.h"
 #include "execution.h"
@@ -247,10 +248,8 @@ void ModelExecution::restore_last_seq_num()
  * @param thread The thread that we might wake up
  * @return True, if we should wake up the sleeping thread; false otherwise
  */
-bool ModelExecution::should_wake_up(const Thread *thread) const
+bool ModelExecution::should_wake_up(const ModelAction * asleep) const
 {
-       const ModelAction *asleep = thread->get_pending();
-
        /* The sleep is literally sleeping */
        switch (asleep->get_type()) {
                case THREAD_SLEEP:
@@ -275,14 +274,16 @@ void ModelExecution::wake_up_sleeping_actions()
                thread_id_t tid = int_to_id(i);
                if (scheduler->is_sleep_set(tid)) {
                        Thread *thr = get_thread(tid);
-                       if (should_wake_up(thr)) {
+                       ModelAction * pending = thr->get_pending();
+                       if (should_wake_up(pending)) {
                                /* Remove this thread from sleep set */
                                scheduler->remove_sleep(thr);
-                               ModelAction * pending = thr->get_pending();
+
                                if (pending->is_sleep()) {
                                        thr->set_wakeup_state(true);
                                } else if (pending->is_wait()) {
                                        thr->set_wakeup_state(true);
+                                       /* Remove this thread from list of waiters */
                                        simple_action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, pending->get_location());
                                        for (sllnode<ModelAction *> * rit = waiters->begin();rit != NULL;rit=rit->getNext()) {
                                                if (rit->getVal()->get_tid() == tid) {
@@ -290,6 +291,10 @@ void ModelExecution::wake_up_sleeping_actions()
                                                        break;
                                                }
                                        }
+
+                                       /* Set ETIMEDOUT error */
+                                       if (pending->is_timedwait())
+                                               thr->set_return_value(ETIMEDOUT);
                                }
                        }
                }
@@ -507,24 +512,38 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                waiters->push_back(curr);
                curr_thrd->set_pending(curr);   // Forbid this thread to stash a new action
 
-               if (fuzzer->waitShouldFail(curr))
-                       scheduler->add_sleep(curr_thrd);        // Place this thread into THREAD_SLEEP_SET
+               if (fuzzer->waitShouldFail(curr))               // If wait should fail spuriously,
+                       scheduler->add_sleep(curr_thrd);        // place this thread into THREAD_SLEEP_SET
                else
                        scheduler->sleep(curr_thrd);
 
                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...
+       case ATOMIC_TIMEDWAIT: {
+               Thread *curr_thrd = get_thread(curr);
+               if (!fuzzer->randomizeWaitTime(curr)) {
+                       curr_thrd->set_return_value(ETIMEDOUT);
+                       return false;
+               }
 
+               /* wake up the other threads */
+               for (unsigned int i = 0;i < get_num_threads();i++) {
+                       Thread *t = get_thread(int_to_id(i));
+                       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;
+
+               /* disable this thread */
+               simple_action_list_t * waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
+               waiters->push_back(curr);
+               curr_thrd->set_pending(curr);   // Forbid this thread to stash a new action
+               scheduler->add_sleep(curr_thrd);
+               break;
+       }
+       case ATOMIC_UNLOCK: {
                // TODO: lock count for recursive mutexes
                /* wake up the other threads */
                Thread *curr_thrd = get_thread(curr);