Skip to content

Commit e2b33d2

Browse files
committed
Merge pull request #3 from anatoliykmetyuk/develop
SubScript Actors basic implementation
2 parents 0c37ee8 + c278e30 commit e2b33d2

8 files changed

+207
-44
lines changed

buildcharacter.properties

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,23 @@
11
#Ant properties
2-
#Mon Jan 06 13:51:32 CET 2014
2+
#Mon Mar 24 23:35:54 EET 2014
33
ant.java.version=1.6
4-
ant.version=Apache Ant(TM) version 1.8.2 compiled on June 20 2012
5-
git.commit.date=20140106-103905
6-
git.commit.sha=b97a422ca6
4+
ant.version=Apache Ant(TM) version 1.9.3 compiled on January 19 2014
5+
git.commit.date=20140324-233102
6+
git.commit.sha=0b9208b7f4
77
java.class.version=50.0
88
java.runtime.name=Java(TM) SE Runtime Environment
9-
java.runtime.version=1.6.0_51-b11-457-11M4509
9+
java.runtime.version=1.6.0_45-b06
1010
java.specification.version=1.6
11-
java.version=1.6.0_51
12-
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
11+
java.version=1.6.0_45
12+
java.vm.name=Java HotSpot(TM) Server VM
1313
java.vm.specification.version=1.0
14-
java.vm.version=20.51-b01-457
14+
java.vm.version=20.45-b01
1515
jline.version=2.11
1616
junit.version=4.10
1717
maven.version.number=2.11.0-SNAPSHOT
1818
maven.version.suffix=-SNAPSHOT
19-
mrj.version=1070.1.6.0_51-457
20-
os.version=10.8.5
21-
osgi.version.number=2.11.0.v20140106-103905-b97a422ca6
19+
os.version=3.13.6-1-ARCH
20+
osgi.version.number=2.11.0.v20140324-233102-0b9208b7f4
2221
osgi.version.suffix=
2322
partest.version.number=1.0.0-RC8
2423
partest.versions=1.3.0\:2.11.0-M7\:1.8.4\:1.0.0-RC8\:1.0
@@ -39,19 +38,19 @@ scalac.args.locker=-feature
3938
scalac.args.optimise=
4039
scalac.args.quick=-feature
4140
scalac.args.strap=-feature
42-
scalacfork.jvmargs=-Xms512M -Xmx1536M -Xss1M -XX\:MaxPermSize\=128M
41+
scalacfork.jvmargs=-Xms1536M -Xmx1536M -Xss1M -XX\:MaxPermSize\=192M -XX\:+UseParallelGC
4342
scalacheck.version.number=1.11.1
4443
scalacheck.versions=1.11.1\:1.0.0-RC5\:2.11.0-M7\:1.0
4544
starr.version=2.11.0-M7
46-
time.DSTAMP=20140106
47-
time.TODAY=January 6 2014
48-
time.TSTAMP=1351
49-
time.human=6 January 2014, 13\:51\:32
50-
time.short=20140106135132
45+
time.DSTAMP=20140324
46+
time.TODAY=March 24 2014
47+
time.TSTAMP=2335
48+
time.human=24 March 2014, 23\:35\:54
49+
time.short=20140324233554
5150
user.timezone=
5251
version.bnum=0
5352
version.major=2
5453
version.minor=11
55-
version.number=2.11.0-20140106-103905-b97a422ca6
54+
version.number=2.11.0-20140324-233102-0b9208b7f4
5655
version.patch=0
5756
version.suffix=
2.4 MB
Binary file not shown.

lib/extra/config-1.2.0.jar

213 KB
Binary file not shown.
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package subscript.akka
2+
3+
import subscript.DSL._scriptType
4+
import scala.collection.mutable.ListBuffer
5+
import subscript.vm._
6+
import akka.actor._
7+
8+
trait SubScriptActor extends Actor {
9+
10+
private object Terminator {
11+
def block = synchronized(wait())
12+
def release = synchronized(notify())
13+
}
14+
15+
private val callHandlers = ListBuffer[PartialFunction[Any, Unit]]()
16+
17+
18+
19+
// Scripts
20+
def _live(): N_call => Unit
21+
private def script terminate = {*Terminator.block*}
22+
private def script die = {if (context ne null) context stop self}
23+
24+
25+
26+
// Callbacks
27+
override def aroundPreStart() {
28+
def script lifecycle = (live || terminate) ; die
29+
SubScriptActor.executeScript(_lifecycle())
30+
super.aroundPreStart()
31+
}
32+
33+
override def aroundReceive(receive: Actor.Receive, msg: Any) {
34+
synchronized {
35+
sendSynchronizationMessage(this)
36+
wait()
37+
}
38+
39+
var messageWasHandled = false
40+
callHandlers.synchronized {
41+
for (h <- callHandlers if h isDefinedAt msg) {
42+
h(msg)
43+
messageWasHandled = true
44+
}
45+
}
46+
47+
// If a message was handled, Akka will try to match it against a function that can handle any message
48+
// otherwise it will try to match the message against function that can handle virtually nothing
49+
// (except LocalObject, which is certainly local and can't be available from the outside)
50+
case object LocalObject
51+
super.aroundReceive(if (messageWasHandled) {case _: Any =>} else {case LocalObject =>}, msg)
52+
}
53+
54+
override def aroundPostStop() {
55+
Terminator.release
56+
super.aroundPostStop()
57+
}
58+
59+
final def receive: Actor.Receive = {case _ =>}
60+
61+
62+
63+
// SubScript actor convenience methods
64+
def initActor(node: N_code_eventhandling, _handler: PartialFunction[Any, Unit]) {
65+
node.codeExecutor = EventHandlingCodeFragmentExecutor(node, node.scriptExecutor)
66+
val handler = _handler andThen {_ => node.codeExecutor.executeAA}
67+
synchronized {callHandlers += handler}
68+
node.onDeactivate {
69+
synchronized {callHandlers -= handler}
70+
}
71+
}
72+
73+
def sendSynchronizationMessage(lock: AnyRef) {
74+
val vm = SubScriptActor.vm
75+
vm insert SynchronizationMessage(vm.rootNode, lock)
76+
}
77+
78+
}
79+
80+
81+
object SubScriptActor {
82+
83+
private lazy val vm: CommonScriptExecutor = {
84+
val _vm = ScriptExecutorFactory.createScriptExecutor(true);
85+
86+
_parallelScript()(_vm.anchorNode)
87+
_vm addHandler synchMsgHandler
88+
89+
new Thread {override def run = {_vm.run}}.start()
90+
while (parallelOp == null) wait()
91+
92+
_vm
93+
}
94+
private var parallelOp: CallGraphParentNodeTrait = null
95+
96+
private object Stopper {
97+
def block = synchronized(wait())
98+
def release = synchronized(notify())
99+
}
100+
private def script parallelScript = {*Stopper.block*} & {captureParallelOp(here)}
101+
private def captureParallelOp(here: CallGraphTreeNode) = synchronized {
102+
parallelOp = here.parent.asInstanceOf[CallGraphParentNodeTrait]
103+
notify()
104+
}
105+
106+
val synchMsgHandler: PartialFunction[CallGraphMessage[_ <: CallGraphNodeTrait], Unit] = {
107+
case SynchronizationMessage(_, lock) => lock.synchronized(lock.notify())
108+
}
109+
110+
def executeScript(script: _scriptType) = synchronized {
111+
val template = extractTemplate(script)
112+
vm.invokeFromET { vm.activateFrom(parallelOp, template) }
113+
}
114+
115+
116+
def extractTemplate(script: _scriptType) = {
117+
val extractor = N_call(T_call(null))
118+
script(extractor)
119+
extractor.t_callee
120+
}
121+
122+
def releaseVm() = Stopper.release
123+
124+
}
125+
126+
case class SynchronizationMessage(node: CallGraphNodeTrait, lock: AnyRef) extends CallGraphMessage[CallGraphNodeTrait] {
127+
priority = -1
128+
}

src/subscript/subscript/swing/GraphicalDebugger.scala

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -539,13 +539,14 @@ class GraphicalDebuggerApp extends SimpleSubscriptApplication with ScriptDebugge
539539
def sleep(duration_ms: Long) = try {Thread.sleep(duration_ms)} catch {case e: InterruptedException => println("sleep interrupted")}
540540
def confirmExit: Boolean = Dialog.showConfirmation(exitButton, "Are you sure?", "About to exit")==Dialog.Result.Yes
541541

542+
object MessageStatusLock
543+
def messageBeingHandled(value: Boolean): Unit = MessageStatusLock.synchronized {
544+
messageBeingHandled = value
545+
MessageStatusLock.notify()
546+
}
542547

543-
def awaitMessageBeingHandled(value: Boolean) = {
544-
var sleeptime = 1
545-
while (messageBeingHandled!=value) {
546-
sleep(sleeptime)
547-
if (sleeptime<100) sleeptime *=2
548-
}
548+
def awaitMessageBeingHandled(value: Boolean) = MessageStatusLock.synchronized {
549+
while (messageBeingHandled != value) MessageStatusLock.wait()
549550
}
550551

551552
def shouldStep: Boolean =
@@ -618,7 +619,7 @@ class GraphicalDebuggerApp extends SimpleSubscriptApplication with ScriptDebugge
618619
live = {*awaitMessageBeingHandled(true)*}
619620
if (shouldStep) ( @{gui(there)}: {!updateDisplay!} stepCommand
620621
|| if(autoCheckBox.selected) {*waitForStepTimeout*} else (-) )
621-
{messageBeingHandled=false}
622+
{messageBeingHandled(false)}
622623
... // TBD: parsing goes wrong without this comment; lineStartOffset was incremented unexpectedly
623624
|| exitDebugger
624625

@@ -647,7 +648,7 @@ class GraphicalDebuggerApp extends SimpleSubscriptApplication with ScriptDebugge
647648

648649
def messageHandled(m: CallGraphMessage[_ <: subscript.vm.CallGraphNodeTrait]): Unit = {
649650
currentMessage = m
650-
messageBeingHandled=true
651+
messageBeingHandled(true)
651652
awaitMessageBeingHandled(false)
652653
currentMessage = null
653654
}

src/subscript/subscript/vm/CallGraphMessage.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,5 @@ import scala.collection.mutable._
104104
// i.e.
105105
// ->..?p:Int? loops and matches all sent integers like <-*1 <-*3
106106

107+
case class InvokeFromET(node: CallGraphNodeTrait, payload: () => Unit) extends CallGraphMessage[CallGraphNodeTrait]
108+

src/subscript/subscript/vm/CallGraphNode.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ trait CallGraphNodeTrait {
6666
def isExecuting = false
6767
var numberOfBusyActions = 0
6868
def isActionBusy = numberOfBusyActions>0
69-
69+
7070
var index = -1
7171
var stamp = 0
7272
var aaStartedCount = 0
@@ -226,6 +226,9 @@ abstract class CallGraphTreeNode_n_ary extends CallGraphTreeParentNode {
226226
var lastActivatedChild: CallGraphNodeTrait = null
227227
var aaStartedSinceLastOptionalBreak = false
228228
def mustBreak = hadBreak = true
229+
230+
var breakWaker: CallGraphNodeTrait = null
231+
229232
}
230233

231234
// The case classes for the bottom node types

src/subscript/subscript/vm/ScriptExecutor.scala

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
package subscript.vm
2828
import scala.collection.mutable._
29+
import scala.collection.mutable.ListBuffer
2930

3031
/*
3132
* Factory for script executors. Produces a CommonScriptExecutor
@@ -148,6 +149,7 @@ trait ScriptExecutor {
148149

149150
class CommonScriptExecutor extends ScriptExecutor {
150151

152+
var waitsForMessage = false
151153

152154
// send out a success when in an And-like context
153155
def doNeutral(n: CallGraphNodeTrait) =
@@ -165,7 +167,14 @@ class CommonScriptExecutor extends ScriptExecutor {
165167
childNode.parent = parentNode
166168
childNode.scriptExecutor = parentNode.scriptExecutor
167169
parentNode.children.append(childNode)
168-
parentNode match {case p: CallGraphTreeNode_n_ary => p.lastActivatedChild = childNode case _ =>}
170+
171+
parentNode match {
172+
case p: CallGraphTreeNode_n_ary =>
173+
childNode match {case N_break(_) | N_optional_break(_) | N_optional_break_loop(_) => p.breakWaker = p.lastActivatedChild case _ =>}
174+
p.lastActivatedChild = childNode
175+
176+
case _ =>
177+
}
169178
}
170179
// disconnect a child node from its parent
171180
def disconnect(childNode: CallGraphNodeTrait) {
@@ -192,6 +201,9 @@ class CommonScriptExecutor extends ScriptExecutor {
192201
case maa@AAToBeReexecuted(n: CallGraphNodeTrait) => n.asInstanceOf[N_atomic_action].msgAAToBeExecuted = maa
193202
case _ =>
194203
}
204+
205+
// Notify this
206+
synchronized { notify() }
195207
}
196208
// remove a message from the queue
197209
def remove(m: CallGraphMessage[_ <: CallGraphNodeTrait]) = {
@@ -665,8 +677,12 @@ class CommonScriptExecutor extends ScriptExecutor {
665677
if (nodesToBeSuspended!=null) nodesToBeSuspended.foreach((n) => insert(Suspend(n)))
666678
case _ =>
667679
}
668-
// message.child may be null now
669-
message.node.forEachParent(p => insert(AAStarted(p, message.node)))
680+
681+
val operator = message.node.n_ary_op_ancestor
682+
if (operator != null && (operator.breakWaker eq message.node)) operator.aaStartedSinceLastOptionalBreak = true
683+
684+
// message.child may be null now
685+
message.node.forEachParent(p => insert(AAStarted(p, message.node)))
670686
}
671687
/*
672688
* Handle an AAEnded message
@@ -892,7 +908,7 @@ class CommonScriptExecutor extends ScriptExecutor {
892908
case _ => if (message.activation!=null || message.aaStarteds!=Nil || message.success!=null || message.deactivations != Nil) {
893909
val b = message.break
894910
val as = message.aaStarteds
895-
n.aaStartedSinceLastOptionalBreak = n.aaStartedSinceLastOptionalBreak || as!=Nil
911+
// n.aaStartedSinceLastOptionalBreak = n.aaStartedSinceLastOptionalBreak || as!=Nil
896912
if (b==null||b.activationMode==ActivationMode.Optional) {
897913
if (n.activationMode==ActivationMode.Optional) {
898914
activateNextOrEnded = n.aaStartedSinceLastOptionalBreak
@@ -1001,12 +1017,12 @@ class CommonScriptExecutor extends ScriptExecutor {
10011017
if (activateNext) {
10021018
val t = message.node.template.children(nextActivationTemplateIndex)
10031019
activateFrom(message.node, t, Some(nextActivationPass))
1004-
if (message.activation!=null) {
1005-
val nary_op_isLeftMerge = n match {
1006-
case nary@N_n_ary_op (t: T_n_ary, isLeftMerge) => isLeftMerge case _ => false
1007-
}
1008-
if (!nary_op_isLeftMerge) insertContinuation(message.activation, n)
1020+
val activation = if (message.activation != null) message.activation else Activation(message.node)
1021+
1022+
val nary_op_isLeftMerge = n match {
1023+
case nary@N_n_ary_op (t: T_n_ary, isLeftMerge) => isLeftMerge case _ => false
10091024
}
1025+
if (!nary_op_isLeftMerge) insertContinuation(activation, n)
10101026
}
10111027
else if (n.children.isEmpty) {
10121028
insertDeactivation(n, null)
@@ -1015,12 +1031,11 @@ class CommonScriptExecutor extends ScriptExecutor {
10151031
// decide on deactivation of n
10161032

10171033
}
1018-
1019-
/*
1020-
* message dispatcher; not really OO, but all real activity should be at the executors; other things should be passive
1021-
*/
1022-
def handle(message: CallGraphMessage[_ <: subscript.vm.CallGraphNodeTrait]):Unit = {
1023-
message match {
1034+
1035+
1036+
type MessageHandler = PartialFunction[CallGraphMessage[_ <: CallGraphNodeTrait], Unit]
1037+
1038+
val defaultHandler: MessageHandler = {
10241039
case a@ Activation (_) => handleActivation (a)
10251040
case a@Continuation (_) => handleContinuation (a)
10261041
case a@Continuation1 (_) => handleContinuation1(a)
@@ -1040,8 +1055,23 @@ class CommonScriptExecutor extends ScriptExecutor {
10401055
case a@AAToBeExecuted (_) => handleAAToBeExecuted (a)
10411056
case CommunicationMatchingMessage => handleCommunicationMatchingMessage
10421057
}
1058+
val communicationHandler: MessageHandler = {
1059+
case InvokeFromET(_, payload) => payload()
10431060
}
10441061

1062+
private val messageHandlers = ListBuffer[MessageHandler](defaultHandler, communicationHandler)
1063+
def addHandler(h: MessageHandler) = messageHandlers.synchronized { messageHandlers += h }
1064+
def removeHandler(h: MessageHandler) = messageHandlers.synchronized { messageHandlers -= h }
1065+
1066+
def invokeFromET(f: => Unit) = insert(InvokeFromET(rootNode, () => f))
1067+
1068+
/*
1069+
* message dispatcher; not really OO, but all real activity should be at the executors; other things should be passive
1070+
*/
1071+
def handle(message: CallGraphMessage[_ <: subscript.vm.CallGraphNodeTrait]):Unit =
1072+
for (h <- messageHandlers if h isDefinedAt message) h(message)
1073+
1074+
10451075
/*
10461076
* Main method of BasicExecutioner
10471077
* Handle all messages until there is nothing more to do:
@@ -1069,10 +1099,10 @@ class CommonScriptExecutor extends ScriptExecutor {
10691099
else if (!rootNode.children.isEmpty) {
10701100
messageAwaiting
10711101
synchronized { // TBD: there should also be a synchronized call in the CodeExecutors
1102+
waitsForMessage = true
10721103
if (callGraphMessageCount==0) // looks stupid, but event may have happened&notify() may have been called during tracing
1073-
synchronized {
10741104
wait() // for an event to happen
1075-
}
1105+
waitsForMessage = false
10761106
}
10771107
// note: there may also be deadlock because of unmatching communications
10781108
// so there should preferably be a check for the existence of waiting event handling actions

0 commit comments

Comments
 (0)