Merge spin-lock implementations

Separate spin-lock implementation from lock-implementation and put it into a
non-public header, so it can be re-used by the DDE kit's and Fiasco.OC's
capability-allocator spin lock. Fixes issue #123.
This commit is contained in:
Stefan Kalkowski 2012-02-29 15:23:06 +01:00 committed by Norman Feske
parent 72183f1536
commit 319813a59b
10 changed files with 140 additions and 95 deletions

View File

@ -27,6 +27,7 @@
#include <util/avl_tree.h>
#include <base/native_types.h>
#include <base/printf.h>
#include <base/lock_guard.h>
#include <cpu/atomic.h>
/* Fiasco.OC includes */
@ -80,42 +81,41 @@ namespace Genode
Capability_allocator* cap_alloc();
/**
* Low-level spin-lock to protect the allocator
*
* We cannot use a normal Genode lock because this lock is used by code
* executed prior the initialization of Genode.
*/
class Spin_lock
{
private:
volatile int _spinlock;
public:
/**
* Constructor
*/
Spin_lock();
void lock();
void unlock();
/**
* Lock guard
*/
typedef Genode::Lock_guard<Spin_lock> Guard;
};
template <unsigned SZ>
class Capability_allocator_tpl : public Capability_allocator
{
private:
/**
* Low-level lock to protect the allocator
*
* We cannot use a normal Genode lock because this lock is used by code
* executed prior the initialization of Genode.
*/
class Alloc_lock
{
private:
int _state;
public:
enum State { LOCKED, UNLOCKED };
/**
* Constructor
*/
Alloc_lock() : _state(UNLOCKED) {}
void lock()
{
while (!Genode::cmpxchg(&_state, UNLOCKED, LOCKED))
Fiasco::l4_ipc_sleep(Fiasco::l4_ipc_timeout(0, 0, 500, 0));
}
void unlock() { _state = UNLOCKED; }
};
/**
* Node in the capability cache,
* associates global cap ids with kernel-capabilities.
@ -156,7 +156,7 @@ namespace Genode
addr_t _cap_idx; /* start cap-selector */
Cap_node _data[SZ]; /* cache-nodes backing store */
Avl_tree<Cap_node> _tree; /* cap cache */
Alloc_lock _lock;
Spin_lock _lock;
public:
@ -173,10 +173,10 @@ namespace Genode
addr_t alloc(size_t num_caps)
{
_lock.lock();
Spin_lock::Guard guard(_lock);
int ret_base = _cap_idx;
_cap_idx += num_caps * Fiasco::L4_CAP_SIZE;
_lock.unlock();
return ret_base;
}
@ -208,7 +208,7 @@ namespace Genode
void free(addr_t cap, size_t num_caps)
{
_lock.lock();
Spin_lock::Guard guard(_lock);
for (unsigned i = 0; i < SZ; i++)
if (!_data[i]._kcap == cap) {
@ -217,7 +217,6 @@ namespace Genode
_data[i]._id = 0;
break;
}
_lock.unlock();
}
};
}

View File

@ -1,7 +1,10 @@
SRC_CC = env.cc context_area.cc cap_sel_alloc.cc reload_parent_cap.cc
LIBS = ipc heap log_console lock
SRC_CC = env.cc context_area.cc cap_sel_alloc.cc \
reload_parent_cap.cc spin_lock.cc
LIBS = ipc heap log_console lock
INC_DIR += $(REP_DIR)/src/base/lock $(BASE_DIR)/src/base/lock
vpath env.cc $(BASE_DIR)/src/base/env
vpath context_area.cc $(BASE_DIR)/src/base/env
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath cap_sel_alloc.cc $(REP_DIR)/src/base/env
vpath reload_parent_cap.cc $(BASE_DIR)/src/base/env
vpath spin_lock.cc $(REP_DIR)/src/base/env

29
base-foc/src/base/env/spin_lock.cc vendored Normal file
View File

@ -0,0 +1,29 @@
/*
* \brief Spin-lock implementation for environment's capability -allocator.
* \author Stefan Kalkowski
* \date 2012-02-29
*
* This is a Fiasco.OC-specific addition to the process enviroment.
*/
/*
* Copyright (C) 2012 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.
*/
/* Genode includes */
#include <base/cap_sel_alloc.h>
/* Lock implementation local include */
#include <spin_lock.h>
Genode::Spin_lock::Spin_lock() : _spinlock(SPINLOCK_UNLOCKED) {}
void Genode::Spin_lock::lock() { spinlock_lock(&_spinlock); }
void Genode::Spin_lock::unlock() { spinlock_unlock(&_spinlock); }

View File

@ -15,6 +15,9 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__BASE__LOCK__LOCK_HELPER_H_
#define _INCLUDE__BASE__LOCK__LOCK_HELPER_H_
/* Genode includes */
#include <base/native_types.h>
#include <base/thread.h>
@ -106,3 +109,5 @@ static inline void thread_stop_myself()
+ Fiasco_capability::THREAD_IRQ_CAP;
l4_irq_receive(irq, L4_IPC_NEVER);
}
#endif /* _INCLUDE__BASE__LOCK__LOCK_HELPER_H_ */

View File

@ -32,10 +32,13 @@ SRC_CC = main.cc \
context_area.cc \
cap_session_component.cc \
cpu_session_extension.cc \
pd_session_extension.cc
pd_session_extension.cc \
spin_lock.cc
INC_DIR += $(REP_DIR)/src/core/include \
$(GEN_CORE_DIR)/include
$(GEN_CORE_DIR)/include \
$(REP_DIR)/src/base/lock \
$(BASE_DIR)/src/base/lock
vpath main.cc $(GEN_CORE_DIR)
vpath multiboot_info.cc $(GEN_CORE_DIR)
@ -52,4 +55,5 @@ vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath context_area.cc $(GEN_CORE_DIR)
vpath thread.cc $(REP_DIR)/src/base/thread
vpath thread_bootstrap.cc $(REP_DIR)/src/base/thread
vpath spin_lock.cc $(REP_DIR)/src/base/env
vpath %.cc $(REP_DIR)/src/core

View File

@ -13,55 +13,18 @@
/* Genode includes */
#include <base/cancelable_lock.h>
#include <base/printf.h>
#include <cpu/atomic.h>
/* local includes */
#include <lock_helper.h>
#include "spin_lock.h"
using namespace Genode;
/**
* Track interesting lock conditions, counters are only used for testing
*/
int debug_spinlock_contention_cnt;
int debug_lock_sleep_race_cnt;
/***************
** Utilities **
***************/
/*
* Spinlock functions used for protecting the critical sections within the
* 'lock' and 'unlock' functions. Contention in these short-running code
* portions is rare but is must be considered.
*/
enum State { SPINLOCK_LOCKED, SPINLOCK_UNLOCKED };
static inline void spinlock_lock(volatile int *lock_variable)
{
while (!cmpxchg(lock_variable, SPINLOCK_UNLOCKED, SPINLOCK_LOCKED)) {
debug_spinlock_contention_cnt++; /* only for statistics */
/*
* Yield our remaining time slice to help the spinlock holder to pass
* the critical section.
*/
thread_yield();
}
}
static inline void spinlock_unlock(volatile int *lock_variable)
{
*lock_variable = SPINLOCK_UNLOCKED;
}
/********************
** Lock applicant **
********************/

View File

@ -0,0 +1,49 @@
/*
* \brief Spin lock implementation
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2009-03-25
*/
/*
* Copyright (C) 2009-2012 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>
/* local includes */
#include <lock_helper.h>
/*
* Spinlock functions used for protecting the critical sections within the
* 'lock' and 'unlock' functions. Contention in these short-running code
* portions is rare but is must be considered.
*/
enum State { SPINLOCK_LOCKED, SPINLOCK_UNLOCKED };
static inline void spinlock_lock(volatile int *lock_variable)
{
while (!Genode::cmpxchg(lock_variable, SPINLOCK_UNLOCKED, SPINLOCK_LOCKED)) {
/*
* Yield our remaining time slice to help the spinlock holder to pass
* the critical section.
*/
thread_yield();
}
}
static inline void spinlock_unlock(volatile int *lock_variable)
{
*lock_variable = SPINLOCK_UNLOCKED;
}
#endif /* _INCLUDE__BASE__LOCK__SPIN_H_ */

View File

@ -19,9 +19,6 @@
*/
typedef volatile int dde_kit_spin_lock;
enum { DDE_KIT_SPIN_LOCK_LOCKED, DDE_KIT_SPIN_LOCK_UNLOCKED };
/**
* Initialize spin lock
*

View File

@ -1,6 +1,7 @@
SRC_C = lock.cc semaphore.cc panic.cc printf.cc interrupt.cc pgtab.cc \
memory.cc thread.cc pci_tree.cc pci.cc resources.cc timer.cc \
dde_kit.cc spin_lock.cc
LIBS = thread alarm
SRC_C = lock.cc semaphore.cc panic.cc printf.cc interrupt.cc pgtab.cc \
memory.cc thread.cc pci_tree.cc pci.cc resources.cc timer.cc \
dde_kit.cc spin_lock.cc
LIBS = thread alarm lock
REP_INC_DIR += src/base/lock
vpath % $(REP_DIR)/src/lib/dde_kit

View File

@ -15,21 +15,16 @@
#include <cpu/atomic.h>
#include <base/printf.h>
#include <spin_lock.h>
extern "C" {
#include <dde_kit/spin_lock.h>
}
static inline void spinlock_lock(volatile int *lock_variable)
{
while (!Genode::cmpxchg(lock_variable, DDE_KIT_SPIN_LOCK_UNLOCKED,
DDE_KIT_SPIN_LOCK_LOCKED));
}
extern "C" void dde_kit_spin_lock_init(dde_kit_spin_lock *spin_lock)
{
*spin_lock = DDE_KIT_SPIN_LOCK_UNLOCKED;
*spin_lock = SPINLOCK_UNLOCKED;
}
@ -52,6 +47,6 @@ extern "C" int dde_kit_spin_lock_try_lock(dde_kit_spin_lock *spin_lock)
extern "C" void dde_kit_spin_lock_unlock(dde_kit_spin_lock *spin_lock)
{
*spin_lock = DDE_KIT_SPIN_LOCK_UNLOCKED;
spinlock_unlock(spin_lock);
}