Skip to content

Commit

Permalink
[sre] Fixing the locks into the stop function of the agent.
Browse files Browse the repository at this point in the history
Signed-off-by: Stéphane Galland <galland@arakhne.org>
  • Loading branch information
gallandarakhneorg committed Feb 22, 2021
1 parent d9df842 commit b1afd08
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 62 deletions.
Expand Up @@ -894,10 +894,11 @@ capacity DefaultContextInteractions {
* @param params the arguments to pass in the initialization event to the spawned agent.
* @return the identifier of the spawned agent.
* @fires AgentSpawned in DefaultSpace
* @fires AgentSpawnFailure if the cannot be spawn.
* @deprecated See the {@link Lifecycle} capacity.
*/
@Deprecated
def spawn(agentType : Class<? extends Agent>, params : Object*) : UUID fires AgentSpawned
def spawn(agentType : Class<? extends Agent>, params : Object*) : UUID fires AgentSpawned, AgentSpawnFailure

}

Expand Down
Expand Up @@ -456,7 +456,7 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
var defaultContext = life.defaultContext
// We should check if it is possible to kill the agent BEFORE killing it.
if (forceKillable || life.isKillableAgent(agentId)) {
var contexts = life.stop(this.skillUninstaller, getLogger)
var contexts = life.stop(^agent, this.skillUninstaller, getLogger)
^agent.onAgentKilled
fireAgentDestructionEvents(^agent, defaultContext, contexts, terminationCause)
// Test if the agent is the latest on this kernel.
Expand Down Expand Up @@ -665,7 +665,7 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
var started = false
var spawnError : Throwable = null
try {
started = life.start(this.skillUninstaller, this.logger, this.spawningAgent, this.parentContext, this.initializationParameters)
started = life.start(^agent, this.skillUninstaller, this.logger, this.spawningAgent, this.parentContext, this.initializationParameters)
} catch (e : Throwable) {
started = false
spawnError = new CannotSpawnException(this.agentType, e)
Expand Down
Expand Up @@ -102,7 +102,7 @@ final class AgentLife {
} else {
life = new AgentLife(lockProvider)
}
life.^agent = ^agent
life.setAgent(^agent)
^agent.sreSpecificData = life
}
return life
Expand Down Expand Up @@ -141,28 +141,31 @@ final class AgentLife {
final def getAgentLogger : Logging {
// This implementation is lock-free because it is assumed that the skill definition will not change a lot.
// The code is inspired from the similar code that is generated by the SARL compiler.
val owner = this.^agent
var capRef = this.loggingCapacity
if (capRef === null ||
capRef.get() === null) {
capRef = SREutils::getInternalSkillReference(this.^agent, typeof(Logging));
capRef = SREutils::getInternalSkillReference(owner, typeof(Logging));
this.loggingCapacity = capRef
}
return SREutils::castInternalSkillReference(this.^agent, capRef, typeof(Logging))
return SREutils::castInternalSkillReference(owner, capRef, typeof(Logging))
}

/** Replies the agent's event bus.
*
* @param ag is the reference to the owner to consider
* @return the event bus.
*/
final def getEventBus : InternalEventBusCapacity {
final def getEventBus(ag : Agent) : InternalEventBusCapacity {
// This implementation is lock-free because it is assumed that the skill definition will not change a lot.
// The code is inspired from the similar code that is generated by the SARL compiler.
val owner = ag ?: getAgent
var capRef = this.eventBusCapacity
if (capRef === null || capRef.get() === null) {
capRef = SREutils::getInternalSkillReference(this.^agent, typeof(InternalEventBusCapacity));
capRef = SREutils::getInternalSkillReference(owner, typeof(InternalEventBusCapacity));
this.eventBusCapacity = capRef
}
return SREutils::castInternalSkillReference(this.^agent, capRef, typeof(InternalEventBusCapacity))
return SREutils::castInternalSkillReference(owner, capRef, typeof(InternalEventBusCapacity))
}

/** Start the agent's life.
Expand All @@ -171,6 +174,7 @@ final class AgentLife {
*
* <p>If an exception is thrown into the initialization code of the agent, the exception is forwarded.
*
* @param startingAgent is the reference to the starting agent.
* @param skillUninstaller the skill uninstaller.
* @param logger the logger to use for reporting initialization errors when the agent's logger is unavailable
* @param startError the exception that avoid to start the agent.
Expand All @@ -180,7 +184,7 @@ final class AgentLife {
* @param initializationParameters the parameters to give to the agent for its start-up.
* @return {@code true} is successful, i.e. the {@code AgentSpawned} could be fired.
*/
def start(skillUninstaller : SkillUninstaller, logger : Logger, spawningAgent : UUID,
def start(startingAgent : Agent, skillUninstaller : SkillUninstaller, logger : Logger, spawningAgent : UUID,
spawningContext : Context, initializationParameters : Object*) : boolean {
val rlock0 = this.lock.readLock
val st = new OutParameter<AgentState>
Expand All @@ -205,7 +209,7 @@ final class AgentLife {
}

// Get the event bus
val eb = getEventBus
val eb = getEventBus(startingAgent)
assert eb !== null

// Attach to the default context
Expand Down Expand Up @@ -252,7 +256,7 @@ final class AgentLife {
}
return true
} else {
stop(skillUninstaller, logger, true)
stop(startingAgent, skillUninstaller, logger, true)
return false
}
} catch (e : Throwable) {
Expand All @@ -261,7 +265,7 @@ final class AgentLife {
} catch (iex : Throwable) {
logger.log(Level::SEVERE, e) [e.localizedMessage]
}
stop(skillUninstaller, logger, true)
stop(startingAgent, skillUninstaller, logger, true)
throw e
}
}
Expand Down Expand Up @@ -324,20 +328,20 @@ final class AgentLife {
*
* <p>This function is invoked for executing the killing stage of the agent.
*
* @param dyingAgent is the agent to be killed.
* @param skillUninstaller the skill uninstaller.
* @param logger the logger to use for reporting initialization errors when the agent's logger is unavailable
* @param fireDestroy indicates if the {@code Destroy} event should be fired.
* @return the contexts from which the agent was removed.
*/
def stop(skillUninstaller : SkillUninstaller, logger : Logger, fireDestroy : boolean = true) : ConcurrentCollection<ContextReference> {
def stop(dyingAgent : Agent, skillUninstaller : SkillUninstaller, logger : Logger, fireDestroy : boolean = true) : ConcurrentCollection<ContextReference> {
assert dyingAgent !== null

// The following line is synchronized
this.state = AgentState::DYING

val dyingAgent = ^agent
assert dyingAgent !== null

try {
val eb = getEventBus
val eb = getEventBus(dyingAgent)
assert eb !== null

// Copy the external event listener in order to unregistered it later.
Expand Down Expand Up @@ -399,24 +403,36 @@ final class AgentLife {
try {
this.externalContextInstances = null
this.defaultContextInstance = null
this.agentInstance = null
} finally {
wlock.unlock
}
this.agentInstance = null

}
}

/** Replies the agent associated to this life.
*/
def getAgent : Agent {
return this.agentInstance
val rlock = this.lock.readLock
rlock.lock
try {
return this.agentInstance
} finally {
rlock.unlock
}
}

/** Change the agent associated to this life.
*/
def setAgent(^agent : Agent) {
this.agentInstance = ^agent
val wlock = this.lock.writeLock
wlock.lock
try {
this.agentInstance = ^agent
} finally {
wlock.unlock
}
}

/** Replies the agent state.
Expand Down
Expand Up @@ -23,14 +23,14 @@ package io.sarl.sre.tests.runtime.bugs.to1000.bug976
import io.sarl.sre.test.framework.context.SreRunContext
import io.sarl.sre.test.framework.^extension.PropertyRestoreExtension
import io.sarl.sre.test.framework.^extension.SreRunExtension
import io.sarl.sre.tests.runtime.bugs.to1000.bug976.mocks.AgentSpawnNBootAgent
import io.sarl.tests.api.extensions.ContextInitExtension
import io.sarl.tests.api.extensions.JavaVersionCheckExtension
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.^extension.ExtendWith
import io.sarl.sre.tests.runtime.bugs.to1000.bug976.mocks.AgentSpawnNBootAgent

/** Tests for issue #976: UnimplementedCapacityException when getting logging capacity.
*
Expand All @@ -52,8 +52,8 @@ import org.junit.jupiter.api.^extension.ExtendWith
@Tag("sre-run")
@Tag("janus")
@Tag("long-test")
@Tag("sre-dbg")
@SuppressWarnings("all")
@Disabled
class Bug976AgentSpawnNTest extends AbstractBug976Test {

private def run(extension rc : SreRunContext, nb : int) : void {
Expand Down
Expand Up @@ -28,7 +28,6 @@ import io.sarl.tests.api.extensions.ContextInitExtension
import io.sarl.tests.api.extensions.JavaVersionCheckExtension
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.RepeatedTest
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.^extension.ExtendWith
Expand All @@ -54,26 +53,25 @@ import org.junit.jupiter.api.^extension.ExtendWith
@Tag("janus")
@Tag("long-test")
@SuppressWarnings("all")
@Disabled
class Bug976DefaultSpaceMembersSpawnNTest extends AbstractBug976Test {
class Bug976DefaultSpaceMembersNSpawnTest extends AbstractBug976Test {

private def run(extension rc : SreRunContext, nb : int) : void {
rc.runDefaultSpace(typeof(AgentSpawnNDSBootAgent), nb)
}

@RepeatedTest(20)
@Test
@DisplayName("up to 1 agent")
def run1(extension rc : SreRunContext) : void {
rc.run(1)
}

@RepeatedTest(20)
@Test
@DisplayName("up to 10 agents")
def run10(extension rc : SreRunContext) : void {
rc.run(10)
}

@RepeatedTest(10)
@Test
@DisplayName("up to 100 agents")
def run100(extension rc : SreRunContext) : void {
rc.run(100)
Expand Down
Expand Up @@ -28,7 +28,6 @@ import io.sarl.tests.api.extensions.ContextInitExtension
import io.sarl.tests.api.extensions.JavaVersionCheckExtension
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.RepeatedTest
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.^extension.ExtendWith
Expand All @@ -54,26 +53,25 @@ import org.junit.jupiter.api.^extension.ExtendWith
@Tag("janus")
@Tag("long-test")
@SuppressWarnings("all")
@Disabled
class Bug976InnerSpaceMembersSpawnNTest extends AbstractBug976Test {
class Bug976InnerSpaceMembersNSpawnTest extends AbstractBug976Test {

private def run(extension rc : SreRunContext, nb : int) : void {
rc.runInnerSpace(typeof(AgentSpawnNISBootAgent), nb)
}

@RepeatedTest(20)
@Test
@DisplayName("up to 1 agent")
def run1(extension rc : SreRunContext) : void {
rc.run(1)
}

@RepeatedTest(20)
@Test
@DisplayName("up to 10 agents")
def run10(extension rc : SreRunContext) : void {
rc.run(10)
}

@RepeatedTest(10)
@Test
@DisplayName("up to 100 agents")
def run100(extension rc : SreRunContext) : void {
rc.run(100)
Expand Down
Expand Up @@ -24,6 +24,7 @@ package io.sarl.sre.tests.runtime.bugs.to1000.bug976.mocks
import io.sarl.core.DefaultContextInteractions
import io.sarl.core.Initialize
import io.sarl.core.Lifecycle
import io.sarl.sre.capacities.InternalSchedules
import io.sarl.sre.test.framework.events.Bye
import io.sarl.sre.test.framework.skills.TestingCapacity
import io.sarl.sre.test.framework.skills.TestingSkill
Expand All @@ -32,7 +33,7 @@ import java.util.concurrent.atomic.AtomicInteger
@SuppressWarnings("all")
agent AgentSpawnNBootAgent {

uses Lifecycle, DefaultContextInteractions
uses Lifecycle, DefaultContextInteractions, InternalSchedules

uses TestingCapacity

Expand All @@ -43,18 +44,23 @@ agent AgentSpawnNBootAgent {
setSkill(new TestingSkill(occurrence))
val nb : int = getParam(0)
this.totalNumber.set(nb)
spawn(nb, typeof(ScalableAgent), buildAgentInitializationParameters)
spawn(nb, typeof(ScalableAgent), buildAgentInitializationParameters(1))
("nb-spawn-" + nb).addResult
}

on Ready {
val n = this.nbSpawn.incrementAndGet
//System.err.println("RECEIVED=" + n)
//System.out.println("READY:" + n)
//System.out.println("[" + n + "]: " + executorServiceStateRepresentation)
if (n >= this.totalNumber.get) {
"all-spawn".addResult
emit(new Bye) [it.ID != this.ID]
killMe
//System.out.println("DIE:" + n)
emit(new Bye)
}
}

on Bye {
killMe
}

}
Expand Up @@ -43,22 +43,23 @@ agent AgentSpawnNDSBootAgent {
setSkill(new TestingSkill(occurrence))
val nb : int = getParam(0)
this.totalNumber.set(nb)
spawn(nb, typeof(ScalableAgent), buildAgentInitializationParameters)
spawn(nb, typeof(ScalableAgent), buildAgentInitializationParameters(nb))
("nb-spawn-" + nb).addResult
}

on Ready {
val n = this.nbSpawn.incrementAndGet
//System.err.println("RECEIVED=" + n)
//System.out.println("READY:" + n)
//System.out.println("[" + n + "]: " + executorServiceStateRepresentation)
if (n >= this.totalNumber.get) {
"all-spawn".addResult
val nb0 = defaultSpace.numberOfStrongParticipants;
("strong-participants-" + nb0).addResult
val nb1 = defaultSpace.numberOfWeakParticipants;
("weak-participants-" + nb1).addResult
emit(new Bye) [it.ID != this.ID]
killMe
//System.out.println("DIE:" + n)
emit(new Bye)
}
}

on Bye {
killMe
}

}

0 comments on commit b1afd08

Please sign in to comment.