Newer
Older
/*
* Copyright (C) 2013 Cloudius Systems, Ltd.
*
* This work is open source software, licensed under the terms of the
* BSD license as described in the LICENSE file in the top-level directory.
*/

Christoph Hellwig
committed
#include <sched.hh>
#include <pthread.h>
#include <cassert>
#ifndef LOCKFREE_MUTEX
static_assert(sizeof(mutex) <= sizeof(pthread_mutex_t), "mutex too big");
static_assert(offsetof(mutex, _hole_for_pthread_compatiblity) == 16, "mutex hole in wrong place");
tracepoint<21001, mutex_t*, void*> trace_mutex_lock("mutex_lock", "%p at RIP=%p");
tracepoint<21002, mutex_t*, void*> trace_mutex_unlock("mutex_unlock", "%p at RIP=%p");
tracepoint<21003, mutex_t*, void*> trace_mutex_wait("mutex_lock_wait", "%p held by %p");

Christoph Hellwig
committed
struct waiter {
struct waiter* next;
sched::thread* thread;

Christoph Hellwig
committed
};

Christoph Hellwig
committed
while (__sync_lock_test_and_set(&sl->_lock, 1))
#ifndef LOCKFREE_MUTEX

Christoph Hellwig
committed
struct waiter w;
trace_mutex_lock(mutex, __builtin_return_address(0));

Christoph Hellwig
committed
w.thread = sched::thread::current();

Christoph Hellwig
committed
spin_lock(&mutex->_wait_lock);
if (!mutex->_owner || mutex->_owner == w.thread) {
spin_unlock(&mutex->_wait_lock);
return;
}

Christoph Hellwig
committed
if (!mutex->_wait_list.first) {
mutex->_wait_list.first = &w;

Christoph Hellwig
committed
mutex->_wait_list.last->next = &w;

Christoph Hellwig
committed
mutex->_wait_list.last = &w;
spin_unlock(&mutex->_wait_lock);
trace_mutex_wait(mutex, mutex->_owner);

Christoph Hellwig
committed
sched::thread::wait_until([=] {

Christoph Hellwig
committed
});
spin_lock(&mutex->_wait_lock);
mutex->_wait_list.first = w.next;
if (!w.next)
mutex->_wait_list.last = nullptr;

Christoph Hellwig
committed
spin_unlock(&mutex->_wait_lock);
}
bool ret = false;
spin_lock(&mutex->_wait_lock);
if (!mutex->_owner || mutex->_owner == sched::thread::current()) {
spin_unlock(&mutex->_wait_lock);
return ret;

Christoph Hellwig
committed
{
trace_mutex_unlock(mutex, __builtin_return_address(0));

Christoph Hellwig
committed
spin_lock(&mutex->_wait_lock);
if (mutex->_depth == 1) {
if (mutex->_wait_list.first) {
mutex->_owner = mutex->_wait_list.first->thread;
mutex->_wait_list.first->thread->wake();
} else {
mutex->_owner = nullptr;
--mutex->_depth;
}

Christoph Hellwig
committed
spin_unlock(&mutex->_wait_lock);
}
{
return (mutex->_owner == sched::thread::current());
}