Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / legion / src / generic / barrier.c
/*
* ========== Copyright Header Begin ==========================================
*
* OpenSPARC T2 Processor File: barrier.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
*
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
*
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ========== Copyright Header End ============================================
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "@(#)barrier.c 1.2 06/09/12 SMI"
#include <errno.h>
#include <thread.h>
#include "barrier.h"
int
barrier_init(barrier_t *bp, int count)
{
int n;
int i;
if (count < 1)
return (EINVAL);
bp->maxcnt = count;
bp->sbp = &bp->sb[0];
for (i = 0; i < 2; ++i) {
struct _sb *sbp = &(bp->sb[i]);
sbp->runners = count;
if (n = mutex_init(&sbp->wait_lk, NULL, NULL))
return (n);
if (n = cond_init(&sbp->wait_cv, NULL, NULL))
return (n);
}
return (0);
}
void
barrier_wait(barrier_t *bp)
{
struct _sb *sbp = bp->sbp;
mutex_lock(&sbp->wait_lk);
if (sbp->runners == 1) {
/* last thread to reach barrier */
if (bp->maxcnt != 1) {
/* reset runner count and switch sub-barriers */
sbp->runners = bp->maxcnt;
bp->sbp = (bp->sbp == &bp->sb[0])
? &bp->sb[1] : &bp->sb[0];
/* wake up the waiters */
cond_broadcast(&sbp->wait_cv);
}
} else {
sbp->runners--; /* one less runner */
while (sbp->runners != bp->maxcnt)
cond_wait(&sbp->wait_cv, &sbp->wait_lk);
}
mutex_unlock(&sbp->wait_lk);
}
int
barrier_busy_init(barrier_busy_t *bbp, int count)
{
int i;
if (count < 1)
return (EINVAL);
bbp->maxcnt = count;
bbp->sbbp = &bbp->sbb[0];
for (i = 0; i < 2; ++i) {
struct _sbb *sbbp = &(bbp->sbb[i]);
sbbp->runners = count;
sbbp->spin_cv = ~0;
}
return (0);
}
void
barrier_busy_wait(barrier_busy_t *bbp)
{
extern uint32_t sim_atomic_add_32_nv(uint32_t *target, int32_t delta);
struct _sbb *sbbp = bbp->sbbp;
if (bbp->maxcnt == 1)
return;
if (sim_atomic_add_32_nv((uint32_t *)&sbbp->runners, -1) == 0) {
/* last thread to reach barrier */
/* switch sub-barriers, reset runner count and "cv" */
bbp->sbbp = (bbp->sbbp == &bbp->sbb[0])
? &bbp->sbb[1] : &bbp->sbb[0];
bbp->sbbp->runners = bbp->maxcnt;
bbp->sbbp->spin_cv = ~0;
/* release the busy-waiters */
sbbp->spin_cv = 0;
} else {
while (sbbp->spin_cv)
;
}
}