forked from Imagelibrary/rtems
score: Add SMP barrier
This commit is contained in:
@@ -59,6 +59,7 @@ include_rtems_score_HEADERS += include/rtems/score/schedulersimpleimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/schedulersmp.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/schedulersmpimpl.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/smp.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/smpbarrier.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/smplock.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/stack.h
|
||||
include_rtems_score_HEADERS += include/rtems/score/stackimpl.h
|
||||
@@ -276,6 +277,7 @@ libscore_a_SOURCES += src/thread.c src/threadchangepriority.c \
|
||||
src/threadblockingoperationcancel.c
|
||||
|
||||
if HAS_SMP
|
||||
libscore_a_SOURCES += src/smpbarrierwait.c
|
||||
libscore_a_SOURCES += src/threaddispatchdisablelevel.c
|
||||
endif
|
||||
|
||||
|
||||
127
cpukit/score/include/rtems/score/smpbarrier.h
Normal file
127
cpukit/score/include/rtems/score/smpbarrier.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* @ingroup ScoreSMPBarrier
|
||||
*
|
||||
* @brief SMP Barrier API
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef _RTEMS_SCORE_SMPBARRIER_H
|
||||
#define _RTEMS_SCORE_SMPBARRIER_H
|
||||
|
||||
#include <rtems/score/cpuopts.h>
|
||||
|
||||
#if defined( RTEMS_SMP )
|
||||
|
||||
#include <rtems/score/atomic.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @defgroup ScoreSMPBarrier SMP Barriers
|
||||
*
|
||||
* @ingroup Score
|
||||
*
|
||||
* @brief The SMP barrier provides barrier synchronization for SMP systems at
|
||||
* the lowest level.
|
||||
*
|
||||
* The SMP barrier is implemented as a sense barrier, see also Herlihy and
|
||||
* Shavit, "The Art of Multiprocessor Programming", 17.3 Sense-Reversing
|
||||
* Barrier.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief SMP barrier control.
|
||||
*/
|
||||
typedef struct {
|
||||
Atomic_Uint value;
|
||||
Atomic_Uint sense;
|
||||
} SMP_barrier_Control;
|
||||
|
||||
/**
|
||||
* @brief SMP barrier per-thread state.
|
||||
*
|
||||
* Each user of the barrier must provide this per-thread state.
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int sense;
|
||||
} SMP_barrier_State;
|
||||
|
||||
/**
|
||||
* @brief SMP barrier control initializer for static initialization.
|
||||
*/
|
||||
#define SMP_BARRIER_CONTROL_INITIALIZER \
|
||||
{ ATOMIC_INITIALIZER_UINT( 0U ), ATOMIC_INITIALIZER_UINT( 0U ) }
|
||||
|
||||
/**
|
||||
* @brief SMP barrier per-thread state initializer for static initialization.
|
||||
*/
|
||||
#define SMP_BARRIER_STATE_INITIALIZER { 0U }
|
||||
|
||||
/**
|
||||
* @brief Initializes a SMP barrier control.
|
||||
*
|
||||
* Concurrent initialization leads to unpredictable results.
|
||||
*
|
||||
* @param[out] control The SMP barrier control.
|
||||
*/
|
||||
static inline void _SMP_barrier_Control_initialize(
|
||||
SMP_barrier_Control *control
|
||||
)
|
||||
{
|
||||
_Atomic_Init_uint( &control->value, 0U );
|
||||
_Atomic_Init_uint( &control->sense, 0U );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a SMP barrier per-thread state.
|
||||
*
|
||||
* @param[out] state The SMP barrier control.
|
||||
*/
|
||||
static inline void _SMP_barrier_State_initialize(
|
||||
SMP_barrier_State *state
|
||||
)
|
||||
{
|
||||
state->sense = 0U;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits on the SMP barrier until count threads rendezvoused.
|
||||
*
|
||||
* @param[in, out] control The SMP barrier control.
|
||||
* @param[in, out] state The SMP barrier per-thread state.
|
||||
* @param[in] count The thread count bound to rendezvous.
|
||||
*/
|
||||
void _SMP_barrier_Wait(
|
||||
SMP_barrier_Control *control,
|
||||
SMP_barrier_State *state,
|
||||
unsigned int count
|
||||
);
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* defined( RTEMS_SMP ) */
|
||||
|
||||
#endif /* _RTEMS_SCORE_SMPBARRIER_H */
|
||||
@@ -219,6 +219,10 @@ $(PROJECT_INCLUDE)/rtems/score/smp.h: include/rtems/score/smp.h $(PROJECT_INCLUD
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smp.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smp.h
|
||||
|
||||
$(PROJECT_INCLUDE)/rtems/score/smpbarrier.h: include/rtems/score/smpbarrier.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smpbarrier.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smpbarrier.h
|
||||
|
||||
$(PROJECT_INCLUDE)/rtems/score/smplock.h: include/rtems/score/smplock.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/smplock.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/smplock.h
|
||||
|
||||
48
cpukit/score/src/smpbarrierwait.c
Normal file
48
cpukit/score/src/smpbarrierwait.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <rtems/score/smpbarrier.h>
|
||||
|
||||
void _SMP_barrier_Wait(
|
||||
SMP_barrier_Control *control,
|
||||
SMP_barrier_State *state,
|
||||
unsigned int count
|
||||
)
|
||||
{
|
||||
unsigned int sense = ~state->sense;
|
||||
unsigned int previous_value;
|
||||
|
||||
state->sense = sense;
|
||||
|
||||
previous_value = _Atomic_Fetch_add_uint(
|
||||
&control->value,
|
||||
1U,
|
||||
ATOMIC_ORDER_RELAXED
|
||||
);
|
||||
|
||||
if ( previous_value + 1U == count ) {
|
||||
_Atomic_Store_uint( &control->value, 0U, ATOMIC_ORDER_RELAXED );
|
||||
_Atomic_Store_uint( &control->sense, sense, ATOMIC_ORDER_RELEASE );
|
||||
} else {
|
||||
while (
|
||||
_Atomic_Load_uint( &control->sense, ATOMIC_ORDER_ACQUIRE ) != sense
|
||||
) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013 embedded brains GmbH. All rights reserved.
|
||||
* Copyright (c) 2013-2014 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
@@ -19,56 +19,12 @@
|
||||
#endif
|
||||
|
||||
#include <rtems/score/atomic.h>
|
||||
#include <rtems/score/smpbarrier.h>
|
||||
#include <rtems.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmacros.h"
|
||||
|
||||
/* FIXME: Add barrier to Score */
|
||||
|
||||
typedef struct {
|
||||
Atomic_Ulong value;
|
||||
Atomic_Ulong sense;
|
||||
} SMP_barrier_Control;
|
||||
|
||||
typedef struct {
|
||||
unsigned long sense;
|
||||
} SMP_barrier_State;
|
||||
|
||||
#define SMP_BARRIER_CONTROL_INITIALIZER \
|
||||
{ ATOMIC_INITIALIZER_ULONG( 0 ), ATOMIC_INITIALIZER_ULONG( 0 ) }
|
||||
|
||||
#define SMP_BARRIER_STATE_INITIALIZER { 0 }
|
||||
|
||||
static void _SMP_barrier_Wait(
|
||||
SMP_barrier_Control *control,
|
||||
SMP_barrier_State *state,
|
||||
unsigned long count
|
||||
)
|
||||
{
|
||||
unsigned long sense = ~state->sense;
|
||||
unsigned long previous_value;
|
||||
|
||||
state->sense = sense;
|
||||
|
||||
previous_value = _Atomic_Fetch_add_ulong(
|
||||
&control->value,
|
||||
1,
|
||||
ATOMIC_ORDER_RELAXED
|
||||
);
|
||||
|
||||
if ( previous_value + 1 == count ) {
|
||||
_Atomic_Store_ulong( &control->value, 0, ATOMIC_ORDER_RELAXED );
|
||||
_Atomic_Store_ulong( &control->sense, sense, ATOMIC_ORDER_RELEASE );
|
||||
} else {
|
||||
while (
|
||||
_Atomic_Load_ulong( &control->sense, ATOMIC_ORDER_ACQUIRE ) != sense
|
||||
) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MASTER_PRIORITY 1
|
||||
|
||||
#define WORKER_PRIORITY 2
|
||||
|
||||
@@ -17,50 +17,12 @@
|
||||
#endif
|
||||
|
||||
#include <rtems/score/smplock.h>
|
||||
#include <rtems/score/smpbarrier.h>
|
||||
#include <rtems/score/atomic.h>
|
||||
#include <rtems.h>
|
||||
|
||||
#include "tmacros.h"
|
||||
|
||||
/* FIXME: Add barrier to Score */
|
||||
|
||||
typedef struct {
|
||||
Atomic_Uint value;
|
||||
Atomic_Uint sense;
|
||||
} barrier_control;
|
||||
|
||||
typedef struct {
|
||||
unsigned int sense;
|
||||
} barrier_state;
|
||||
|
||||
#define BARRIER_CONTROL_INITIALIZER \
|
||||
{ ATOMIC_INITIALIZER_UINT(0), ATOMIC_INITIALIZER_UINT(0) }
|
||||
|
||||
#define BARRIER_STATE_INITIALIZER { 0 }
|
||||
|
||||
static void barrier_wait(
|
||||
barrier_control *control,
|
||||
barrier_state *state,
|
||||
unsigned int cpu_count
|
||||
)
|
||||
{
|
||||
unsigned int sense = ~state->sense;
|
||||
unsigned int value;
|
||||
|
||||
state->sense = sense;
|
||||
|
||||
value = _Atomic_Fetch_add_uint(&control->value, 1, ATOMIC_ORDER_RELAXED);
|
||||
|
||||
if (value + 1 == cpu_count) {
|
||||
_Atomic_Store_uint(&control->value, 0, ATOMIC_ORDER_RELAXED);
|
||||
_Atomic_Store_uint(&control->sense, sense, ATOMIC_ORDER_RELEASE);
|
||||
} else {
|
||||
while (_Atomic_Load_uint(&control->sense, ATOMIC_ORDER_ACQUIRE) != sense) {
|
||||
/* Wait */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define TASK_PRIORITY 1
|
||||
|
||||
#define CPU_COUNT 32
|
||||
@@ -75,7 +37,7 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
Atomic_Uint state;
|
||||
barrier_control barrier;
|
||||
SMP_barrier_Control barrier;
|
||||
rtems_id timer_id;
|
||||
rtems_interval timeout;
|
||||
unsigned long counter[TEST_COUNT];
|
||||
@@ -85,7 +47,7 @@ typedef struct {
|
||||
|
||||
static global_context context = {
|
||||
.state = ATOMIC_INITIALIZER_UINT(INITIAL),
|
||||
.barrier = BARRIER_CONTROL_INITIALIZER,
|
||||
.barrier = SMP_BARRIER_CONTROL_INITIALIZER,
|
||||
.lock = SMP_LOCK_INITIALIZER
|
||||
};
|
||||
|
||||
@@ -121,7 +83,7 @@ static bool assert_state(global_context *ctx, int desired_state)
|
||||
typedef void (*test_body)(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
);
|
||||
@@ -129,7 +91,7 @@ typedef void (*test_body)(
|
||||
static void test_0_body(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
)
|
||||
@@ -148,7 +110,7 @@ static void test_0_body(
|
||||
static void test_1_body(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
)
|
||||
@@ -168,7 +130,7 @@ static void test_1_body(
|
||||
static void test_2_body(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
)
|
||||
@@ -188,7 +150,7 @@ static void test_2_body(
|
||||
static void test_3_body(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
)
|
||||
@@ -221,7 +183,7 @@ static void busy_section(void)
|
||||
static void test_4_body(
|
||||
int test,
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self
|
||||
)
|
||||
@@ -248,7 +210,7 @@ static const test_body test_bodies[TEST_COUNT] = {
|
||||
|
||||
static void run_tests(
|
||||
global_context *ctx,
|
||||
barrier_state *bs,
|
||||
SMP_barrier_State *bs,
|
||||
unsigned int cpu_count,
|
||||
unsigned int cpu_self,
|
||||
bool master
|
||||
@@ -257,7 +219,7 @@ static void run_tests(
|
||||
int test;
|
||||
|
||||
for (test = 0; test < TEST_COUNT; ++test) {
|
||||
barrier_wait(&ctx->barrier, bs, cpu_count);
|
||||
_SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
|
||||
|
||||
if (master) {
|
||||
rtems_status_code sc = rtems_timer_fire_after(
|
||||
@@ -276,7 +238,7 @@ static void run_tests(
|
||||
(*test_bodies[test])(test, ctx, bs, cpu_count, cpu_self);
|
||||
}
|
||||
|
||||
barrier_wait(&ctx->barrier, bs, cpu_count);
|
||||
_SMP_barrier_Wait(&ctx->barrier, bs, cpu_count);
|
||||
}
|
||||
|
||||
static void task(rtems_task_argument arg)
|
||||
@@ -285,7 +247,7 @@ static void task(rtems_task_argument arg)
|
||||
uint32_t cpu_count = rtems_smp_get_processor_count();
|
||||
uint32_t cpu_self = rtems_smp_get_current_processor();
|
||||
rtems_status_code sc;
|
||||
barrier_state bs = BARRIER_STATE_INITIALIZER;
|
||||
SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
|
||||
|
||||
run_tests(ctx, &bs, cpu_count, cpu_self, false);
|
||||
|
||||
@@ -301,7 +263,7 @@ static void test(void)
|
||||
uint32_t cpu;
|
||||
int test;
|
||||
rtems_status_code sc;
|
||||
barrier_state bs = BARRIER_STATE_INITIALIZER;
|
||||
SMP_barrier_State bs = SMP_BARRIER_STATE_INITIALIZER;
|
||||
|
||||
for (cpu = 0; cpu < cpu_count; ++cpu) {
|
||||
if (cpu != cpu_self) {
|
||||
|
||||
Reference in New Issue
Block a user