score: Avoid Giant lock for CORE spinlock

Use an ISR lock to protect the spinlock state.  Remove empty attributes.

Update #2555.
This commit is contained in:
Sebastian Huber
2016-03-18 15:36:58 +01:00
parent c904df5733
commit 5a5fb3b9d6
12 changed files with 151 additions and 303 deletions
+10 -17
View File
@@ -75,26 +75,19 @@ RTEMS_INLINE_ROUTINE void _POSIX_Spinlock_Free (
_Objects_Free( &_POSIX_Spinlock_Information, &the_spinlock->Object );
}
/**
* @brief Get a spinlock control block.
*
* This function maps spinlock IDs to spinlock control blocks.
* If ID corresponds to a local spinlock, then it returns
* the_spinlock control pointer which maps to ID and location
* is set to OBJECTS_LOCAL. if the spinlock ID is global and
* resides on a remote node, then location is set to OBJECTS_REMOTE,
* and the_spinlock is undefined. Otherwise, location is set
* to OBJECTS_ERROR and the_spinlock is undefined.
*/
RTEMS_INLINE_ROUTINE POSIX_Spinlock_Control *_POSIX_Spinlock_Get (
RTEMS_INLINE_ROUTINE POSIX_Spinlock_Control *_POSIX_Spinlock_Get(
pthread_spinlock_t *spinlock,
Objects_Locations *location
ISR_lock_Context *lock_context
)
{
return (POSIX_Spinlock_Control *) _Objects_Get(
&_POSIX_Spinlock_Information,
(Objects_Id) *spinlock,
location
if ( spinlock == NULL ) {
return NULL;
}
return (POSIX_Spinlock_Control *) _Objects_Get_local(
&_POSIX_Spinlock_Information,
*spinlock,
lock_context
);
}
+22 -45
View File
@@ -18,58 +18,35 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/system.h>
#include <rtems/posix/spinlockimpl.h>
/**
* This directive allows a thread to delete a spinlock specified by
* the spinlock id. The spinlock is freed back to the inactive
* spinlock chain.
*
* @param[in] spinlock is the spinlock id
*
* @return This method returns 0 if there was not an
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
int pthread_spin_destroy(
pthread_spinlock_t *spinlock
)
{
POSIX_Spinlock_Control *the_spinlock = NULL;
Objects_Locations location;
#include <errno.h>
if ( !spinlock )
return EINVAL;
int pthread_spin_destroy( pthread_spinlock_t *spinlock )
{
POSIX_Spinlock_Control *the_spinlock;
ISR_lock_Context lock_context;
_Objects_Allocator_lock();
the_spinlock = _POSIX_Spinlock_Get( spinlock, &location );
switch ( location ) {
case OBJECTS_LOCAL:
if ( _CORE_spinlock_Is_busy( &the_spinlock->Spinlock ) ) {
_Objects_Put( &the_spinlock->Object );
return EBUSY;
}
_Objects_Close( &_POSIX_Spinlock_Information, &the_spinlock->Object );
_Objects_Put( &the_spinlock->Object );
_POSIX_Spinlock_Free( the_spinlock );
_Objects_Allocator_unlock();
return 0;
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context );
if ( the_spinlock == NULL ) {
_Objects_Allocator_unlock();
return EINVAL;
}
_Objects_Allocator_unlock();
_CORE_spinlock_Acquire_critical( &the_spinlock->Spinlock, &lock_context );
return EINVAL;
if ( _CORE_spinlock_Is_busy( &the_spinlock->Spinlock ) ) {
_CORE_spinlock_Release( &the_spinlock->Spinlock, &lock_context );
_Objects_Allocator_unlock();
return EBUSY;
}
_CORE_spinlock_Release( &the_spinlock->Spinlock, &lock_context );
_Objects_Close( &_POSIX_Spinlock_Information, &the_spinlock->Object );
_POSIX_Spinlock_Free( the_spinlock );
_Objects_Allocator_unlock();
return 0;
}
+1 -4
View File
@@ -47,7 +47,6 @@ int pthread_spin_init(
)
{
POSIX_Spinlock_Control *the_spinlock;
CORE_spinlock_Attributes attributes;
if ( !spinlock )
return EINVAL;
@@ -67,9 +66,7 @@ int pthread_spin_init(
return EAGAIN;
}
_CORE_spinlock_Initialize_attributes( &attributes );
_CORE_spinlock_Initialize( &the_spinlock->Spinlock, &attributes );
_CORE_spinlock_Initialize( &the_spinlock->Spinlock );
_Objects_Open_u32( &_POSIX_Spinlock_Information, &the_spinlock->Object, 0 );
+15 -35
View File
@@ -18,46 +18,26 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/system.h>
#include <rtems/posix/spinlockimpl.h>
/**
* This directive allows a thread to wait at a spinlock.
*
* @param[in] spinlock is spinlock id
*
* @return This method returns 0 if there was not an
* error. Otherwise, a status code is returned indicating the
* source of the error.
*/
int pthread_spin_lock(
pthread_spinlock_t *spinlock
)
#include <errno.h>
int pthread_spin_lock( pthread_spinlock_t *spinlock )
{
POSIX_Spinlock_Control *the_spinlock = NULL;
Objects_Locations location;
CORE_spinlock_Status status;
POSIX_Spinlock_Control *the_spinlock;
ISR_lock_Context lock_context;
CORE_spinlock_Status status;
if ( !spinlock )
the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context );
if ( the_spinlock == NULL ) {
return EINVAL;
the_spinlock = _POSIX_Spinlock_Get( spinlock, &location );
switch ( location ) {
case OBJECTS_LOCAL:
status = _CORE_spinlock_Wait( &the_spinlock->Spinlock, true, 0 );
_Objects_Put( &the_spinlock->Object );
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
}
return EINVAL;
status = _CORE_spinlock_Seize(
&the_spinlock->Spinlock,
true,
0,
&lock_context
);
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
}
+14 -38
View File
@@ -18,50 +18,26 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/system.h>
#include <rtems/posix/spinlockimpl.h>
/*
* pthread_spin_trylock
*
* This directive allows a thread to poll an attempt at locking a spinlock.
*
* Input parameters:
* spinlock - spinlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
#include <errno.h>
int pthread_spin_trylock(
pthread_spinlock_t *spinlock
)
int pthread_spin_trylock( pthread_spinlock_t *spinlock )
{
POSIX_Spinlock_Control *the_spinlock = NULL;
Objects_Locations location;
CORE_spinlock_Status status;
POSIX_Spinlock_Control *the_spinlock;
ISR_lock_Context lock_context;
CORE_spinlock_Status status;
if ( !spinlock )
the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context );
if ( the_spinlock == NULL ) {
return EINVAL;
the_spinlock = _POSIX_Spinlock_Get( spinlock, &location );
switch ( location ) {
case OBJECTS_LOCAL:
status = _CORE_spinlock_Wait( &the_spinlock->Spinlock, false, 0 );
_Objects_Put( &the_spinlock->Object );
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
}
return EINVAL;
status = _CORE_spinlock_Seize(
&the_spinlock->Spinlock,
false,
0,
&lock_context
);
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
}
+9 -38
View File
@@ -20,50 +20,21 @@
#include "config.h"
#endif
#include <pthread.h>
#include <errno.h>
#include <rtems/system.h>
#include <rtems/posix/spinlockimpl.h>
/*
* pthread_spin_unlock
*
* This directive allows a thread to wait at a spinlock.
*
* Input parameters:
* spinlock - spinlock id
*
* Output parameters:
* 0 - if successful
* error code - if unsuccessful
*/
#include <errno.h>
int pthread_spin_unlock(
pthread_spinlock_t *spinlock
)
int pthread_spin_unlock( pthread_spinlock_t *spinlock )
{
POSIX_Spinlock_Control *the_spinlock = NULL;
Objects_Locations location;
CORE_spinlock_Status status;
POSIX_Spinlock_Control *the_spinlock;
ISR_lock_Context lock_context;
CORE_spinlock_Status status;
if ( !spinlock )
the_spinlock = _POSIX_Spinlock_Get( spinlock, &lock_context );
if ( the_spinlock == NULL ) {
return EINVAL;
the_spinlock = _POSIX_Spinlock_Get( spinlock, &location );
switch ( location ) {
case OBJECTS_LOCAL:
status = _CORE_spinlock_Release( &the_spinlock->Spinlock );
_Objects_Put( &the_spinlock->Object );
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
#if defined(RTEMS_MULTIPROCESSING)
case OBJECTS_REMOTE:
#endif
case OBJECTS_ERROR:
break;
}
return EINVAL;
status = _CORE_spinlock_Surrender( &the_spinlock->Spinlock, &lock_context );
return _POSIX_Spinlock_Translate_core_spinlock_return_code( status );
}
+1 -1
View File
@@ -194,7 +194,7 @@ libscore_a_SOURCES += src/coresem.c
## CORE_SPINLOCK_C_FILES
if HAS_PTHREADS
libscore_a_SOURCES += src/corespinlock.c src/corespinlockrelease.c \
libscore_a_SOURCES += src/corespinlockrelease.c \
src/corespinlockwait.c
endif
+14 -16
View File
@@ -19,7 +19,8 @@
#ifndef _RTEMS_SCORE_CORESPINLOCK_H
#define _RTEMS_SCORE_CORESPINLOCK_H
#include <rtems/score/object.h>
#include <rtems/score/isrlock.h>
#include <rtems/score/thread.h>
#ifdef __cplusplus
extern "C" {
@@ -35,38 +36,35 @@ extern "C" {
*/
/**@{*/
/**
* The following defines the control block used to manage the
* attributes of each spinlock.
*/
typedef struct {
/** This element indicates XXX
*/
uint32_t XXX;
} CORE_spinlock_Attributes;
/**
* The following defines the control block used to manage each
* spinlock.
*/
typedef struct {
/** XXX may not be needed */
CORE_spinlock_Attributes Attributes;
/**
* @brief Lock to protect the other fields.
*
* This implementation is a bit stupid. However, test cases in the Linux
* Test Project do things like sleep() and printf() while owning a
* pthread_spinlock_t, e.g.
* testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_lock/1-2.c
*/
ISR_LOCK_MEMBER( Lock )
/** This field is the lock.
*/
volatile uint32_t lock;
uint32_t lock;
/** This field is a count of the current number of threads using
* this spinlock. It includes the thread holding the lock as well
* as those waiting.
*/
volatile uint32_t users;
uint32_t users;
/** This field is the Id of the thread holding the lock. It may or may
* not be the thread which acquired it.
*/
volatile Objects_Id holder;
Thread_Control *holder;
} CORE_spinlock_Control;
/**@}*/
@@ -22,6 +22,8 @@
#include <rtems/score/corespinlock.h>
#include <rtems/score/watchdog.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -78,12 +80,29 @@ typedef enum {
* This routine initializes the spinlock based on the parameters passed.
*
* @param[in] the_spinlock is the spinlock control block to initialize
* @param[in] the_spinlock_attributes define the behavior of this instance
*/
void _CORE_spinlock_Initialize(
CORE_spinlock_Control *the_spinlock,
CORE_spinlock_Attributes *the_spinlock_attributes
);
RTEMS_INLINE_ROUTINE void _CORE_spinlock_Initialize(
CORE_spinlock_Control *the_spinlock
)
{
memset( the_spinlock, 0, sizeof( *the_spinlock ) );
}
RTEMS_INLINE_ROUTINE void _CORE_spinlock_Acquire_critical(
CORE_spinlock_Control *the_spinlock,
ISR_lock_Context *lock_context
)
{
_ISR_lock_Acquire( &the_spinlock->Lock, lock_context );
}
RTEMS_INLINE_ROUTINE void _CORE_spinlock_Release(
CORE_spinlock_Control *the_spinlock,
ISR_lock_Context *lock_context
)
{
_ISR_lock_Release_and_ISR_enable( &the_spinlock->Lock, lock_context );
}
/**
* @brief Wait for spinlock.
@@ -100,10 +119,11 @@ void _CORE_spinlock_Initialize(
* @retval A status is returned which indicates the success or failure of
* this operation.
*/
CORE_spinlock_Status _CORE_spinlock_Wait(
CORE_spinlock_Control *the_spinlock,
bool wait,
Watchdog_Interval timeout
CORE_spinlock_Status _CORE_spinlock_Seize(
CORE_spinlock_Control *the_spinlock,
bool wait,
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
);
/**
@@ -114,22 +134,11 @@ CORE_spinlock_Status _CORE_spinlock_Wait(
*
* @param[in] the_spinlock is the spinlock to surrender
*/
CORE_spinlock_Status _CORE_spinlock_Release(
CORE_spinlock_Control *the_spinlock
CORE_spinlock_Status _CORE_spinlock_Surrender(
CORE_spinlock_Control *the_spinlock,
ISR_lock_Context *lock_context
);
/**
* This method is used to initialize core spinlock attributes.
*
* @param[in] the_attributes pointer to the attributes to initialize.
*/
RTEMS_INLINE_ROUTINE void _CORE_spinlock_Initialize_attributes(
CORE_spinlock_Attributes *the_attributes
)
{
the_attributes->XXX = 0;
}
/**
* This method is used to determine if the spinlock is available or not.
*
-37
View File
@@ -1,37 +0,0 @@
/**
* @file
*
* @brief Initialize a Spinlock
*
* @ingroup ScoreSpinlock
*/
/*
* COPYRIGHT (c) 1989-2006.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/system.h>
#include <rtems/score/corespinlockimpl.h>
#include <rtems/score/thread.h>
void _CORE_spinlock_Initialize(
CORE_spinlock_Control *the_spinlock,
CORE_spinlock_Attributes *the_spinlock_attributes
)
{
the_spinlock->Attributes = *the_spinlock_attributes;
the_spinlock->lock = 0;
the_spinlock->users = 0;
the_spinlock->holder = 0;
}
+8 -11
View File
@@ -20,30 +20,27 @@
#include <rtems/score/corespinlockimpl.h>
#include <rtems/score/percpu.h>
#include <rtems/score/thread.h>
#include <rtems/score/watchdog.h>
CORE_spinlock_Status _CORE_spinlock_Release(
CORE_spinlock_Control *the_spinlock
CORE_spinlock_Status _CORE_spinlock_Surrender(
CORE_spinlock_Control *the_spinlock,
ISR_lock_Context *lock_context
)
{
ISR_Level level;
_ISR_Disable( level );
_CORE_spinlock_Acquire_critical( the_spinlock, lock_context );
/*
* It must locked before it can be unlocked.
*/
if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) {
_ISR_Enable( level );
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_NOT_LOCKED;
}
/*
* It must locked by the current thread before it can be unlocked.
*/
if ( the_spinlock->holder != _Thread_Executing->Object.id ) {
_ISR_Enable( level );
if ( the_spinlock->holder != _Thread_Executing ) {
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_NOT_HOLDER;
}
@@ -54,6 +51,6 @@ CORE_spinlock_Status _CORE_spinlock_Release(
the_spinlock->lock = CORE_SPINLOCK_UNLOCKED;
the_spinlock->holder = 0;
_ISR_Enable( level );
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_SUCCESSFUL;
}
+25 -38
View File
@@ -18,48 +18,36 @@
#include "config.h"
#endif
#include <rtems/system.h>
#include <rtems/score/corespinlockimpl.h>
#include <rtems/score/thread.h>
#include <rtems/score/threaddispatch.h>
#include <rtems/score/percpu.h>
/*
* _CORE_spinlock_Wait
*
* This function waits for the spinlock to become available. Optionally,
* a limit may be placed on the duration of the spin.
*
* Input parameters:
* the_spinlock - the spinlock control block to initialize
* wait - true if willing to wait
* timeout - the maximum number of ticks to spin (0 is forever)
*
* Output parameters: NONE
*/
CORE_spinlock_Status _CORE_spinlock_Wait(
CORE_spinlock_Control *the_spinlock,
bool wait,
Watchdog_Interval timeout
CORE_spinlock_Status _CORE_spinlock_Seize(
CORE_spinlock_Control *the_spinlock,
bool wait,
Watchdog_Interval timeout,
ISR_lock_Context *lock_context
)
{
ISR_Level level;
Thread_Control *executing;
#if defined(FUNCTIONALITY_NOT_CURRENTLY_USED_BY_ANY_API)
Watchdog_Interval limit = _Watchdog_Ticks_since_boot + timeout;
#endif
_ISR_Disable( level );
if ( (the_spinlock->lock == CORE_SPINLOCK_LOCKED) &&
(the_spinlock->holder == _Thread_Executing->Object.id) ) {
_ISR_Enable( level );
executing = _Thread_Executing;
_CORE_spinlock_Acquire_critical( the_spinlock, lock_context );
if ( the_spinlock->lock == CORE_SPINLOCK_LOCKED &&
the_spinlock->holder == executing ) {
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_HOLDER_RELOCKING;
}
the_spinlock->users += 1;
for ( ;; ) {
if ( the_spinlock->lock == CORE_SPINLOCK_UNLOCKED ) {
the_spinlock->lock = CORE_SPINLOCK_LOCKED;
the_spinlock->holder = _Thread_Executing->Object.id;
_ISR_Enable( level );
the_spinlock->holder = executing;
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_SUCCESSFUL;
}
@@ -68,7 +56,7 @@ CORE_spinlock_Status _CORE_spinlock_Wait(
*/
if ( !wait ) {
the_spinlock->users -= 1;
_ISR_Enable( level );
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_UNAVAILABLE;
}
@@ -78,7 +66,7 @@ CORE_spinlock_Status _CORE_spinlock_Wait(
*/
if ( timeout && (limit <= _Watchdog_Ticks_since_boot) ) {
the_spinlock->users -= 1;
_ISR_Enable( level );
_CORE_spinlock_Release( the_spinlock, lock_context );
return CORE_SPINLOCK_TIMEOUT;
}
#endif
@@ -100,16 +88,15 @@ CORE_spinlock_Status _CORE_spinlock_Wait(
* safe from deletion.
*/
_ISR_Enable( level );
/* An ISR could occur here */
_CORE_spinlock_Release( the_spinlock, lock_context );
_Thread_Enable_dispatch();
/* Another thread could get dispatched here */
/*
* An ISR could occur here. Another thread could get dispatched here.
* Reenter the critical sections so we can attempt the lock again.
*/
/* Reenter the critical sections so we can attempt the lock again. */
_Thread_Disable_dispatch();
_ISR_Disable( level );
_ISR_lock_ISR_disable( lock_context );
_CORE_spinlock_Acquire_critical( the_spinlock, lock_context );
}
}