Asynchrony This section contains classes that manage asynchrony.

See:
          Description

Packages
javax.realtime  

 

Asynchrony

This section contains classes that manage asynchrony. They:

Definitions

The following terms and abbreviations will be used:

AE - Asynchronous Event.  An instance of the javax.realtime.AsyncEvent class.

AEH - Asynchronous Event Handler. An instance of the javax.realtime.AsyncEventHandler class.

Bound AEH  - Bound Asynchronous Event Handler. An instance of the javax.realtime.BoundAsyncEventHandler class.

ATC - Asynchronous Transfer of Control.

AIE - Asynchronously Interrupted Exception. An instance of javax.realtime.AsynchronouslyInterruptedException class (a subclass of java.lang.InterruptedException).

AI-method - Asynchronously Interruptible method. A method or constructor  that includes AsynchronouslyInterruptedException explicitly (that is not a subclass of AsynchronouslyInterruptedException) in its throws clause.

A happening is an event that takes place outside the Java runtime environment. The triggers for happenings depend on the external environment, but happenings might include signals and interrupts.

Lexical Scope [of a method, constructor, or statement]. The textual region within the constructor, method, or statement, excluding the code within any class declarations, and the code within any class instance creation expressions for anonymous classes, contained therein. The lexical scope of a construct does not include the bodies of any methods or constructors that this code invokes.

ATC-deferred section. A synchronized statement, a static initializer or any method or constructor without AsynchronouslyInterruptedException in its throws clause. As specified in the introduction to Chapter 8 in Java Language Specification, a synchronized method is equivalent to a non-synchronized method with the body of the method contained in a synchronized statement. Thus, a synchronized AI method behaves like an AI method containing only an ATC-deferred statement.

Interruptible blocking methods. The RTSJ and standard Java methods that are explicitly interruptible by an AIE. The interruptible blocking methods comprise HighResolutionTime.waitForObject(), Object.wait(), Thread.sleep(), RealtimeThread.sleep(), Thread.join(), ScopedMemory.join(), ScopedMemory.joinAndEnter(), RealtimeThread.waitForNextPeriodInterruptible(), WaitFreeWriteQueue.read(), WaitFreeReadQueue.waitForData(), WaitFreeReadQueue.write(), WaitFreeDequeue.blockingRead(), WaitFreeDequeue.blockingWrite() and their overloaded forms.

Overview

This specification provides several facilities for arranging asynchronous control of execution. These facilities fall into two main categories: asynchronous event handling and asynchronous transfer of control, which includes real-time thread termination.

Asynchronous event handling is captured by the classes AsyncEvent (AE), AsyncEventHandler (AEH) and BoundAsyncEventHandler. An AE is an object used to direct event occurrences to asynchronous event handlers. An event occurrence may be initiated by application logic, by mechanisms internal to the RTSJ implementation (see the handlers in PeriodicParameters), or by the triggering of a happening external to the JVM (such as a software signal or a hardware interrupt handler). An event occurrence is initiated in program logic by the invocation of the fire() method of an AE. The triggering of an event  due to a happening is implementation dependent except as specified in POSIXSignalHandler,

An AEH  is a schedulable object embodying code that is released for execution in response to the occurrence of an associated event. Each AEH behaves as if it is executed by a RealtimeThread or NoHeapRealtimeThread except that it is not permitted to use the waitForNextPeriod() or waitForNextPeriodInterruptible() methods, and it is treated as having a null thread group in all cases. There is not necessarily a separate real-time thread for each AEH, but the server real-time thread (returned by currentRealtimeThread()) remains constant during each execution of the run() method. The class BoundAsyncEventHandler extends AsyncEventHandler and ensures that a handler has a dedicated server real-time thread (a server thread is associated with one and only one bound AEH for the lifetime of that AEH). An event count (called fireCount) is maintained so that a handler can cope with event bursts - situations where an event occurs more frequently than its handler can respond.

The interrupt() method in java.lang.Thread provides rudimentary asynchronous communication by setting a pollable/resettable flag in the target thread, and by throwing a synchronous exception when the target thread is blocked at an invocation of wait(), sleep(), or join(). This specification extends the effect of Thread.interrupt() by adding an overridden version in RealtimeThread, offering a more comprehensive and non-polling asynchronous execution control facility. It is based on throwing and propagating exceptions that, though asynchronous, are deferred where necessary in order to avoid data structure corruption. The main elements of ATC are embodied in the class AsynchronouslyInterruptedException, its subclass Timed, the interface Interruptible, and in the semantics of the interrupt method in RealtimeThread.

A method indicates its eligibility to be asynchronously interrupted by including the checked exception AsynchronouslyInterruptedException in its throws clause. If a schedulable object is asynchronously interrupted while executing such a method, then an AIE will be delivered as soon as the schedulable object is outside of a section in which ATC is deferred. Several idioms are available for handling an AIE, giving the programmer the choice of using catch clauses and a low-level mechanism with specific control over propagation, or a higher-level facility that allows specifying the interruptible code, the handler, and the result retrieval as separate methods.

Semantics and Requirements for Asynchronous Events and their Handlers

This following list establishes the semantics and requirements that are applicable to asynchronous events and their handlers.  Semantics that apply to particular classes, constructors, methods, and fields will be found in the class description and the constructor, method, and field detail sections.
  1. When an asynchronous event  occurs (by either program logic or by the triggering of a happening), its attached handlers (that is, AEHs that have been added to the AE by the execution of addHandler()) are released for execution. Every occurrence of an event increments the fireCount in each attached handler. Handlers may elect to execute logic for each occurrence of the event or not.
  2. The release of attached handlers occurs in execution eligibility order (priority order with the default PriorityScheduler) and at the active priority of the schedulable object that invoked the fire method. The release of handlers resulting from a happening or a timer must begin within a bounded time (ignoring time consumed by unrelated activities in the system). This worst-case response interval must be documented for some reference architecture.
  3. The release of attached handlers is an atomic operation with respect to adding and removing handlers.
  4. The logical release of an attached handler may occur before the previous release has completed.
  5. A deadline may be associated with each logical release of an attached handler. The deadline is relative to the occurrence of the associated event.
  6. AEs and AEHs may be created and used by any program logic within the constraints of the memory assignment rules.
  7. More than one AEH may be added to an AE. However, adding an AEH to an AE has no effect if the AEH is already attached to the AE.
  8. The same AEH may be added to more than one AE.
  9. More than one happening may be associated with the same AE, however, binding a happening to an AE has no effect if it is already attached to the AE.
  10. By default all AEHs are considered to be daemons (the daemon status being set by their constructors). An AEH can be set to have a non daemon status after it has been created and before it has been attached to an AE.
  11. The object returned by currentRealtimeThread() while an AEH is running shall behave with respect to memory access and assignment rules as if it were allocated in the same memory area as the AEH.
An RTSJ program terminates when and only when

Semantics and Requirements for Asynchronous Transfer of Control

Asynchronously interrupting a schedulable object consists of the following activities. Between the generation and delivery, the asynchronous interrupt exception is held pending. After delivery, the AIE remains pending until it is cleared  by the program logic using clear(), happened() or doInterruptible().

This following list establishes the semantics and requirements that are applicable to ATC. Semantics that apply to particular classes, constructors, methods, and fields will be found in the class description and the constructor, method, and field detail sections.

  1. An AIE is generated for a given schedulable object, when the fire() method is called on an AIE for which the schedulable object is executing within the doInterruptible() method, or the RealtimeThread.interrupt() method is called; the latter is effectively called when an AIE is generated by internal virtual machine mechanisms (such as an interrupt I/O protocol) that are asynchronous to the execution of program logic which is the target of the AIE.  A generated AIE becomes pending upon generation and remains pending until explicitly cleared or replaced by another AIE.
  2. The RealtimeThread.interrupt() method throws the generic AIE at the target real-time thread and has the behaviors defined for Thread.interrupt(). This is the only interaction between the ATC mechanism and the conventional interrupt() mechanism.
  3. An AIE is delivered to a schedulable object when it is executing in an AI-method except as indicated below.
  4. The generation of an AIE through the fire() mechanism behaves as if it set an asynchronously-interrupted status in the schedulable object. If the schedulable object is blocked within an interruptible blocking method, or invokes an interruptible blocking method, when this asynchronously-interrupted status is set, then the invocation immediately completes by throwing the pending AIE and clearing the asynchronously-interrupted status. When a pending AIE is explicitly cleared then the asynchronously-interrupted status is also cleared.
  5. Methods which block through mechanisms other than the interruptible blocking methods, (for example, blocking methods in java.io.*) must be prevented from blocking indefinitely when invoked from a method with AsynchronouslyInterruptedException in its throws clause. When an AIE is generated and the target schedulable object's control is blocked inside one of these methods invoked from an AI-method, the implementation may either unblock the blocked call, raise an InterruptedIOException on behalf of the call, or allow the call to complete normally if the implementation determines that the call would eventually unblock.
  6. If an AI-method is attempting to acquire an object lock when an associated AIE is generated, the attempt to acquire the lock is abandoned.
  7. If control is in the lexical scope of an ATC-deferred section when an AIE (targeted at the executing schedulable object) is generated, the AIE is not delivered until the first subsequent attempt to transfer control to code that is not ATC-deferred. At that point, control is transferred to the catch or finally clause of the nearest dynamically-enclosing a try statement that has a handler for the generated AIE's (that is a handler naming the AIE's class or any of its superclasses, or a finally clause) and which is in an ATC-deferred section.   Intervening handlers and finally clauses that are not in ATC-deferred sections are not executed, but object locks are released.  See section 11.3 of The Java Language Specification second edition for an explanation of the terms, dynamically enclosing and handler. The RTSJ uses those JLS definitions unaltered. Note, if synchronized code is abandoned as a result of this control transfer, the associated locks are released.
  8. Constructors are allowed to include AsynchronouslyInterruptedException in their throws clause and if they do will be asynchronously interruptible under the same conditions as AI methods.
  9. Native methods that include AsynchronouslyInterruptedException in their throws clause have implementation-specific behavior.
  10. An implementation must deliver the transfer of control in a schedulable object that is subject to asynchronous interruption (in an AI-method but not in a synchronized block) within a bounded execution time of that schedulable object. This worst-case response interval must be documented for some reference architecture.
  11. Instances of the Timed class logically have an associated timer.  When the timer fires, the schedulable object executing the instance's doInterruptible method must have the AIE generated within a bounded execution time of the schedulable object. This worst-case response interval must be documented for some reference architecture.
  12. An AIE only has the semantics defined here if it originates with the AsynchronouslyInterruptedException.fire() method, the RealtimeThread.interrupt() method or from within the real-time VM. If an AIE is thrown from program logic using the Java throw statement, it acts the same as throwing any other instance of a subclass of Exception, it is processed as a normal exception, and has no affect on the pending state of any AIE, and no affect on the firing of the AIE concerned.

Summary of ATC Operation

The RTSJ's approach to ATC is designed to follow the above principles. It is based on exceptions and is an extension of the current Java language rules for java.lang.Thread.interrupt(). In summary, ATC works as follows:

If so is an instance of a schedulable object  and  the interrupt() method is called on the real-time thread associated with that object (in this context, the associated real-time thread of an AEH is the real-time thread returned by a call of the RealtimeThread.currentRealtimeThread() method by that AEH) then:

  1. If control is in an ATC-deferred section, then the AIE remains in a pending state.
  2. If control is not in an ATC-deferred section, then control is transferred to the catch or finally clause of the nearest dynamically-enclosing a try statement that has a handler for the generated AIE's (that is a handler naming the AIE's class or any of its superclasses, or a finally clause) and which is in an ATC-deferred section.   Intervening handlers and finally clauses that are not in ATC-deferred sections are not executed, but objects locks are released.  See section 11.3 of The Java Language Specification second edition for an explanation of the terms, dynamically enclosing and handles. The RTSJ uses those definitions unaltered.
  3. If control is in an interruptible blocking method the schedulable object is awakened and the generated AIE (which is a subclass of InterruptedException) is thrown with regular Java semantics  (the AIE is still marked as pending). Then ATC follows option 1, or 2 as appropriate. 
  4. If control is in an ATC-deferred section, control continues normally until the first attempt to return to an AI method or invoke an AI method or exit a synchronized block within an AI method. Then ATC follows option 1, or 2 as appropriate.
  5. If control is transferred from an ATC-deferred section to an AI method through the action of propagating an exception and if an AIE is pending then when the transition to the AI-method occurs, the thrown exception is discarded and replaced by the AIE.
An AIE may be generated while another AIE is pending. Because AI code blocks are nested by method invocation (a stack-based nesting) there is a natural precedence among active instances of AIE. Let AIE0 be the AIE raised when the RealtimeThread.interrupt() method is invoked and AIE i (i = 1,...,n, for n unique instances of AIE) be the AIE generated when AIE. fire() is invoked. In the following, the phrase "a frame deeper on the stack than this frame" refers to a method nearer to the current stack frame. The phrase  "a frame shallower on the stack than this frame" refers to a method further from the current stack frame.
  1. If the current AIE is an AIE0 and the new AIE is an AIE x associated with any frame on the stack then the new AIE (AIE x) is discarded.
  2. If the current AIE is an AIEx and the new AIE is an AIE 0, then the current AIE (AIEx) is replaced by the new AIE (AIE0).
  3. If the current AIE is an AIEx and the new AIE is an AIE y from a frame deeper on the stack, then the new AIE (AIE y) discarded.
  4. If the current AIE is an AIEx and the new AIE is an AIE y from a frame shallower on the stack, the current AIE (AIE x) is replaced by the new AIE (AIEy).
  5. If the current AIE is an AIE0 and the new AIE is an AIE 0, or if the current AIE is an AIEx  and the new AIE is an AIEx, the new AIE is discarded.
When clear() or happened() is called on a pending AIE or that AIE is superseded by another, the first AIE's pending state is cleared. If the happened() method is called on a non-pending AIE the result depends on the value of the propagate parameter, as indicated in the "No Match" column of the table below. Clearing a non-pending AIE (with the clear() method) has no effect.
    Match
    No Match
    propagate == true clear the pending AIE, 
    return true
    the AIE remains pending, propagate
    propagate == false clear the pending AIE, 
    return true
    the AIE remains pending, return false

Rationale

The design of the asynchronous event handling facilities was intended to provide the necessary functionality while allowing efficient implementations and catering for a variety of real-time applications. In particular, in some real-time systems there may be a large number of potential events and event handlers (numbering in the thousands or perhaps even the tens of thousands), although at any given time only a small number will be used. Thus it would not be appropriate to dedicate a real-time thread to each event handler. The RTSJ addresses this issue by allowing the programmer to specify an event handler either as not bound to a specific real-time thread (the class AsyncEventHandler) or alternatively as bound to a dedicated real-time thread (the class BoundAsyncEventHandler). The RTSJ does not define at what point a non-bound event handler is bound to a real-time thread for its execution.

Events are dataless: the fire method does not pass any data to the handler. This was intentional in the interest of simplicity and efficiency. An application that needs to associate data with an AsyncEvent can do so explicitly by setting up a buffer; it will then need to deal with buffer overflow issues as required by the application.

The ability to trigger an ATC in a schedulable object is necessary in many kinds of real-time applications but must be designed carefully in order to minimize the risks of problems such as data structure corruption and deadlock. There is, invariably, a tension between the desire to cause an ATC to be immediate, and the desire to ensure that certain sections of code are executed to completion.

One basic decision was to allow ATC in a method only if the method explicitly permits this. The default of no ATC is reasonable, since legacy code might be written expecting no ATC, and asynchronously aborting the execution of such a method could lead to unpredictable results. Since the natural way to model ATC is with an exception (AsynchronouslyInterruptedException), the way that a method indicates its susceptibility to ATC is by including AsynchronouslyInterruptedException in its throws clause. Causing this exception to be thrown in a real-time thread t as an effect of calling t.interrupt() was a natural extension of the semantics of interrupt as currently defined by java.lang.Thread.

One ATC-deferred section is synchronized code. This is a context that needs to be executed completely in order to ensure a program operates correctly. If synchronized code were aborted, a shared object could be left in an inconsistent state. Note that by making synchronized code ATC-deferred, this specification avoids the problems that caused Thread.stop() to be deprecated and that have made the use of Thread.destroy(), (now also deprecated in Java 1.5) prone to deadlock. If synchronized code calls an AI-method and an associated AIE is generated, then if no appropriate handler is present in the synchronized code, the AIE will propagate through the code. 

Constructors and finally clauses are subject to interruption if the program indicates so. However, if a constructor is aborted, an object might be only partially initialized. If the execution of a finally clause in an AI-method is aborted, needed cleanup code might not be performed. Indeed,  a finally clause in an aborted AI-method will not be executed at all if the abort occurs before its execution begins. It is the programmer's responsibility to ensure that executing these constructs either does not induce unwanted ATC latency (if ATCs are not allowed) or does not produce undesirable results (if ATCs are allowed).

A potential problem with using the exception mechanism to model ATC is that a method with a "catch-all" handler (for example a catch clause identifying Exception or even Throwable as the exception class) can inadvertently intercept an exception intended for a caller. This problem is avoided by having special semantics for catching an AIE. Even though a catch clause may catch an AIE, the exception will be propagated unless the handler invokes the happened method from AIE. Thus, if a schedulable object is asynchronously interrupted while in a try block that has a handler such as

catch (Throwable e){ return; }

the AIE will remain pending and will be thrown next time control enters or returns to an AI method.

This specification does not provide a special mechanism for terminating a real-time thread; ATC can be used to achieve this effect. This means that, by default, a real-time thread cannot be asynchronously terminated; to support asynchronous termination it needs to enter methods that are AI enabled at frequent intervals. Allowing termination as the default would have been questionable, bringing the same insecurities that are found in Thread.stop() and Thread.destroy().