#include "CPP_EEOPTIONS.h"

CBOP
C     !ROUTINE: BAR2_INIT

C     !INTERFACE:
      SUBROUTINE BAR2_INIT( myThid )
      IMPLICIT NONE

C     !DESCRIPTION:
C     *=====================================================================*
C     | SUBROUTINE BAR2\_INIT
C     | o Setup global barrier data structures.
C     *=====================================================================*
C     | Initialise global barrier data structures that can be used in
C     | conjunction with MPI or that can also be used to create
C     *=====================================================================*

C     !USES:
C     == Global variables ==
#include "SIZE.h"
#include "EEPARAMS.h"
#include "EESUPPORT.h"
#include "BAR2.h"
C

C     !INPUT/OUTPUT PARAMETERS:
C     == Routine arguments ==
C     myThid :: Thread number of this instance of BAR2_INIT
      INTEGER myThid

C     !LOCAL VARIABLES:
C     == Local variables ==
C     I :: Loop counter
      INTEGER I
CEOP

C
      DO I = 1, lShare4
       BAR2_level(I,myThid) = 0
       BAR2_barrierCount(I,myThid) = 0
       BAR2_spinsCount(I,myThid) = 0
       BAR2_spinsCount(I,myThid) = 0
       BAR2_spinsMax  (I,myThid) = 0
       BAR2_spinsMin  (I,myThid) = 1000000000
      ENDDO
C
      bar2CollectStatistics = .TRUE.
C
      RETURN
      END

CBOP

C     !ROUTINE: BAR2

C     !INTERFACE:
      SUBROUTINE BAR2( myThid )
      IMPLICIT NONE

C     !DESCRIPTION:
C     *=====================================================================*
C     | SUBROUTINE BAR2
C     | o Global barrier routine.
C     *=====================================================================*
C     | Implements a simple true shared memory barrier that uses a global
C     | heap array that all threads can access to synchronise. Each thread
C     | writes to a predefined location. One thread polls the locations. Other
C     | threads poll an all clear assertion location. Once the polling
C     | thread that is looping over locations sees writes for each thread is
C     | writes the all clear assertion location and everyone proceeds. A
C     | cyclic series of locations is used to ensure that race conditions do
C     | not occur. A few simple statistics are recorded giving number of
C     | barrier calls, max, min and aggregate polling loop counts.
C     *=====================================================================*

C     !USES:
C     == Global variables ==
#include "SIZE.h"
#include "EEPARAMS.h"
#include "EESUPPORT.h"
#include "BAR2.h"

C     !INPUT/OUTPUT PARAMETERS:
C     == Routine arguments ==
C     myThid :: Thread number of this instance of BAR2
      INTEGER myThid

C     !LOCAL VARIABLES:
C     == Local variables ==
C     myLevel   :: Temp. to hold "active" barrier level
C     nDone     :: Temp. for counting number of threads that
C                  have reached the barrier.
C     I         :: Loop counter
C     spinCount :: Temp. for doing statistics on how many
C                  times barrier code looped.
      INTEGER myLevel
      INTEGER nDone
      INTEGER I
      INTEGER spinCount
CEOP

#ifdef USE_OMP_THREADING
C$OMP BARRIER
      BAR2_barrierCount(1,myThid) = BAR2_barrierCount(1,myThid)+1
Cdbg C$OMP BARRIER
Cdbg       DO I = 2, nThreads
Cdbg        IF ( BAR2_barrierCount(1,I) .NE. BAR2_barrierCount(1,1) ) THEN
Cdbg         PRINT *, BAR2_barrierCount(1,1:nThreads)
Cdbg         CALL SYSTEM('sleep 1')
Cdbg         PRINT *, BAR2_barrierCount(1,1:nThreads)
Cdbg         Stop ' bar2 OUT OF SYNC '
Cdbg        ENDIF
Cdbg       ENDDO
Cdbg C$OMP BARRIER
      RETURN
#endif

      spinCount = 0

      IF ( myThid .NE. 1 ) THEN

       BAR2_level(1,myThid) = BAR2_level(1,myThid)+1
       myLevel              = BAR2_level(1,myThid)
   10  CONTINUE
        IF ( BAR2_level(1,1) .EQ. myLevel  ) GOTO 11
        spinCount = spinCount+1
        CALL FOOL_THE_COMPILER( BAR2_level(1,1) )
       GOTO 10
   11  CONTINUE

      ELSE

       myLevel = BAR2_level(1,1)
   12  CONTINUE
        CALL FOOL_THE_COMPILER( BAR2_level(1,1) )
        nDone   = 1
        DO I = 2, nThreads
         IF ( BAR2_level(1,1) .EQ. BAR2_level(1,I)-1 ) nDone = nDone+1
        ENDDO
        spinCount = spinCount+1
       IF ( nDone .LT. nThreads ) GOTO 12

       BAR2_level(1,1) = myLevel+1

      ENDIF

      BAR2_barrierCount(1,myThid) = BAR2_barrierCount(1,myThid)+1
      BAR2_spinsCount(1,myThid) = BAR2_spinsCount(1,myThid)+spinCount
      BAR2_spinsMax  (1,myThid) = MAX(BAR2_spinsMax(1,myThid),spinCount)
      BAR2_spinsMin  (1,myThid) = MIN(BAR2_spinsMin(1,myThid),spinCount)

      RETURN
      END
