struct model_snapshot_members;
struct bug_message;
+typedef SnapList<ModelAction *> simple_action_list_t;
typedef actionlist action_list_t;
typedef SnapList<uint32_t> func_id_list_t;
typedef SnapList<FuncInst *> func_inst_list_t;
return tmp;
}
+static simple_action_list_t * get_safe_ptr_action(HashTable<const void *, simple_action_list_t *, uintptr_t, 2> * hash, void * ptr)
+{
+ simple_action_list_t *tmp = hash->get(ptr);
+ if (tmp == NULL) {
+ tmp = new simple_action_list_t();
+ hash->put(ptr, tmp);
+ }
+ return tmp;
+}
+
/** @return a thread ID for a new Thread */
thread_id_t ModelExecution::get_next_id()
{
//TODO: FIND SOME BETTER WAY TO CHECK LOCK INITIALIZED OR NOT
//if (curr->get_cv()->getClock(state->alloc_tid) <= state->alloc_clock)
// assert_bug("Lock access before initialization");
+
+ // TODO: lock count for recursive mutexes
state->locked = get_thread(curr);
ModelAction *unlock = get_last_unlock(curr);
//synchronize with the previous unlock statement
/* unlock the lock - after checking who was waiting on it */
state->locked = NULL;
- /* disable this thread */
- get_safe_ptr_action(&condvar_waiters_map, curr->get_location())->addAction(curr);
+ /* remove old wait action and disable this thread */
+ simple_action_list_t * waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
+ for (sllnode<ModelAction *> * it = waiters->begin(); it != NULL; it = it->getNext()) {
+ ModelAction * wait = it->getVal();
+ if (wait->get_tid() == curr->get_tid()) {
+ waiters->erase(it);
+ break;
+ }
+ }
+
+ waiters->push_back(curr);
scheduler->sleep(get_thread(curr));
}
//FAILS AND IN THE CASE IT DOESN'T... TIMED WAITS
//MUST EVENMTUALLY RELEASE...
+ // TODO: lock count for recursive mutexes
/* wake up the other threads */
for (unsigned int i = 0;i < get_num_threads();i++) {
Thread *t = get_thread(int_to_id(i));
break;
}
case ATOMIC_NOTIFY_ALL: {
- action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
+ simple_action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
//activate all the waiting threads
for (sllnode<ModelAction *> * rit = waiters->begin();rit != NULL;rit=rit->getNext()) {
scheduler->wake(get_thread(rit->getVal()));
break;
}
case ATOMIC_NOTIFY_ONE: {
- action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
+ simple_action_list_t *waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
if (waiters->size() != 0) {
Thread * thread = fuzzer->selectNotify(waiters);
scheduler->wake(thread);
if (curr->is_lock()) {
cdsc::mutex *lock = curr->get_mutex();
struct cdsc::mutex_state *state = lock->get_state();
- if (state->locked)
+ if (state->locked) {
+ Thread *lock_owner = (Thread *)state->locked;
+ Thread *curr_thread = get_thread(curr);
+ if (lock_owner == curr_thread && state->type == PTHREAD_MUTEX_RECURSIVE) {
+ return true;
+ }
+
return false;
+ }
} else if (curr->is_thread_join()) {
Thread *blocking = curr->get_thread_operand();
if (!blocking->is_complete()) {
/** Per-object list of actions. Maps an object (i.e., memory location)
* to a trace of all actions performed on the object. */
- HashTable<const void *, action_list_t *, uintptr_t, 2> condvar_waiters_map;
+ HashTable<const void *, simple_action_list_t *, uintptr_t, 2> condvar_waiters_map;
/** Per-object list of actions that each thread performed. */
HashTable<const void *, SnapVector<action_list_t> *, uintptr_t, 2> obj_thrd_map;
return model->get_thread(curr_tid);
}
-Thread * Fuzzer::selectNotify(action_list_t * waiters) {
+Thread * Fuzzer::selectNotify(simple_action_list_t * waiters) {
int numwaiters = waiters->size();
int random_index = random() % numwaiters;
sllnode<ModelAction*> * it = waiters->begin();
while(random_index--)
it=it->getNext();
Thread *thread = model->get_thread(it->getVal());
- waiters->removeAction(it->getVal());
+ waiters->erase(it);
return thread;
}
bool Fuzzer::shouldWait(const ModelAction * act)
{
- return random() & 1;
+ return true;
}
virtual bool has_paused_threads() { return false; }
virtual Thread * selectThread(int * threadlist, int numthreads);
- Thread * selectNotify(action_list_t * waiters);
+ Thread * selectNotify(simple_action_list_t * waiters);
bool shouldSleep(const ModelAction *sleep);
bool shouldWake(const ModelAction *sleep);
virtual bool shouldWait(const ModelAction *wait);
#include "modeltypes.h"
#include "mymemory.h"
+#include "mypthread.h"
namespace cdsc {
struct mutex_state {
void *locked; /* Thread holding the lock */
thread_id_t alloc_tid;
modelclock_t alloc_clock;
+ int type;
+ int lock_count;
};
class mutex {
public:
- mutex();
+ mutex(int type = PTHREAD_MUTEX_DEFAULT);
~mutex() {}
void lock();
bool try_lock();
class snapmutex : public mutex {
public:
- snapmutex() : mutex()
+ snapmutex(int type = 0) : mutex(type)
{ }
SNAPSHOTALLOC
};
#include <sched.h>
#include <pthread.h>
+/* pthread mutex types
+enum
+{
+ PTHREAD_MUTEX_NORMAL
+ PTHREAD_MUTEX_RECURSIVE
+ PTHREAD_MUTEX_ERRORCHECK
+ PTHREAD_MUTEX_DEFAULT
+};*/
+
typedef void *(*pthread_start_t)(void *);
struct pthread_params {
namespace cdsc {
-mutex::mutex()
+mutex::mutex(int type)
{
state.locked = NULL;
thread_id_t tid = thread_current()->get_id();
state.alloc_tid = tid;
ClockVector *cv = model->get_execution()->get_cv(tid);
state.alloc_clock = cv == NULL ? 0 : cv->getClock(tid);
+
+ // For recursive mutex
+ state.type = type;
+ state.lock_count = 0;
}
void mutex::lock()
void notify_paused_thread(Thread * thread);
Thread * selectThread(int * threadlist, int numthreads);
- Thread * selectNotify(action_list_t * waiters);
+ Thread * selectNotify(simple_action_list_t * waiters);
bool shouldSleep(const ModelAction * sleep);
bool shouldWake(const ModelAction * sleep);
bool shouldWait(const ModelAction * wait);
real_pthread_exit(NULL);
}
-int pthread_mutex_init(pthread_mutex_t *p_mutex, const pthread_mutexattr_t *) {
+int pthread_mutex_init(pthread_mutex_t *p_mutex, const pthread_mutexattr_t * attr) {
if (!model) {
snapshot_system_init(10000, 1024, 1024, 40000);
model = new ModelChecker();
model->startChecker();
}
- cdsc::snapmutex *m = new cdsc::snapmutex();
+
+ int mutex_type = PTHREAD_MUTEX_DEFAULT;
+ if (attr != NULL)
+ pthread_mutexattr_gettype(attr, &mutex_type);
+
+ cdsc::snapmutex *m = new cdsc::snapmutex(mutex_type);
ModelExecution *execution = model->get_execution();
execution->getMutexMap()->put(p_mutex, m);
bool Thread::is_waiting_on(const Thread *t) const
{
Thread *wait;
+
+ // One thread relocks a recursive mutex
+ if (waiting_on() == t && pending->is_lock()) {
+ int mutex_type = pending->get_mutex()->get_state()->type;
+ if (mutex_type == PTHREAD_MUTEX_RECURSIVE)
+ return false;
+ }
+
for (wait = waiting_on();wait != NULL;wait = wait->waiting_on())
if (wait == t)
return true;