Skip to content

Commit

Permalink
Corrected two-phase barrier behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
dbarashev committed Sep 28, 2024
1 parent f9059ec commit 666a951
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 7 deletions.
22 changes: 15 additions & 7 deletions ganttproject/src/main/java/biz/ganttproject/app/Barriers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -75,21 +75,34 @@ class TwoPhaseBarrierImpl<T>(private val value: T) : Barrier<T>, BarrierEntrance
private val counter = AtomicInteger(0)
private val exits = mutableListOf<BarrierExit<T>>()
private val activities = mutableMapOf<String, OnBarrierReached>()

var isActive: Boolean = false
set(value) {
field = value
if (value && counter.get() == 0) {
exits.forEach { it(this.value) }
}
}

override fun await(code: BarrierExit<T>) {
if (counter.get() == 0) {
if (isActive && counter.get() == 0) {
code(value)
} else {
exits.add(code)
}
}

override fun register(activity: String): OnBarrierReached {
assert(!isActive) {
"You need to register barrier activities before it gets active"
}
return {
if (counter.get() > 0) {
BARRIER_LOGGER.debug("Barrier reached: $activity")
//println("Barrier reached: $activity")
activities.remove(activity)
tick()
counter.decrementAndGet()
isActive = true
}
}.also {
BARRIER_LOGGER.debug("Barrier waiting: $activity")
Expand All @@ -98,11 +111,6 @@ class TwoPhaseBarrierImpl<T>(private val value: T) : Barrier<T>, BarrierEntrance
counter.incrementAndGet()
}
}
private fun tick() {
if (counter.decrementAndGet() == 0) {
exits.forEach { it(value) }
}
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ open class GanttProjectImpl(
for (l in listeners) {
l.projectOpened(barrier, barrier)
}
barrier.isActive = true
}

@Throws(Document.DocumentException::class, IOException::class)
Expand Down
53 changes: 53 additions & 0 deletions ganttproject/src/test/java/biz/ganttproject/app/BarriersTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright 2024 BarD Software s.r.o., Dmitry Barashev.
*
* This file is part of GanttProject, an opensource project management tool.
*
* GanttProject is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GanttProject 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 GanttProject. If not, see <http://www.gnu.org/licenses/>.
*/
package biz.ganttproject.app

import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class BarriersTest {

@Test
fun `two phase barrier exit registered before entrance`() {
var exitCalled = false
val barrier = TwoPhaseBarrierImpl<Boolean>(true)
barrier.await {
assertTrue(it)
exitCalled = true
}
assertFalse(exitCalled)

barrier.register("Entrance activity").let { entrance -> entrance() }
assertTrue(exitCalled)
}

@Test
fun `two phase barrier exit registered after entrance`() {
var exitCalled = false
val barrier = TwoPhaseBarrierImpl<Boolean>(true)
barrier.register("Entrance activity").let { entrance -> entrance() }
barrier.await {
assertTrue(it)
exitCalled = true
}
assertTrue(exitCalled)
}

}

0 comments on commit 666a951

Please sign in to comment.