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 <util/avl_tree.h>
#include <base/native_types.h> #include <base/native_types.h>
#include <base/printf.h> #include <base/printf.h>
#include <base/lock_guard.h>
#include <cpu/atomic.h> #include <cpu/atomic.h>
/* Fiasco.OC includes */ /* Fiasco.OC includes */
@ -80,42 +81,41 @@ namespace Genode
Capability_allocator* cap_alloc(); 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> template <unsigned SZ>
class Capability_allocator_tpl : public Capability_allocator class Capability_allocator_tpl : public Capability_allocator
{ {
private: 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, * Node in the capability cache,
* associates global cap ids with kernel-capabilities. * associates global cap ids with kernel-capabilities.
@ -156,7 +156,7 @@ namespace Genode
addr_t _cap_idx; /* start cap-selector */ addr_t _cap_idx; /* start cap-selector */
Cap_node _data[SZ]; /* cache-nodes backing store */ Cap_node _data[SZ]; /* cache-nodes backing store */
Avl_tree<Cap_node> _tree; /* cap cache */ Avl_tree<Cap_node> _tree; /* cap cache */
Alloc_lock _lock; Spin_lock _lock;
public: public:
@ -173,10 +173,10 @@ namespace Genode
addr_t alloc(size_t num_caps) addr_t alloc(size_t num_caps)
{ {
_lock.lock(); Spin_lock::Guard guard(_lock);
int ret_base = _cap_idx; int ret_base = _cap_idx;
_cap_idx += num_caps * Fiasco::L4_CAP_SIZE; _cap_idx += num_caps * Fiasco::L4_CAP_SIZE;
_lock.unlock();
return ret_base; return ret_base;
} }
@ -208,7 +208,7 @@ namespace Genode
void free(addr_t cap, size_t num_caps) void free(addr_t cap, size_t num_caps)
{ {
_lock.lock(); Spin_lock::Guard guard(_lock);
for (unsigned i = 0; i < SZ; i++) for (unsigned i = 0; i < SZ; i++)
if (!_data[i]._kcap == cap) { if (!_data[i]._kcap == cap) {
@ -217,7 +217,6 @@ namespace Genode
_data[i]._id = 0; _data[i]._id = 0;
break; break;
} }
_lock.unlock();
} }
}; };
} }

View File

@ -1,7 +1,10 @@
SRC_CC = env.cc context_area.cc cap_sel_alloc.cc reload_parent_cap.cc SRC_CC = env.cc context_area.cc cap_sel_alloc.cc \
LIBS = ipc heap log_console lock 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 env.cc $(BASE_DIR)/src/base/env
vpath context_area.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 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. * 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 */ /* Genode includes */
#include <base/native_types.h> #include <base/native_types.h>
#include <base/thread.h> #include <base/thread.h>
@ -106,3 +109,5 @@ static inline void thread_stop_myself()
+ Fiasco_capability::THREAD_IRQ_CAP; + Fiasco_capability::THREAD_IRQ_CAP;
l4_irq_receive(irq, L4_IPC_NEVER); 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 \ context_area.cc \
cap_session_component.cc \ cap_session_component.cc \
cpu_session_extension.cc \ cpu_session_extension.cc \
pd_session_extension.cc pd_session_extension.cc \
spin_lock.cc
INC_DIR += $(REP_DIR)/src/core/include \ 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 main.cc $(GEN_CORE_DIR)
vpath multiboot_info.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 context_area.cc $(GEN_CORE_DIR)
vpath thread.cc $(REP_DIR)/src/base/thread vpath thread.cc $(REP_DIR)/src/base/thread
vpath thread_bootstrap.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 vpath %.cc $(REP_DIR)/src/core

View File

@ -13,55 +13,18 @@
/* Genode includes */ /* Genode includes */
#include <base/cancelable_lock.h> #include <base/cancelable_lock.h>
#include <base/printf.h>
#include <cpu/atomic.h>
/* local includes */ /* local includes */
#include <lock_helper.h> #include "spin_lock.h"
using namespace Genode; using namespace Genode;
/** /**
* Track interesting lock conditions, counters are only used for testing * Track interesting lock conditions, counters are only used for testing
*/ */
int debug_spinlock_contention_cnt;
int debug_lock_sleep_race_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 ** ** 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; typedef volatile int dde_kit_spin_lock;
enum { DDE_KIT_SPIN_LOCK_LOCKED, DDE_KIT_SPIN_LOCK_UNLOCKED };
/** /**
* Initialize spin lock * Initialize spin lock
* *

View File

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

View File

@ -15,21 +15,16 @@
#include <cpu/atomic.h> #include <cpu/atomic.h>
#include <base/printf.h> #include <base/printf.h>
#include <spin_lock.h>
extern "C" { extern "C" {
#include <dde_kit/spin_lock.h> #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) 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) 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);
} }