Asynchronous Transfer of Control

From Suhrid.net Wiki
Jump to navigationJump to search

Intro

  • An ATC is where the point of execution of one SO is changed by the action of another SO.
  • Therefore an SO may be executing on 1 method and through no action of its own, find itself executing in another method.
  • Controversial:
    • Complicates language semantics.
    • Makes it difficult to write correct code as it may be interfered with.
    • Increases complexity of the RTJVM.
    • Slow down code which does not use the feature.

Requirements for ATC

  • Fundamental requirement is for a thread to respond quickly to a condition detected by another thread.
  • Error recovery: To support coordinated error recovery between real-time threads.
    • Where several threads are performing a computation, an error detected by one thread needs to be quickly and safely communicated to other threads.
  • Mode changes: Where changes between modes are expected but cannot be planned.
    • A fault may lead to aircraft abandoning take off and entering emergency mode.
    • An accident in a manufacturing plant may required mode change to shutdown the plant.
    • Threads must be quickly and safely informed that the mode in which they are operating has changed and they now need to perform different sets of actions.
  • Scheduling using partial/imprecise computations: Many algos whose accuracy depends on how much time has been allocated to their calculation, when times up thread must be interrupted to stop refinement of result.
  • User Interrupts - Users may want to cancel current operation because they have detected an error condition and want to start again.

How to solve

  • Polling - Polling for notifications is too slow.
  • Aborts - Destroy the thread and allow another thread to perform some recovery. However destroying thread can be expensive and may be an extreme response. This can also leave system in inconsistent state (monitor locks may not be released)
  • Therefore a control form of ATC is required.

RTSJ Basic Model

  • Bring together Java exception handling and an extension of thread interruption semantics.
  • When an RTThread is interrupted an asynchronous exception is thrown at the thread rather than the thread having to poll for the interruption, like in normal Java.
  • How to program safely in the presence of asynchronous exceptions ?
  • Most exception handling mechanism have exception propagation within termination model.
    • For e.g. if a method throws an exception, then the program continues to execute in the context of the handler .. E.g. the catch block. It does not return to the context where the original exception was thrown. This makes it difficult to write code that is tolerant of an Asynchronous Exception being thrown at it.
    • This means that every method would need a handler for root class of all ASE's.
  • RTSJ solves this problem by requiring that all methods that are prepared to allow the delivery of an ASE place the ASE in their throws list.
  • These methods are called Asynchronously Interruptible (AI) methods.
  • If a method does not do this, not an AI method then the ASE is not delivered, but held pending until the SO is in a method which has the appropriate throw clause.
  • Hence code written without being concerned with ATC can be used safely in an environment where ATCs are being used.
  • To ensure ATC's are handled safely, RTSJ requires that
    • synchronized methods and synchronized blocks are ATC deferred. Such methods alongwith non-AI methods are called ATC-Deferred sections.
    • ATC's can only be handled in ACT-Deferred sections. Why? To avoid the ATC handler being interrupted by another ATC being thrown ?
  • So:
    • AI Methods allow delivery of an ATC.
    • Non-AI methods and ACT-Deferred regions allow handling of an ATC.
  • Use of ATC requires
    • AI Methods declare AsynchronouslyInterruptedException (AIE) in their throws list.
    • Throwing an AIE at a SO. How ?
      • Caling interrupt() in the RealtimeThread class throws the generic AIE.
  • Example:
import javax.realtime.*;

public class ATC1 {

	public static void main(String[] args) throws InterruptedException {
		ATC1 a = new ATC1();
		a.go();
	}
	
	private void go() throws InterruptedException {
		
		final RealtimeThread rtt = new RealtimeThread() {
			public void run() {
				try {
					longRunningComputation();
				} catch (AsynchronouslyInterruptedException aie) {
					System.out.println("Caught AIE");
				}
			}
		};
		
		rtt.start();
		
		System.out.println("Waiting for 3 secs for RTT to finish..");
		Thread.sleep(3000);
		RealtimeThread interrupter = new RealtimeThread() {
			public void run() {
				System.out.println("Interrupting RTT");
				rtt.interrupt();
			}
		};
		interrupter.start();
		
	}
	
	private void longRunningComputation() throws AsynchronouslyInterruptedException {
		long l = 0;
		for(int i=0; i < Integer.MAX_VALUE; i++) {
			l = l + i;
		}
		System.out.println(l);
	}

}

AIE Semantics

  • If t is executing in an ATC-Deferred region (means AIE cant be delivered, only handled) the AIE is marked as pending.
  • A pending AIE is delivered as soon as t returns to an AI method.
  • If t is executing in an AI method and is blocked inside a call to sleep() or join(), t is rescheduled and AIE is thrown.
  • If t is executing in an ATC deferred region and is blocked inside a call to wait(), sleep(), join() t is rescheduled and is thrown as a synchronous exception and also marked as pending.
  • Example for last case:
public class ATC1 {

	public static void main(String[] args) throws InterruptedException {
		ATC1 a = new ATC1();
		a.go();
	}
	
	private void go() throws InterruptedException {
		
		final RealtimeThread rtt = new RealtimeThread() {
			public void run() {
				try {
					launchSleep();
				} catch (AsynchronouslyInterruptedException aie) {
					System.out.println("Now the AIE is caught");
				}
			}
		};
		
		rtt.start();
		
		System.out.println("Waiting for 3 secs for RTT to finish..");
		Thread.sleep(3000);
		RealtimeThread interrupter = new RealtimeThread() {
			public void run() {
				System.out.println("Interrupting RTT");
				rtt.interrupt();
			}
		};
		interrupter.start();
		
	}
	
	private void launchSleep() throws AsynchronouslyInterruptedException {
		longRunningSleep();
		//AIE will be delivered here.
	}
	
	private void longRunningSleep() throws AsynchronouslyInterruptedException {
		try {
			Thread.sleep(10000);
		} catch (InterruptedException ie) {
			System.out.println("Interrupted from sleep"); //Wont print
		}
	}

}

Difference from Java Exception Handling

  • Only explicitly naming AIE (and not any subclass) in the throws clause indicates method is AI.
  • Therefore catch clauses also must name only the AIE.
  • Handlers for AIE's do not automatically stop the propagation of AIE's. It is necessary to call the clear method.
  • The catch clauses in ATC Deferred regions that name InterruptedException or Exception will handle an AIE, they will not stop the propagation of an AIE.
  • The catch clauses for AIE, IE and Exception in AI regions will not catch an AIE.
  • Finally clauses in AI methods are not executed when an ATC is thrown.
  • When a synchronous exception is propagating in an AI method and there is a pending AIE, the synchronous exception is lost when AIE is pending/thrown.

Catching an AIE

  • When a handler catches an AIE, it must determine if it is the same AIE as the one it expects. ( Because many different AIE's can be thrown, but catch block is for the generic AIE)
  • If it is, AIE should be handled.
  • Otherwise AIE must be propagated down the stack to the calling method.
  • The clear method is used for this purpose.

Clear Semantics

  • If the AIE is the current AIE, the AIE is no longer pending; true is returned.
  • If the AIE is not the current AIE, the AIE is still pending; false is returned.