
scala.reactive.isolate.IsolateFrame.scala Maven / Gradle / Ivy
The newest version!
package scala.reactive
package isolate
import java.util.concurrent.atomic.AtomicReference
import scala.annotation.tailrec
import scala.util.control.NonFatal
final class IsolateFrame[@spec(Int, Long, Double) T](
val name: String,
val isolateSystem: IsolateSystem,
val eventQueue: EventQueue[T],
val systemEmitter: Reactive.Emitter[SysEvent],
val sourceEmitter: Reactive.Emitter[T],
val failureEmitter: Reactive.Emitter[Throwable],
val scheduler: Scheduler,
val state: IsolateFrame.State,
val isolateState: AtomicReference[IsolateFrame.IsolateState]
) extends Reactor[T] {
@volatile private[reactive] var isolate: Isolate[T] = _
@volatile private[reactive] var channel: Channel[T] = _
@volatile private[reactive] var dequeuer: Dequeuer[T] = _
@volatile private[reactive] var errorHandling: PartialFunction[Throwable, Unit] = _
@volatile private[reactive] var terminating = false
@volatile var schedulerInfo: AnyRef = _
@volatile var allowedBudget: Long = _
@volatile var interruptRequested: Boolean = _
private def propagate(event: T) {
try sourceEmitter += event
catch errorHandling
finally {}
}
def react(event: T) {
isolate.later enqueue event
}
def isTerminating = terminating
def isOwned: Boolean = state.READ_STATE == 1
final def tryOwn(): Boolean = state.CAS_STATE(0, 1)
final def unOwn(): Unit = state.WRITE_STATE(0)
def unreact() {
// channel and all its reactives have been closed
// so no new messages will be added to the event queue
terminating = true
wake()
}
@tailrec def wake(): Unit = if (isolateState.get != IsolateFrame.Terminated) {
if (!isOwned) {
if (tryOwn()) scheduler.schedule(this)
else wake()
}
}
private def initErrorHandler() {
errorHandling = {
case NonFatal(t) => failureEmitter += t
}
}
def init(dummy: IsolateFrame[T]) {
// call the asynchronous foreach on the event queue
dequeuer = eventQueue.foreach(this)(scheduler)
// send to failure emitter
initErrorHandler()
// set allowed event budget to a default value
allowedBudget = 50
interruptRequested = false
}
init(this)
/* running the frame */
def run() {
run(this.dequeuer)
}
private def run(dummy: Dequeuer[T]) {
try {
if (isolateState.get != IsolateFrame.Terminated) isolateAndRun(dequeuer)
} finally {
unOwn()
if (dequeuer.nonEmpty || terminating) {
if (isolateState.get != IsolateFrame.Terminated) wake()
}
}
}
private def isolateAndRun(dummy: Dequeuer[T]) {
if (Isolate.selfIsolate.get != null) {
throw new IllegalStateException(s"Cannot execute isolate inside of another isolate: ${Isolate.selfIsolate.get}.")
}
try {
Isolate.selfIsolate.set(isolate)
runInIsolate(dequeuer)
} catch {
scheduler.handler
} finally {
Isolate.selfIsolate.set(null)
}
}
@tailrec private def checkCreated() {
import IsolateFrame._
if (isolateState.get == Created) {
if (isolateState.compareAndSet(Created, Running)) systemEmitter += IsolateStarted
else checkCreated()
}
}
private def checkEmptyQueue() {
if (dequeuer.isEmpty) systemEmitter += IsolateEmptyQueue
}
@tailrec private def checkTerminating() {
import IsolateFrame._
if (terminating && dequeuer.isEmpty && isolateState.get == Running) {
if (isolateState.compareAndSet(Running, Terminated)) systemEmitter += IsolateTerminated
else checkTerminating()
}
}
private def runInIsolate(dummy: Dequeuer[T]) {
try {
checkCreated()
var budget = 0L
while (dequeuer.nonEmpty && budget < allowedBudget && !interruptRequested) {
val event = dequeuer.dequeue()
propagate(event)
budget += 1
}
} finally {
try checkEmptyQueue()
finally checkTerminating()
}
}
}
object IsolateFrame {
/** Ownership state of the isolate frame - 0 is not owned, 1 is owned.
*/
final class State {
@volatile private[reactive] var state: Int = 0
def READ_STATE: Int = state
def WRITE_STATE(v: Int): Unit = util.unsafe.putIntVolatile(this, IsolateFrame.STATE_OFFSET, v)
def CAS_STATE(ov: Int, nv: Int): Boolean = util.unsafe.compareAndSwapInt(this, IsolateFrame.STATE_OFFSET, ov, nv)
}
val STATE_OFFSET = util.unsafe.objectFieldOffset(classOf[State].getDeclaredField("state"))
sealed trait IsolateState
case object Created extends IsolateState
case object Running extends IsolateState
case object Terminated extends IsolateState
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy