mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 11:27:29 +00:00
nova: replacement of generic Genode spinlock
Turn Genode user-level spinlock into a user-level "helpinglock". This requires support by the kernel introduced with kernel branch r5. The commit avoids live-locks when multiple threads with SCs on different priority levels compete for the same user-level Genode "spinlock". Issue #986
This commit is contained in:
parent
bfa3053e62
commit
9ae441e469
@ -25,6 +25,7 @@ SRC_CC += thread/context_allocator.cc env/utcb.cc
|
||||
SRC_CC += lock/cmpxchg.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||
INC_DIR += $(REP_DIR)/include/codezero/dummies
|
||||
|
||||
|
@ -41,9 +41,6 @@ Genode::Thread_base * __attribute__((weak)) Genode::Thread_base::myself()
|
||||
}
|
||||
|
||||
|
||||
static inline void thread_yield() { Nova::ec_ctrl(Nova::EC_YIELD); }
|
||||
|
||||
|
||||
static inline bool thread_check_stopped_and_restart(Genode::Thread_base *thread_base)
|
||||
{
|
||||
Genode::addr_t sem = thread_base ?
|
||||
|
103
base-nova/src/base/lock/spin_lock.h
Normal file
103
base-nova/src/base/lock/spin_lock.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* \brief Nova specific user land "Spin lock" implementation
|
||||
* \author Alexander Boettcher
|
||||
* \date 2014-02-07
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014-2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__LOCK__SPIN_H_
|
||||
#define _INCLUDE__BASE__LOCK__SPIN_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <cpu/atomic.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
/* local includes */
|
||||
#include <lock_helper.h>
|
||||
|
||||
|
||||
enum State {
|
||||
SPINLOCK_LOCKED = 0, SPINLOCK_UNLOCKED = 1, SPINLOCK_CONTENDED = 2,
|
||||
};
|
||||
|
||||
enum { RESERVED_BITS = 12, COUNTER_MASK = 0xFFC };
|
||||
|
||||
template <typename T>
|
||||
static inline void spinlock_lock(volatile T *lock_variable)
|
||||
{
|
||||
using Genode::cmpxchg;
|
||||
|
||||
Genode::Thread_base * myself = Genode::Thread_base::myself();
|
||||
T const tid = myself ? myself->tid().ec_sel : Nova::PT_SEL_MAIN_EC;
|
||||
|
||||
unsigned help_counter = 0;
|
||||
|
||||
/* sanity check that ec_sel fits into the lock_variable */
|
||||
if (tid >= (1 << (sizeof(*lock_variable) * 8 - RESERVED_BITS)))
|
||||
nova_die();
|
||||
|
||||
if (myself) {
|
||||
Nova::Utcb * utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb());
|
||||
help_counter = utcb->tls & COUNTER_MASK;
|
||||
}
|
||||
|
||||
/* try to get lock */
|
||||
do {
|
||||
T raw = *lock_variable;
|
||||
|
||||
if (raw != SPINLOCK_UNLOCKED) {
|
||||
if (!(raw & SPINLOCK_CONTENDED))
|
||||
/* if it fails - just re-read and retry */
|
||||
if (!Genode::cmpxchg(lock_variable, raw, raw | SPINLOCK_CONTENDED))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Donate remaining time slice to help the spinlock holder to
|
||||
* pass the critical section.
|
||||
*/
|
||||
unsigned long const ec = raw >> RESERVED_BITS;
|
||||
unsigned long const tls = raw & COUNTER_MASK;
|
||||
Nova::ec_ctrl(Nova::EC_DONATE_SC, ec, tls);
|
||||
continue;
|
||||
}
|
||||
} while (!cmpxchg(lock_variable, (T)SPINLOCK_UNLOCKED,
|
||||
(tid << RESERVED_BITS) | help_counter | SPINLOCK_LOCKED));
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
static inline void spinlock_unlock(volatile T *lock_variable)
|
||||
{
|
||||
using Nova::Utcb;
|
||||
|
||||
Genode::Thread_base * myself = Genode::Thread_base::myself();
|
||||
Utcb * utcb = myself ? reinterpret_cast<Utcb *>(myself->utcb()) : 0;
|
||||
|
||||
/* unlock */
|
||||
T old;
|
||||
do {
|
||||
old = *lock_variable;
|
||||
} while (!Genode::cmpxchg(lock_variable, old, (T)SPINLOCK_UNLOCKED));
|
||||
|
||||
/* de-flag time donation help request and set new counter */
|
||||
if (utcb) {
|
||||
utcb->tls = (((utcb->tls & COUNTER_MASK) + 4) % 4096) & COUNTER_MASK;
|
||||
/* take care that compiler generates code that writes tls to memory */
|
||||
asm volatile ("":::"memory");
|
||||
}
|
||||
|
||||
/*
|
||||
* If anybody donated time, request kernel for a re-schedule in order that
|
||||
* the helper can get its time donation (SC) back.
|
||||
*/
|
||||
if (old & SPINLOCK_CONTENDED)
|
||||
Nova::ec_ctrl(Nova::EC_RESCHEDULE);
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__BASE__LOCK__SPIN_H_ */
|
@ -24,6 +24,7 @@ SRC_CC += thread/thread.cc thread/thread_bootstrap.cc thread/trace.cc
|
||||
SRC_CC += thread/context_allocator.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||
|
||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||
|
@ -24,6 +24,7 @@ SRC_CC += thread/thread.cc thread/trace.cc thread/thread_bootstrap.cc
|
||||
SRC_CC += thread/context_allocator.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/lock
|
||||
INC_DIR += $(BASE_DIR)/src/base/thread
|
||||
|
||||
vpath cap_copy.cc $(BASE_DIR)/src/platform
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <base/cancelable_lock.h>
|
||||
|
||||
/* local includes */
|
||||
#include "spin_lock.h"
|
||||
#include <spin_lock.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user