blob: c76814820c374a1550c92d3ac589f5deb5407237 [file] [log] [blame]
//===--- ctlock.cc - Common threads implementation of locks ---------------===//
//
// The Micro Virtual Machine
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <cassert>
#include "mvm/Threads/Cond.h"
#include "mvm/Threads/Locks.h"
#include "mvm/Threads/Thread.h"
#include "cterror.h"
#include <cerrno>
#include <sys/time.h>
#include <pthread.h>
using namespace mvm;
Lock::Lock() {
pthread_mutexattr_t attr;
// Initialize the mutex attributes
int errorcode = pthread_mutexattr_init(&attr);
assert(errorcode == 0);
// Initialize the mutex as a recursive mutex, if requested, or normal
// otherwise.
int kind = PTHREAD_MUTEX_NORMAL;
errorcode = pthread_mutexattr_settype(&attr, kind);
assert(errorcode == 0);
#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \
!defined(__DragonFly__)
// Make it a process local mutex
errorcode = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
#endif
// Initialize the mutex
errorcode = pthread_mutex_init(&internalLock, &attr);
assert(errorcode == 0);
// Destroy the attributes
errorcode = pthread_mutexattr_destroy(&attr);
assert(errorcode == 0);
owner = 0;
}
Lock::~Lock() {
pthread_mutex_destroy((pthread_mutex_t*)&internalLock);
}
bool Lock::selfOwner() {
return owner == mvm::Thread::get();
}
mvm::Thread* Lock::getOwner() {
return owner;
}
void LockNormal::lock() {
Thread* th = Thread::get();
th->enterUncooperativeCode();
pthread_mutex_lock((pthread_mutex_t*)&internalLock);
th->leaveUncooperativeCode();
owner = th;
}
void LockNormal::unlock() {
assert(selfOwner() && "Not owner when unlocking");
owner = 0;
pthread_mutex_unlock((pthread_mutex_t*)&internalLock);
}
void LockRecursive::lock() {
if (!selfOwner()) {
Thread* th = Thread::get();
th->enterUncooperativeCode();
pthread_mutex_lock((pthread_mutex_t*)&internalLock);
th->leaveUncooperativeCode();
owner = th;
}
++n;
}
int LockRecursive::tryLock() {
int res = 0;
if (!selfOwner()) {
res = pthread_mutex_trylock((pthread_mutex_t*)&internalLock);
owner = mvm::Thread::get();
}
++n;
return res;
}
void LockRecursive::unlock() {
assert(selfOwner() && "Not owner when unlocking");
--n;
if (n == 0) {
owner = 0;
pthread_mutex_unlock((pthread_mutex_t*)&internalLock);
}
}
int LockRecursive::unlockAll() {
assert(selfOwner() && "Not owner when unlocking all");
int res = n;
n = 0;
owner = 0;
pthread_mutex_unlock((pthread_mutex_t*)&internalLock);
return res;
}
void LockRecursive::lockAll(int count) {
if (selfOwner()) {
n += count;
} else {
Thread* th = Thread::get();
th->enterUncooperativeCode();
pthread_mutex_lock((pthread_mutex_t*)&internalLock);
th->leaveUncooperativeCode();
owner = th;
n = count;
}
}
Cond::Cond() {
int errorcode = pthread_cond_init((pthread_cond_t*)&internalCond, NULL);
assert(errorcode == 0);
}
Cond::~Cond() {
pthread_cond_destroy((pthread_cond_t*)&internalCond);
}
void Cond::broadcast() {
pthread_cond_broadcast((pthread_cond_t*)&internalCond);
}
void Cond::wait(Lock* l) {
int n = l->unsafeUnlock();
Thread* th = Thread::get();
th->enterUncooperativeCode();
int res = pthread_cond_wait((pthread_cond_t*)&internalCond,
(pthread_mutex_t*)&(l->internalLock));
th->leaveUncooperativeCode();
assert(!res && "Error on wait");
l->unsafeLock(n);
}
void Cond::signal() {
pthread_cond_signal((pthread_cond_t*)&internalCond);
}
int Cond::timedWait(Lock* l, struct timeval *ref) {
struct timespec timeout;
struct timeval now;
struct timezone tz;
gettimeofday(&now, &tz);
timeout.tv_sec = now.tv_sec + ref->tv_sec;
timeout.tv_nsec = now.tv_usec + ref->tv_usec;
int n = l->unsafeUnlock();
Thread* th = Thread::get();
th->enterUncooperativeCode();
int res = pthread_cond_timedwait((pthread_cond_t*)&internalCond,
(pthread_mutex_t*)&(l->internalLock),
&timeout);
th->leaveUncooperativeCode();
assert((!res || res == ETIMEDOUT) && "Error on timed wait");
l->unsafeLock(n);
return res;
}