12.07.2015 Views

Asynchronous Transfer of Control in the Real-Time ... - SIGAda

Asynchronous Transfer of Control in the Real-Time ... - SIGAda

Asynchronous Transfer of Control in the Real-Time ... - SIGAda

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Dur<strong>in</strong>g <strong>the</strong> evolution <strong>of</strong> <strong>the</strong> RTSJ o<strong>the</strong>r ATC-deferred code sections were proposed, formethodological reasons; <strong>in</strong> particular, constructors and f<strong>in</strong>ally clauses. The rationalefor consider<strong>in</strong>g such sections to be ATC-deferred was that an ATC out <strong>of</strong> a constructorcould cause <strong>in</strong>consistent global state, and an ATC out <strong>of</strong> a f<strong>in</strong>ally clause could skipneeded f<strong>in</strong>alizations. However, s<strong>in</strong>ce <strong>the</strong> programmer can decide (via <strong>the</strong> presence <strong>of</strong> a“throws AIE” clause) whe<strong>the</strong>r a constructor is AI, <strong>the</strong>re is no need for <strong>the</strong> specification tobe more constra<strong>in</strong><strong>in</strong>g. And s<strong>in</strong>ce f<strong>in</strong>ally clauses are not recognizable <strong>in</strong> <strong>the</strong> generatedbytecodes, requir<strong>in</strong>g such sections to be ATC-deferred would have affected <strong>the</strong> compiler,<strong>in</strong> violation <strong>of</strong> one <strong>of</strong> <strong>the</strong> RTSJ’s guid<strong>in</strong>g pr<strong>in</strong>ciples. Thus f<strong>in</strong>ally clauses andconstructors are not def<strong>in</strong>ed as ATC-deferred sections (but <strong>of</strong> course a f<strong>in</strong>ally clause <strong>in</strong>a context that is not AI, and a constructor lack<strong>in</strong>g a “throws AIE clause”, are ATCdeferred).4.2 Underly<strong>in</strong>g Model for ATCThere are two pr<strong>in</strong>cipal ways to specify ATC. One approach, illustrated by Ada 95[Intermetrics 95], is based on <strong>the</strong> concept <strong>of</strong> abort<strong>in</strong>g a thread. In this model <strong>the</strong>re is astatement to abort a thread and <strong>the</strong>re is also <strong>the</strong> notion <strong>of</strong> an abort-deferred region (e.g.,code that is be<strong>in</strong>g executed by a thread that is hold<strong>in</strong>g a lock). ATC is captured <strong>in</strong> aspecial control structure. A section <strong>of</strong> code that is susceptible to ATC is conceptually aseparate thread, associated with a trigger<strong>in</strong>g event such as a timeout. If <strong>the</strong> event occursbefore <strong>the</strong> separate thread term<strong>in</strong>ates, <strong>the</strong>n <strong>the</strong> thread is aborted as soon as it is outside <strong>of</strong>an abort-deferred region. If <strong>the</strong> separate thread term<strong>in</strong>ates before <strong>the</strong> event occurs, <strong>the</strong>n<strong>the</strong> event is canceled. (This is a conceptual model only; it is possible to implement ATCwith<strong>in</strong> a s<strong>in</strong>gle thread <strong>of</strong> control via a setjmp / longjmp approach. Also <strong>the</strong>re are o<strong>the</strong>rdetails, such as <strong>the</strong> execution <strong>of</strong> f<strong>in</strong>alization code before an aborted thread term<strong>in</strong>ates,that we are omitt<strong>in</strong>g.)There are several advantages to <strong>the</strong> two-thread model. S<strong>in</strong>ce it is based on <strong>the</strong> threadabort concept, no new mechanisms are needed for thread term<strong>in</strong>ation. It avoids <strong>the</strong>complications <strong>of</strong> an exception-based approach such as special rules for propagation (seebelow). And it deals with nested ATCs smoothly.However, <strong>the</strong> RTSJ did not adopt this approach, for two ma<strong>in</strong> reasons. First, <strong>the</strong>overhead <strong>of</strong> thread management for ATC, and <strong>the</strong> complexity due to <strong>in</strong>teractions with <strong>the</strong>RTSJ schedul<strong>in</strong>g framework, would have been excessive <strong>in</strong> many situations. Second, <strong>the</strong>handl<strong>in</strong>g <strong>of</strong> nested ATC would have required <strong>in</strong>troduc<strong>in</strong>g a concept <strong>of</strong> thread dependence(so that abort<strong>in</strong>g a thread implicitly aborts all <strong>of</strong> its dependents) that is o<strong>the</strong>rwise absentfrom Java and <strong>the</strong> RTSJ.Instead, <strong>the</strong> RTSJ’s ATC model is based on exceptions. Intuitively this seems a naturalapproach, especially s<strong>in</strong>ce <strong>the</strong>re is already an established syntax <strong>in</strong> Java for deal<strong>in</strong>g withsynchronous exceptions. However, captur<strong>in</strong>g ATC by simply allow<strong>in</strong>g a thread toarbitrarily throw an exception at a target thread (even with <strong>the</strong> requirement to deferthrow<strong>in</strong>g <strong>the</strong> exception when <strong>the</strong> target thread is <strong>in</strong> ATC-deferred code) would not work:• If <strong>the</strong> exception is thrown before <strong>the</strong> target thread is ready to handle it (i.e., before<strong>the</strong> target thread reaches a try statement with an applicable catch clause) or after<strong>the</strong> target thread is no longer ready to handle it (i.e. after it has completed such aPage 5


try statement) <strong>the</strong>n throw<strong>in</strong>g <strong>the</strong> exception will have <strong>the</strong> effect <strong>of</strong> term<strong>in</strong>at<strong>in</strong>g <strong>the</strong>target thread s<strong>in</strong>ce <strong>the</strong> exception will simply propagate out.• If <strong>the</strong> exception is thrown while <strong>the</strong> target thread is execut<strong>in</strong>g a try statement withan all-purpose catch clause such as for Exception or Throwable, <strong>the</strong>n it may<strong>in</strong>correctly handle <strong>the</strong> asynchronous exception. In particular if <strong>the</strong> exception issupposed to lead to <strong>the</strong> term<strong>in</strong>ation <strong>of</strong> <strong>the</strong> target thread, <strong>the</strong>n <strong>the</strong> accidentalhandl<strong>in</strong>g <strong>of</strong> this exception will prevent <strong>the</strong> target thread from term<strong>in</strong>at<strong>in</strong>g.The key po<strong>in</strong>t is to ensure that an asynchronous exception is only thrown at a threadwhen <strong>the</strong> thread has dynamically <strong>in</strong>dicated its read<strong>in</strong>ess to deal with that exception.The RTSJ supplies mechanisms at several levels to meet <strong>the</strong> requirements for ATC:• Low-level build<strong>in</strong>g blocks for detailed control <strong>of</strong> exception propagation• A higher-level construct for an idiom that hides <strong>the</strong> low-level details• A class that specifically captures <strong>the</strong> use <strong>of</strong> ATC for timeoutThe next section describes <strong>the</strong>se three mechanisms as well as o<strong>the</strong>r aspects <strong>of</strong> ATCsemantics.5 ATC SemanticsThis section presents <strong>the</strong> rules associated with ATC. These comprise both an API(classes and <strong>in</strong>terfaces <strong>in</strong> <strong>the</strong> javax.realtime package) and an extension <strong>of</strong> <strong>the</strong>semantics <strong>of</strong> exception propagation. Several k<strong>in</strong>ds <strong>of</strong> examples are presented, some toillustrate <strong>the</strong> semantics and o<strong>the</strong>rs to show typical idioms.5.1 ATC Build<strong>in</strong>g BlocksATC semantics are ultimately based on two concepts:• The <strong>in</strong>terrupt() method <strong>in</strong> class <strong>Real</strong>timeThread• The way <strong>in</strong> which an <strong>in</strong>stance <strong>of</strong> AIE is propagatedThe ma<strong>in</strong> ideas are relatively straightforward, although <strong>the</strong>re are some differences (notedbelow) from regular Java exception semantics, and perhaps <strong>the</strong> idea <strong>of</strong> an exceptionstay<strong>in</strong>g pend<strong>in</strong>g even after it has been handled is somewhat novel. The pr<strong>in</strong>cipalcomplication arises from <strong>the</strong> possibility <strong>of</strong> one ATC be<strong>in</strong>g triggered while ano<strong>the</strong>r one is<strong>in</strong> progress. Here we focus only on <strong>the</strong> case with one ATC active at a time; nested ATCis described <strong>in</strong> section 5.4.5.1.1 Basic PropertiesThe AIE class has a specific <strong>in</strong>stance, referred to as <strong>the</strong> “generic AIE <strong>in</strong>stance” (or simply<strong>the</strong> “generic AIE”), which is returned by <strong>the</strong> static method getGeneric(). Whent.<strong>in</strong>terrupt() is <strong>in</strong>voked on a <strong>Real</strong>timeThread t, this “generic” AIE becomespend<strong>in</strong>g on t. There are two possibilities:1. If t is <strong>in</strong> ATC-deferred code <strong>the</strong>n it cont<strong>in</strong>ues regular execution (which may entailthrow<strong>in</strong>g and handl<strong>in</strong>g o<strong>the</strong>r exceptions), until it enters AI code – ei<strong>the</strong>r byPage 6


eturn<strong>in</strong>g (normally or abnormally) to or call<strong>in</strong>g an AI method. At this po<strong>in</strong>t <strong>the</strong>AIE is thrown but stays pend<strong>in</strong>g. This rule has several consequences. First, if tnever <strong>in</strong>vokes or returns to an AI method, <strong>the</strong>n t will eventually term<strong>in</strong>ate without<strong>the</strong> AIE ever be<strong>in</strong>g thrown. Second, if a non-AI method attempts to propagate aregular exception back to an AI method while an AIE is pend<strong>in</strong>g, <strong>the</strong>n <strong>the</strong> regularexception is discarded and <strong>the</strong> AIE is thrown <strong>in</strong>stead.2. If t is <strong>in</strong> AI code <strong>the</strong>n <strong>the</strong> AIE is thrown immediately. However, unlike o<strong>the</strong>rexceptions, an AIE is not caught by a catch clause <strong>in</strong> AI code. Instead, controltransfers to <strong>the</strong> catch clause (for AIE or any <strong>of</strong> its ancestors) <strong>of</strong> <strong>the</strong> nearestdynamically enclos<strong>in</strong>g try statement that is <strong>in</strong> an ATC-deferred section 5 , and <strong>the</strong>AIE stays pend<strong>in</strong>g. It is important to realize that, as <strong>the</strong> stackframes for AImethods are peeled back, nei<strong>the</strong>r exception handlers nor f<strong>in</strong>ally clauses <strong>in</strong> <strong>the</strong>semethods are executed. Note that <strong>the</strong>re must be some such dynamically enclos<strong>in</strong>gtry statement, s<strong>in</strong>ce AIE is a checked exception class and <strong>the</strong> run() method <strong>in</strong><strong>Real</strong>timeThread does not have a throws clause.These rules make AIE semantics somewhat different from regular exceptions.As with <strong>the</strong> <strong>in</strong>terrupt() method <strong>in</strong> class Thread, <strong>in</strong>vok<strong>in</strong>g t.<strong>in</strong>terrupt() on a<strong>Real</strong>timeThread t will awaken t if t is blocked at a call <strong>of</strong> wait(), jo<strong>in</strong>(), orsleep(). The generic AIE will be thrown at that po<strong>in</strong>t and will be pend<strong>in</strong>g. Likewise, ift is execut<strong>in</strong>g <strong>in</strong> an ATC-deferred section when t.<strong>in</strong>terrupt() occurs, <strong>the</strong>n <strong>the</strong> genericAIE is thrown and stays pend<strong>in</strong>g when t calls one <strong>of</strong> <strong>the</strong>se block<strong>in</strong>g methods. The effectis <strong>the</strong>n as described above. Notice that <strong>the</strong> AIE will be thrown even if t is <strong>in</strong> ATCdeferredcode. (Indeed, <strong>in</strong> order for t to <strong>in</strong>voke wait() it will need to be <strong>in</strong> ATCdeferredcode s<strong>in</strong>ce it requires <strong>the</strong> lock on <strong>the</strong> object that is wait’ed.)The reason that <strong>in</strong>terrupt() is def<strong>in</strong>ed to awaken a blocked thread is to allow <strong>the</strong>programmer to avoid unbounded block<strong>in</strong>g. A potential issue arises <strong>in</strong> connection withI/O calls. Attempt<strong>in</strong>g to identify <strong>in</strong> <strong>the</strong> RTSJ which I/O methods are unblocked when<strong>in</strong>terrupted is not practical and <strong>in</strong>deed whe<strong>the</strong>r or not a call blocks (and, if it blocks,whe<strong>the</strong>r that is reasonably detectable) may be implementation dependent. The RTSJ’sposition is to require that methods <strong>in</strong> <strong>the</strong> java.io package be prevented from block<strong>in</strong>g<strong>in</strong>def<strong>in</strong>itely when <strong>in</strong>voked from an AI method. If t.<strong>in</strong>terrupt() is <strong>in</strong>voked on arealtime thread t while t is <strong>in</strong> a method from a java.io class, <strong>the</strong>n <strong>the</strong> effect isimplementation dependent: t may throw an IOException or <strong>the</strong> generic<strong>Asynchronous</strong>lyInterruptedException, or it may alternatively be allowed to cont<strong>in</strong>ueexecution if <strong>the</strong> implementation can determ<strong>in</strong>e that unbounded block<strong>in</strong>g would not occur.Handl<strong>in</strong>g an AIE does not make it non-pend<strong>in</strong>g. Once an AIE is triggered it willcont<strong>in</strong>ue to propagate up <strong>the</strong> call cha<strong>in</strong>, eventually term<strong>in</strong>at<strong>in</strong>g <strong>the</strong> thread, unless <strong>the</strong>program explicitly resets <strong>the</strong> AIE’s pend<strong>in</strong>g status. This reset is generally performed by anon-AI method <strong>in</strong> a catch clause for AIE, through <strong>the</strong> method call5 Note that if <strong>the</strong> call <strong>of</strong> <strong>the</strong> <strong>in</strong>terrupted AI method was from a synchronized block, <strong>the</strong>n <strong>the</strong> relevant catchclause might not be <strong>in</strong> synchronized code, and thus <strong>the</strong> lock will be released prematurely. However, this isno different from <strong>the</strong> situation with synchronous exceptions propagated out <strong>of</strong> synchronized blocks.Page 7


aie.happened(false) where aie is <strong>the</strong> catch clause’s exception parameter; <strong>the</strong> falseargument <strong>in</strong>dicates that propagation should not take place.A note on f<strong>in</strong>ally clauses: If an AI method has a try statement with a f<strong>in</strong>ally clause,<strong>the</strong>n <strong>the</strong> f<strong>in</strong>ally clause is executed only if no ATC is triggered while control is <strong>in</strong> <strong>the</strong> trystatement. If application logic demands that <strong>the</strong> f<strong>in</strong>ally clause be executed regardless <strong>of</strong>whe<strong>the</strong>r an ATC is triggered, <strong>the</strong>n <strong>the</strong> try statement should be taken out <strong>of</strong> l<strong>in</strong>e andplaced <strong>in</strong> a non-AI method that is called from <strong>the</strong> AI method.5.1.2 Example: AIE SemanticsHere is an artificial example that illustrates <strong>the</strong> semantics:class Frammis extends <strong>Real</strong>timeThread{public void run(){System.out.pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> run");notAI1();System.out.pr<strong>in</strong>tln("F<strong>in</strong>ish<strong>in</strong>g try <strong>in</strong> run");}void notAI1(){try{System.out.pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> notAI1");yesAI1();System.out.pr<strong>in</strong>tln("F<strong>in</strong>ish<strong>in</strong>g try <strong>in</strong> notAI1");}catch (<strong>Asynchronous</strong>lyInterruptedException aie){System.out.pr<strong>in</strong>tln("Catch<strong>in</strong>g AIE <strong>in</strong> notAI1");aie.happened(false); // Reset pend<strong>in</strong>g status}}void yesAI1() throws <strong>Asynchronous</strong>lyInterruptedException{try{System.out.pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> yesAI1");yesAI2();System.out.pr<strong>in</strong>tln("F<strong>in</strong>ish<strong>in</strong>g try <strong>in</strong> yesAI1");}catch (Exception e){System.out.pr<strong>in</strong>tln("Catch<strong>in</strong>g Exception <strong>in</strong> yesAI1");}f<strong>in</strong>ally {System.out.pr<strong>in</strong>tln("In yesAI1, f<strong>in</strong>ally");}}void yesAI2() throws <strong>Asynchronous</strong>lyInterruptedException{try{System.out.pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> yesAI2");notAI2();System.out.pr<strong>in</strong>tln("F<strong>in</strong>ish<strong>in</strong>g try <strong>in</strong> yesAI2");}catch (Exception e){System.out.pr<strong>in</strong>tln("Catch<strong>in</strong>g Exception <strong>in</strong> yesAI2");}f<strong>in</strong>ally {Page 8


System.out.pr<strong>in</strong>tln("In yesAI2, f<strong>in</strong>ally");}}void notAI2(){try{System.out.pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> notAI2");throw new RuntimeException();}f<strong>in</strong>ally{System.out.pr<strong>in</strong>tln("In notAI2, f<strong>in</strong>ally");}}public static void ma<strong>in</strong>(Str<strong>in</strong>g[] args){Frammis f = new Frammis();f.start();...f.<strong>in</strong>terrupt();...}}In this example <strong>the</strong> realtime thread f <strong>in</strong>vokes a non-AI method (run), which <strong>in</strong>vokesano<strong>the</strong>r non-AI method (notAI1), which <strong>in</strong>vokes an AI method (yesAI1), which <strong>in</strong>vokesano<strong>the</strong>r AI method (yesAI2), which <strong>in</strong>vokes ano<strong>the</strong>r non-AI method (notAI2). Theeffect depends on where f is execut<strong>in</strong>g when f.<strong>in</strong>terrupt() is <strong>in</strong>voked <strong>in</strong> ma<strong>in</strong>.• Run / notAI1 / yesAI1 / yesAI2 / notAI2 / pr<strong>in</strong>tlnThe generic AIE is made pend<strong>in</strong>g on f. When pr<strong>in</strong>tln returns, execution cont<strong>in</strong>ues <strong>in</strong>notAI2, <strong>the</strong> RuntimeException is thrown, and <strong>the</strong> f<strong>in</strong>ally block is executed.However, <strong>the</strong> generic AIE ra<strong>the</strong>r than <strong>the</strong> RuntimeException is propagated back toyesAI2. S<strong>in</strong>ce AIEs are not caught <strong>in</strong> AI code, <strong>the</strong> exception is immediately propagatedback to <strong>the</strong> closest dynamically enclos<strong>in</strong>g ATC-deferred section, namely <strong>the</strong> po<strong>in</strong>t after<strong>the</strong> <strong>in</strong>vocation <strong>of</strong> yesAI1 <strong>in</strong> notAI1. The generic AIE is thrown <strong>the</strong>re (still pend<strong>in</strong>g), andis handled by <strong>the</strong> catch block <strong>in</strong> notAI1. S<strong>in</strong>ce <strong>the</strong> propagation parameter to happenedis false, <strong>the</strong> AIE is marked non-pend<strong>in</strong>g. 6 <strong>Control</strong> returns normally to <strong>the</strong> run method,which eventually returns. The follow<strong>in</strong>g will be <strong>the</strong> output:Enter<strong>in</strong>g try <strong>in</strong> runEnter<strong>in</strong>g try <strong>in</strong> notAI1Enter<strong>in</strong>g try <strong>in</strong> yesAI1Enter<strong>in</strong>g try <strong>in</strong> yesAI2Enter<strong>in</strong>g try <strong>in</strong> notAI2In notAI2, f<strong>in</strong>allyCatch<strong>in</strong>g AIE <strong>in</strong> notAI1F<strong>in</strong>ish<strong>in</strong>g try <strong>in</strong> run• Run / notAI1/ pr<strong>in</strong>tln("Enter<strong>in</strong>g try <strong>in</strong> notAI1")6 This usage <strong>of</strong> happened() assumes that no o<strong>the</strong>r attempt to trigger an ATC <strong>in</strong> f will occur while <strong>the</strong>process<strong>in</strong>g <strong>of</strong> f.<strong>in</strong>terrupt() is <strong>in</strong> progress. Section 5.4 shows how to deal with nested ATCs.Page 9


Here <strong>the</strong> ATC is triggered before <strong>the</strong> thread reaches AI code. The generic AIE is markedpend<strong>in</strong>g on f, and f cont<strong>in</strong>ues normal execution until it <strong>in</strong>vokes yesAI1. At this po<strong>in</strong>t <strong>the</strong>AIE is thrown (and it is still pend<strong>in</strong>g). <strong>Control</strong> passes to <strong>the</strong> catch block <strong>in</strong> notAI1, <strong>the</strong>happened method resets <strong>the</strong> pend<strong>in</strong>g status <strong>of</strong> <strong>the</strong> AIE, and control returns to run. Therun method returns normally.Note that if <strong>the</strong> argument to happened were true ra<strong>the</strong>r than false, <strong>the</strong> effects wouldhave been almost <strong>the</strong> same. The only difference, which would have been unobservable,is that run would have returned with an AIE pend<strong>in</strong>g.5.1.3 Example: Trigger<strong>in</strong>g an AIE from an AsyncEventHandlerHere is a more realistic example. A realtime thread creates a one-shot timer whoseexpiry will cause an ATC. This illustrates how an AsyncEventHandler can trigger anATC.class <strong>Time</strong>outExample extends <strong>Real</strong>timeThread{<strong>Real</strong>timeThread target;static class AtcTrigger extends AsyncEventHandler{AtcTrigger(<strong>Real</strong>timeThread target; Runnable logic){// target is <strong>the</strong> thread to be <strong>in</strong>terrupted// logic.run is <strong>the</strong> handlerAsyncEventHandler( logic );this.target=target;}void <strong>in</strong>terruptibleCode() throws <strong>Asynchronous</strong>lyInterruptedException{... // <strong>in</strong>terruptible stuff}public void run(){OneShot<strong>Time</strong>r ost =new OneShot<strong>Time</strong>r(new Relative<strong>Time</strong>( 5000, 0 ), // 5 secondsnew AtcTrigger( // async event handlerthis, // target to be <strong>in</strong>terruptednew Runnable(){public void run(){this.target.<strong>in</strong>terrupt();})));try{<strong>in</strong>terruptibleCode();}catch (<strong>Asynchronous</strong>lyInterruptedException aie){... // code that runs if timer firesaie.happened(false);}f<strong>in</strong>ally{ost.destroy();}}public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]){<strong>Time</strong>outExample te = new <strong>Time</strong>outExample();Page 10


<strong>of</strong> <strong>the</strong> run() method is abandoned (as soon as run() is <strong>in</strong> an AI section) andi.<strong>in</strong>terruptAction(aie) is <strong>in</strong>voked.A source thread needs to trigger this activity by <strong>in</strong>vok<strong>in</strong>g aie.fire(). (Thus <strong>the</strong> sourcethread needs <strong>the</strong> reference to <strong>the</strong> AIE; this would typically be passed <strong>in</strong> a constructor for<strong>the</strong> source thread.) Invok<strong>in</strong>g aie.fire() too early (before aie.doInterruptible()has been called) or too late (after aie.doInterruptible() has returned) have no effect.In essence, when a realtime thread t <strong>in</strong>vokes aie.doInterruptible(), t’s currentstackframe is marked as <strong>the</strong> “owner” <strong>of</strong> <strong>the</strong> AIE. To avoid implementation complexity, agiven AIE can be owned by only one stackframe at a time. If aie.doInterruptible is<strong>in</strong>voked while some o<strong>the</strong>r <strong>in</strong>vocation <strong>of</strong> <strong>the</strong> same call is <strong>in</strong> progress, <strong>the</strong>n <strong>the</strong> second callhas no effect 7 .Note that <strong>the</strong> exception handl<strong>in</strong>g and propagation <strong>in</strong>herent <strong>in</strong> ATC is transparent to aprogram that uses fire() and doInterruptible(). The implementation <strong>of</strong>doInterruptible must manage <strong>the</strong> asynchronous exception by <strong>in</strong>vok<strong>in</strong>g<strong>in</strong>terruptAction to handle <strong>the</strong> exception and by mak<strong>in</strong>g <strong>the</strong> AIE non-pend<strong>in</strong>g.Here is a skeletal example that illustrates this style:class Foo extends <strong>Real</strong>timeThread{<strong>Asynchronous</strong>lyInterruptedException aie;Foo( <strong>Asynchronous</strong>lyInterruptedException aie ){this.aie = aie;}public static void run(){... // Non<strong>in</strong>terruptible codeaie.doInterruptible(new Interruptible(public void run(<strong>Asynchronous</strong>lyInterruptedException e )throws <strong>Asynchronous</strong>lyInterruptedException{... // <strong>in</strong>terruptible code}public void <strong>in</strong>terruptAction(<strong>Asynchronous</strong>lyInterruptedException e ){... // code that executes if run() is <strong>in</strong>terrupted}));}public static void ma<strong>in</strong>( Str<strong>in</strong>g[] args ){<strong>Asynchronous</strong>lyInterruptedException aie =new <strong>Asynchronous</strong>lyInterruptedException()Foo foo = new Foo( aie );Bar bar = new Bar( aie );foo.start();bar.start();7 The doInterruptible method returns a boolean result that normally will be true. It is false if ano<strong>the</strong>r<strong>in</strong>vocation <strong>of</strong> doInterruptible on <strong>the</strong> same AIE is <strong>in</strong> progress for any thread.Page 12


}}class Bar extends <strong>Real</strong>timeThread{<strong>Asynchronous</strong>lyInterruptedException aie;}Bar(<strong>Asynchronous</strong>lyInterruptedException aie ){this.aie = aie;}public static void run(){...aie.fire(); // <strong>in</strong>terrupts foo if foo is <strong>in</strong> doInterruptible...}Note that <strong>the</strong> “throws AIE” clause on <strong>the</strong> run() method def<strong>in</strong>ed <strong>in</strong> <strong>the</strong> anonymousInterrupible class is essential; without it, <strong>the</strong> method will not be AI.Us<strong>in</strong>g doInterruptible allows f<strong>in</strong>e-gra<strong>in</strong>ed control over asynchronous <strong>in</strong>terruptibility<strong>of</strong> <strong>the</strong> Interruptible’s run() method, <strong>in</strong> particular <strong>the</strong> ability to turn any sequence <strong>of</strong>code <strong>in</strong>to an ATC-deferred section. This is accomplished by call<strong>in</strong>g e.disable() andsubsequently e.enable() from run() where e is <strong>the</strong> AIE parameter to run(). Ifaie.fire() is <strong>in</strong>voked while a thread is execut<strong>in</strong>g <strong>the</strong> run() method <strong>of</strong> <strong>the</strong>Interruptible passed to aie.doInterruptible, after disable() has been <strong>in</strong>vokedbut before <strong>the</strong> match<strong>in</strong>g enable() has been reached, <strong>the</strong>n <strong>the</strong> AIE is made pend<strong>in</strong>g. Itwill be thrown (and stay pend<strong>in</strong>g, with <strong>the</strong> usual semantics) after it is enabled. Theenable() and disable() methods return boolean results. Normally <strong>the</strong> result for eachwill be true; it is false if <strong>the</strong> method is not <strong>in</strong>voked with<strong>in</strong> a dynamically enclos<strong>in</strong>g call<strong>of</strong> doInterruptible on <strong>the</strong> same AIE; <strong>in</strong> such a case <strong>in</strong>vok<strong>in</strong>g enable() or disable()has no effect.Here’s an example <strong>of</strong> disable() and enable(), shown as a variation <strong>of</strong> <strong>the</strong> run()method from class Foo above:public static void run(){... // Non<strong>in</strong>terruptible codeaie.doInterruptible(new Interruptible(public void run(<strong>Asynchronous</strong>lyInterruptedException e)throws <strong>Asynchronous</strong>lyInterruptedException{... // <strong>in</strong>terruptible codee.disable();... // non-<strong>in</strong>terruptible codee.enable();... // <strong>in</strong>terruptible code}public void <strong>in</strong>terruptAction(<strong>Asynchronous</strong>lyInterruptedException e ){... // code that executes if run() is <strong>in</strong>terrupted})Page 13


});5.3 The <strong>Time</strong>d ClassSection 5.1.3 illustrated programm<strong>in</strong>g a timeout us<strong>in</strong>g <strong>in</strong>terrupt() from anAsyncEventHandler associated with a OneShot<strong>Time</strong>r. S<strong>in</strong>ce timeouts are a commonrequirement, <strong>the</strong> RTSJ provides a way to obta<strong>in</strong> <strong>the</strong> needed functionality <strong>in</strong> a notationallymore convenient fashion, namely <strong>the</strong> <strong>Time</strong>d class, which extends AIE. This class has aconstructor that takes a HighResolution<strong>Time</strong> argument. Call<strong>in</strong>gtimed.doInterruptible(i) on a <strong>Time</strong>d object timed supplies <strong>in</strong> <strong>the</strong> Interruptibleparameter i both <strong>the</strong> code that is susceptible to <strong>in</strong>terruption and <strong>the</strong> code that is toexecute <strong>in</strong> response to <strong>the</strong> timeout. Here is how <strong>the</strong> earlier example can be expressed:class <strong>Time</strong>outExample extends <strong>Real</strong>timeThread{public void run(){new <strong>Time</strong>d(new Relative<strong>Time</strong>( 5000, 0 )).doInterruptible(new Interruptible(){public void run(<strong>Asynchronous</strong>lyInterruptedException e)throws <strong>Asynchronous</strong>lyInterruptedException{... // code that is asynchronously <strong>in</strong>terruptible}public void <strong>in</strong>terruptAction(<strong>Asynchronous</strong>lyInterruptedException e){... // code that runs if timeout occurs});}public static void ma<strong>in</strong>(Str<strong>in</strong>g args[]){<strong>Time</strong>outExample te = new <strong>Time</strong>outExample();te.start();}}5.4 Nested ATCsA complication with ATC is to properly deal with <strong>the</strong> situation where a second ATC istriggered while a first one is <strong>in</strong> progress. For example, suppose that a realtime thread setsa 500 msec timeout on some AI code. That code calls a method foo() that <strong>in</strong>ternally setsa 700 msec timeout on ano<strong>the</strong>r AI section. If <strong>the</strong> 500 msec expires when <strong>the</strong> thread isexecut<strong>in</strong>g <strong>in</strong> foo(), <strong>the</strong>n several th<strong>in</strong>gs need to happen:• The 700 msec timer needs to be canceled• The AIE for <strong>the</strong> 500 msec timer needs to propagate back to <strong>the</strong> scope that “owns”it (based on <strong>the</strong> semantics <strong>of</strong> 5.1), where it can be handledThese effects are obta<strong>in</strong>ed when <strong>the</strong> programmer uses ei<strong>the</strong>r doInterruptible() or its“syntactic sugar” <strong>the</strong> <strong>Time</strong>d class. In particular, <strong>the</strong> RTSJ def<strong>in</strong>es a level for each eachAIE. When a realtime thread <strong>in</strong>vokes aie.doInterruptible, <strong>the</strong>n <strong>the</strong> level <strong>of</strong> aie isPage 14


<strong>the</strong> dynamic nest<strong>in</strong>g level <strong>of</strong> <strong>the</strong> <strong>in</strong>vok<strong>in</strong>g method or constructor. (The run() method isat level 1, and any method or constructor directly or <strong>in</strong>directly <strong>in</strong>voked from run() has anest<strong>in</strong>g level 1 greater than that <strong>of</strong> its <strong>in</strong>voker.) Before aie.doInterrupuble is <strong>in</strong>vokedand after it returns, <strong>the</strong> nest<strong>in</strong>g level <strong>of</strong> aie is undef<strong>in</strong>ed. The “generic AIE” is def<strong>in</strong>ed tohave level 0.Suppose that aie new .fire() is <strong>in</strong>voked while aie old is pend<strong>in</strong>g on <strong>the</strong> thread that<strong>in</strong>voked aie new .doInterruptible. Intuitively, <strong>the</strong> AIE at <strong>the</strong> shallower level is <strong>the</strong> onethat should be used. Thus if <strong>the</strong> level <strong>of</strong> aie old is less than or equal to <strong>the</strong> level <strong>of</strong> aie new ,aie new is ignored. (This could correspond to a situation where an <strong>in</strong>ner timer goes <strong>of</strong>fwhile an outer timeout is propagat<strong>in</strong>g to its handler.) If <strong>the</strong> level <strong>of</strong> aie new is less than <strong>the</strong>level <strong>of</strong> aie old , <strong>the</strong>n aie new replaces aie old as <strong>the</strong> pend<strong>in</strong>g AIE.The rules give precedence to <strong>the</strong> generic AIE triggered by <strong>in</strong>terrupt() – it has priorityover all o<strong>the</strong>r AIEs – s<strong>in</strong>ce this is typically used to arrange “immediate” threadterm<strong>in</strong>ation.Note that <strong>the</strong>re is a potential race condition that programmers need to be alert to.Suppose that a thread is about to handle an AIE, but between <strong>the</strong> time that <strong>the</strong> catchclause is selected and control enters <strong>the</strong> associated handler, <strong>the</strong> AIE has been replaced byano<strong>the</strong>r one at a shallower level. The handler should recognize this situation andpropagate <strong>the</strong> new AIE. This effect can be realized through <strong>the</strong> aie.happened()method, which returns a boolean: true if aie is <strong>the</strong> AIE that is currently pend<strong>in</strong>g (<strong>the</strong>typical situation) but false if not (aie has been replaced by a different AIE). Forexample:void foo(){try{<strong>in</strong>terruptibleCode(); // method that throws AIE}catch ( <strong>Asynchronous</strong>lyInterruptedException aie ){if (happened(false)){// The AIE that was thrown is still <strong>the</strong> current one// Handle it now and turn <strong>of</strong>f its propagation...} else {// New AIE has occurred, so let it propagate<strong>Asynchronous</strong>lyInterruptedException.propagate();}}}The static method <strong>Asynchronous</strong>lyInterruptedException.propagate() keeps <strong>the</strong>pend<strong>in</strong>g status <strong>of</strong> <strong>the</strong> currently pend<strong>in</strong>g AIE, thus caus<strong>in</strong>g it to propagate. Actually this isnot needed s<strong>in</strong>ce by default <strong>the</strong> new AIE stays pend<strong>in</strong>g, but <strong>in</strong>clud<strong>in</strong>g it makes clearerthat <strong>the</strong> propagation is <strong>in</strong>tentional.Page 15


6 Implementation Model6.1 Implementation RequirementsThe implementation <strong>of</strong> ATC <strong>in</strong> <strong>the</strong> Reference Implementation (RI) for <strong>the</strong> RTSJ is<strong>in</strong>tended only as a pro<strong>of</strong>-<strong>of</strong>-concept design. Efficiency was a secondary concern relativeto its clarity. Indeed, obvious optimizations have been specifically left out <strong>of</strong> <strong>the</strong> RI tomake <strong>the</strong> code more clear. Implementors can choose ei<strong>the</strong>r to use <strong>the</strong> basic RI design andto add desired improvements, or to use totally different approaches that impose little orno overhead.6.2 Implementation DesignThe basic premise <strong>of</strong> <strong>the</strong> RI ATC model is to poll for a flag <strong>in</strong> <strong>the</strong> thread context with alow-cost operation after every bytecode. In pr<strong>in</strong>ciple <strong>the</strong> Java programmer could obta<strong>in</strong> asimilar effect by <strong>in</strong>vok<strong>in</strong>g Thread.<strong>in</strong>terrupted() after each statement, but this wouldbe stylistically gruesome and also ra<strong>the</strong>r expensive. The RI approach operates at a muchf<strong>in</strong>er granularity and with lower cost (a sav<strong>in</strong>gs <strong>of</strong> many hundreds <strong>of</strong> bytecodes comparedwith explicit user-level poll<strong>in</strong>g).There are always two threads <strong>in</strong>volved <strong>in</strong> ATC, <strong>the</strong> poster (<strong>the</strong> thread call<strong>in</strong>gaie.fire() or realtimeThread.<strong>in</strong>terrupt()) and <strong>the</strong> target (<strong>the</strong> thread that willreceive <strong>the</strong> AIE). Given <strong>the</strong> poll<strong>in</strong>g-based design, <strong>the</strong> poster does very little work. Afteracquir<strong>in</strong>g a mutex on <strong>the</strong> target thread <strong>the</strong> poster checks to see if an AIE is currentlypend<strong>in</strong>g on <strong>the</strong> target. If <strong>the</strong> poster’s AIE is <strong>of</strong> higher precedence or <strong>the</strong>re is no pend<strong>in</strong>gAIE, <strong>the</strong> reference to <strong>the</strong> AIE is copied <strong>in</strong>to <strong>the</strong> target’s context as <strong>the</strong> pend<strong>in</strong>g AIE.The target thread executes a macro after every bytecode that checks for a posted AIE. Inthis sense, <strong>in</strong> this implementation, each bytecode <strong>in</strong>struction can be thought <strong>of</strong> ascompris<strong>in</strong>g a deferred section (because <strong>the</strong> AIE is <strong>in</strong>itially set to pend<strong>in</strong>g) followed by anondeferred section (<strong>the</strong> poll, which moves <strong>the</strong> AIE out <strong>of</strong> pend<strong>in</strong>g). The macroeffectively implements:if( ){if( ){;}}Note that this approach yields near m<strong>in</strong>imal latency. The target thread will respond to <strong>the</strong><strong>in</strong>terrupt after execut<strong>in</strong>g at most one <strong>in</strong>terven<strong>in</strong>g bytecode <strong>in</strong>struction.The monitorenter and monitorexit bytecodes, as well as <strong>the</strong> method <strong>in</strong>vocationbytecodes, have been adjusted to alter <strong>the</strong> deferred state, associated with <strong>the</strong> stack frame(<strong>the</strong> method <strong>in</strong>vocation), as appropriate. Thus <strong>the</strong> poster need not concern itself with <strong>the</strong>deferred context <strong>of</strong> <strong>the</strong> target.The method <strong>in</strong>vocation and return bytecodes manage <strong>the</strong> call<strong>in</strong>g thread’s <strong>in</strong>terruptiblestate by stor<strong>in</strong>g <strong>the</strong> current state <strong>in</strong> <strong>the</strong> stack frame at method <strong>in</strong>vocation, and <strong>the</strong>nrestor<strong>in</strong>g it on return.Page 16


Bibliography[Bollella et. al. 2000] Greg Bollella, James Gosl<strong>in</strong>g, Ben Brosgol, Peter Dibble, SteveFurr, David Hard<strong>in</strong>, Mark Turnbull; The <strong>Real</strong>-<strong>Time</strong> Specification for Java, Addison-Wesley, 2000.[Chan et. al. 1998] Patrick Chan, Rosanna Lee, Douglas Kramer; The Java ClassLibraries Second Edition, Volume 1; Addison-Wesley, 1998.[Gosl<strong>in</strong>g et. al. 2000] James Gosl<strong>in</strong>g, Bill Joy, Guy Steele, Gilad Bracha; The JavaLanguage Specification Second Edition, Addison-Wesley, 2000.[Intermetrics 95] Intermetrics, Inc., Ada Reference Manual, International StandardANSI/ISO/IEC-8652:1995, January 1995.[JSR-1 2001] Java Specification Request JSR-00001, The <strong>Real</strong>-<strong>Time</strong> Specification forJava, November 2001.Page 18

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!