1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00
libhermit/usr/ircce/iRCCE_atomic.c
2016-12-03 00:43:49 +01:00

195 lines
5.3 KiB
C

//***************************************************************************************
// Functions for handling Atomic Increment Registers (AIR).
//***************************************************************************************
//
// Copyright 2012, Chair for Operating Systems, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "iRCCE_lib.h"
#ifdef AIR
//--------------------------------------------------------------------------------------
// FUNCTION: iRCCE_atomic_alloc
//--------------------------------------------------------------------------------------
// Allocates a new AIR register; returns iRCCE_ERRO if all AIRs are already allocated
//--------------------------------------------------------------------------------------
int iRCCE_atomic_alloc(iRCCE_AIR** reg)
{
if(iRCCE_atomic_alloc_counter < 2 * RCCE_NP) {
int next_reg = RC_COREID[iRCCE_atomic_alloc_counter];
if(iRCCE_atomic_alloc_counter > RCCE_NP) next_reg += RCCE_MAXNP;
(*reg) = &iRCCE_atomic_inc_regs[next_reg];
#ifdef _OPENMP
#pragma omp master
{
iRCCE_atomic_alloc_counter++;
}
#pragma omp barrier
#else
iRCCE_atomic_alloc_counter++;
#endif
iRCCE_atomic_write((*reg), 0);
return iRCCE_SUCCESS;
}
else {
return iRCCE_ERROR;
}
}
//--------------------------------------------------------------------------------------
// FUNCTION: iRCCE_atomic_inc
//--------------------------------------------------------------------------------------
// Increments an AIR register and returns its privious content
//--------------------------------------------------------------------------------------
int iRCCE_atomic_inc(iRCCE_AIR* reg, int* value)
{
int _value;
if(value == NULL) value = &value;
#ifndef _OPENMP
(*value) = (*reg->counter);
#else
#pragma omp critical
{
(*value) = reg->counter;
reg->counter++;
reg->init = reg->counter;
}
#endif
return iRCCE_SUCCESS;
}
//--------------------------------------------------------------------------------------
// FUNCTION: iRCCE_atomic_read
//--------------------------------------------------------------------------------------
// Returns the current value of an AIR register
//--------------------------------------------------------------------------------------
int iRCCE_atomic_read(iRCCE_AIR* reg, int* value)
{
#ifndef _OPENMP
(*value) = (*reg->init);
#else
#pragma omp critical
{
(*value) =reg->init;
}
#endif
return iRCCE_SUCCESS;
}
//--------------------------------------------------------------------------------------
// FUNCTION: iRCCE_atomic_write
//--------------------------------------------------------------------------------------
// Initializes an AIR register by writing a start value
//--------------------------------------------------------------------------------------
int iRCCE_atomic_write(iRCCE_AIR* reg, int value)
{
#ifndef _OPENMP
(*reg->init) = value;
#else
#pragma omp critical
{
reg->init = value;
reg->counter = value;
}
#endif
return iRCCE_SUCCESS;
}
//--------------------------------------------------------------------------------------
// FUNCTION: iRCCE_barrier
//--------------------------------------------------------------------------------------
// A barrier version based on the Atomic Increment Registers (AIR); if AIRs are not
// supported, the function makes a fall-back to the common RCCE_barrier().
//--------------------------------------------------------------------------------------
static void RC_wait(int wait) {
#ifndef _OPENMP
asm volatile( "movl %%eax,%%ecx\n\t"
"test:nop\n\t"
"loop test"
: /* no output registers */
: "a" (wait)
: "%ecx" );
#endif
return;
}
static int idx = 0;
static unsigned int rnd = 0;
#ifdef _OPENMP
#pragma omp threadprivate (idx, rnd)
#endif
int iRCCE_barrier(RCCE_COMM *comm)
{
int backoff = BACKOFF_MIN, wait, i = 0;
int counter;
if(comm == NULL) comm = &RCCE_COMM_WORLD;
if (comm == &RCCE_COMM_WORLD) {
iRCCE_atomic_inc(iRCCE_atomic_barrier[idx], &counter);
if (counter < (comm->size-1))
{
iRCCE_atomic_read(iRCCE_atomic_barrier[idx], &counter);
while (counter > 0)
{
rnd = rnd * 1103515245u + 12345u;
wait = BACKOFF_MIN + (rnd % (backoff << i));
RC_wait(wait);
if (wait < BACKOFF_MAX) i++;
iRCCE_atomic_read(iRCCE_atomic_barrier[idx], &counter);
}
}
else
{
iRCCE_atomic_write(iRCCE_atomic_barrier[idx], 0);
}
idx = !idx;
return(RCCE_SUCCESS);
}
else
{
return RCCE_barrier(comm);
}
}
#else // !AIR
int iRCCE_barrier(RCCE_COMM *comm)
{
if(comm == NULL) return RCCE_barrier(&RCCE_COMM_WORLD);
else return RCCE_barrier(comm);
}
#endif // !AIR