Skip to content

Commit

Permalink
[SRE] Adding a double lock in Agent spawn
Browse files Browse the repository at this point in the history
Correcting the bug where the number of effectively spawnagent was
different than the number of spawn call. Discover on boids Demo.
  • Loading branch information
ngaud committed Mar 25, 2020
1 parent 0f184d8 commit ad2c130
Showing 1 changed file with 22 additions and 14 deletions.
Expand Up @@ -32,18 +32,19 @@ import io.sarl.sre.services.executor.ExecutorService
import io.sarl.sre.services.executor.Runnables
import io.sarl.sre.services.logging.LoggingService
import java.lang.ref.WeakReference
import static java.text.MessageFormat.*
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedDeque
import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicLong
import java.util.concurrent.atomic.AtomicReference
import java.util.concurrent.locks.ReentrantLock
import java.util.logging.Level
import javax.inject.Provider
import javax.inject.Singleton
import org.eclipse.xtext.xbase.lib.Functions.Function0

import static io.sarl.sre.services.lifecycle.AgentLife.*
import static java.text.MessageFormat.*

/**
* Implementation of a spawning service that is based on the other services of the SRE platform.
Expand Down Expand Up @@ -201,15 +202,15 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
this.agentId = new AtomicReference(agentId)
}
}

def apply : UUID {
val id = this.agentId?.getAndSet(null)
if (id === null) {
return UUID::randomUUID
}
return id
}

}

/** Replies if the service can spawn.
Expand All @@ -220,27 +221,31 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
isRunning
}

val lock : ReentrantLock = new ReentrantLock

protected def spawnAgent(nbAgents : int, spawningAgent : UUID, parent : Context,
agentClazz : Class<? extends Agent>, params : Object[],
agentIds : ()=>UUID) {
agentClazz : Class<? extends Agent>, params : Object[], agentIds : ()=>UUID) {
if (canSpawnAgent && nbAgents > 0) {

// Check if the version of the SARL agent class is compatible.
if (this.sarlSpecificationChecker === null ||
!this.sarlSpecificationChecker.isValidSarlElement(agentClazz)) {
throw new InvalidSarlSpecificationException(agentClazz)
}

val spawnQueryAccess = new SpawnQueries(this)

lock.lock
// Create the shared injector that is also able to create the agent instance.
val agentInstanceCreator = this.agentCreatorProvider.getAgentCreator(agentClazz, parent.ID,
nbAgents, dynamicSkillProviders)
val agentInstanceCreator = this.agentCreatorProvider.getAgentCreator(agentClazz, parent.ID, nbAgents,
dynamicSkillProviders)
lock.unlock
// Create the block of code for creating a single agent
val agentCreator : Runnable = [
val aid = agentIds.apply

val aid = agentIds.apply
// Effectively create the agent
val ^agent = agentInstanceCreator.apply(aid)

if (^agent === null) {
throw new CannotSpawnException(agentClazz)
}
Expand All @@ -249,14 +254,15 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
var life = getLife(^agent)
var started = false
var spawnError : Throwable = null
lock.lock
try {
started = life.start(this.skillUninstaller, getLoggingService, spawningAgent, parent,
params)
started = life.start(this.skillUninstaller, getLoggingService, spawningAgent, parent, params)
} catch (e : Throwable) {
started = false
spawnError = new CannotSpawnException(agentClazz, e)
} finally {
spawnQueryAccess.done
lock.unlock
}
if (started) {
// Add the agent in the system. It is synchronized because additions may occur in parallel
Expand All @@ -275,6 +281,7 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
// start before stopping the SRE.
parent.startShutdownLookup
}

]
if (nbAgents > 1) {
this.executor.executeNotBlockingTask(loggingService.kernelLogger, nbAgents,
Expand Down Expand Up @@ -338,7 +345,8 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
* @param parent the context in which the agents are created.
* @param agentClazz the type of the spawned agents.
*/
protected def fireAgentSpawningErrorEvents(spawningAgent : UUID, parent : Context, agentClazz : Class<? extends Agent>) {
protected def fireAgentSpawningErrorEvents(spawningAgent : UUID, parent : Context,
agentClazz : Class<? extends Agent>) {
this.platformLifecycleEventEmitter.agentSpawnFailure(spawningAgent, parent, agentClazz)
}

Expand All @@ -353,9 +361,9 @@ abstract class AbstractLifecycleService extends AbstractSreService implements Li
}

/** Replies if the given agent could be kill according to the SARL specification.
*
*
* <p>An agent could be kill if is has no internal member.
*
*
* @param life the internal data structure for the agent.
* @param id the identifier of the agent.
* @return {@code true} if the agent could be killed.
Expand Down

0 comments on commit ad2c130

Please sign in to comment.