Tutorial: Guidelines for designing real-time and safety-critical embedded Java applications - Part 3 - Embedded.com

Tutorial: Guidelines for designing real-time and safety-critical embedded Java applications – Part 3

Within the context of the Real Time Specification for Java, (RTSJ),hard real time systems are those in which an action performed atthewrong time has zero or possibly negative value. The connotation of”hard real time” is that compliance with all timing constraints isproven using theoretical static analysis techniques prior todeployment.

The difference between hard real-time and soft real-time does notdepend on the time ranges specified for deadlines or periodic tasks. Asoft real-time system might have a deadline of 100 µs, while ahard real-time system may have a deadline of 3 seconds.

To guide developers of real-time software, Aonix has drafted a setof 28 rules for hard real time Java development. These guidelines have been submitted to the Open Group'sReal-Time and Embedded Forum for consideration as part of the standardon safety-critical development with Java.

Rule 1. Use a hard real-time subsetof the standard Java libraries
There is no automatic garbage collection in the hard real-time domainso many of the standard Java libraries will not function reliably.Other motivations to restrict usage of the standard libraries are (1) to reduce the standard memoryfootprint and (2) to reducethe amount of code that must be certified in case safety certificationrequirements must be satisfied. The set of libraries approved for usein hard real-time Java applications, which only supports NoHeapRealtimeThread and forbidsthe use of java.lang.Thread and RealtimeThread , isdetailed in Appendix B of reference1, below .

Rule 2. Use a hard real-time subset of theReal-Time Specification for Java
The full RTSJ includes many capabilities that are not portable betweendifferent compliant implementations. Furthermore, supporting the fullgenerality of the RTSJ imposes certain performance-limitingrestrictions on the implementation. The set of RTSJ libraries that areapproved for use in hard real-time Java applications is detailed inAppendix C of reference 1, below.

Rule 3. Use enhanced replacements for certain RTSJlibraries
Certain RTSJ libraries lack the features desired for hard real-time andsafety-critical development. Analogous replacement libraries areavailable in the javax.realtime.util.sc package. Use these replacementlibraries instead of the traditional RTSJ libraries. The specificreplacement libraries, which differ only slightly from their RTSJcounterparts, include: AbsoluteTime, AsyncEvent, AsyncEventHandler,BoundAsyncEventHandler, Clock, HighResolutionTime,NoHeapRealtimeThread, OneShotTimer, PeriodicTimer, PriorityParameters,PriorityScheduler, RealtimeThread, RelativeTime, ReleaseParameters,Schedulable, Scheduler, SchedulingParameters, SizeEstimator,SporadicParameters,Timer and UnknownHappeningException .

Rule 4. Use standard extended libraries for I/Oports and interrupt handling
When implementing low-level access to I/O devices and interrupthandling, use the standard RTSJ library extensions described in reference 1, below.

Rule 5. Assure availability of supplementallibraries
Appendices B, C, and D of reference 1below describe standard libraries that are assumed to exist inall compliant hard real-time execution environments. If particularapplications require additional libraries beyond this minimal set,assure that the libraries are available for all intended targetplatforms.

Rule 6. Use an intelligent linker and annotationsto guide initialization of static variables
In traditional Java, class variables are to be initialized “immediatelybefore first use”. This requires run-time checks, introducesnon-determinism into the worst-case execution-time analysis, andhinders efficient translation of programs for native execution.

Further, it introduces certain race conditions in which the initialvalues of particular class variables (even the values of certain finalvariables) depend on the sequence in which classes are accessed (andinitialized). Use an intelligent static linker guided by @StaticDependency and @InitializeAtStartup annotations toperform initialization of all static variables.

Rule 7. Use only 128 priority levels forNoHeapRealtimeThread
The official RTSJ specification states that a compliant implementationmust provide at least 28 priorities, but may support many more. Forhard real-time mission-critical development, application softwareshould limit its use of priorities to the range from 1 though 128.Vendors can readily support this priority range as a standard hardreal-time mission-critical platform.

Rule 8. Do not start up traditionalThread or RealtimeThread
The hard real-time environment only runs NoHeapRealtimeThread. Any attemptto instantiate other thread types will result in a run-time exception.

Rule 9. Use NATIVE-mode NoHeapRealtimeThread forinvocation of native methods
Only threads that are instantiated as NATIVE mode are allowed to invokenative methods. Note that a transfigured NATIVE-mode thread is also noteligible for invocation of native methods.

Rule 10. Do not invoke native methods withincontexts that hold a Java synchronization lock
When a NATIVE-mode thread enters a Java synchronized method, the threadtransfigures itself to behave as if it were a COMPLIANT-mode thread. Inthis mode, the thread is not allowed to execute native code.

Rule 11 . Preallocate Throwable instances
The traditional Java convention of allocating a new Throwable each timean exceptional condition is encountered is not compatible withlimited-memory hard real-time development practices. Preallocatenecessary Throwable objects in scopes that are sufficiently visiblethat they can be seen by the intended catch statement. Throw thepreallocated ImmortalMemory Throwable instances available in javax.realtime.util.sc.PreallocatedExceptionsand javax.realtime.util.mc . When appropriate, use PreallocatedExceptions.

Rule 12. Restrict access toThrowable attributes
In a traditional Java environment, memory is allocated to representprivate information associated with each thrown Throwable. Because ahard real-time environment is assumed to have limited memory resourcesand no automatic garbage collection, the typical hard real-timeprogramming style avoids allocation of memory for each thrownexception. One fixed-size buffer holding up to 20 StackTraceElement objects ismaintained for each thread. Each time an exception is thrown, thisbuffer is overwritten with no more than 20 of the inner-most nestedmethod activation frames.

The buffer's contents can be copied by invoking Throwable.getStackTrace() beforeany other throw statements are executed by the thread. Any code thatattempts to access more than 20 stack frames, or delays invocation of Throwable.getStackTrace() untilafter a second Throwabl e hasbeen thrown, will not run reliably in the hard real-time environment.

Rule 13. Annotate all program components to indicatescoped memory behaviors.
In order to enable static analysis to prove referential integritywithout the need for run-time fetch and store checks, programmers mustannotate their software to identify variables that might holdreferences to objects allocated in temporary memory scopes.

Rule 14. Carefully restrict the use of methodsdeclared with the @AllowCheckedScopedLinks annotation
Methods with this annotation may terminate with a run-time exceptionresulting from inappropriate assignment operations. Automated staticanalysis tools are not able to guarantee the absence of these run-timeexceptions, and reference assignment operations contained within thesemethods will run slower than other code because each assignment must beaccompanied by a run-time check.

For each method that is declared with the @AllowCheckedScopedLinksannotation, programmers should provide commentary explaining why theybelieve the code will not violate scoped-memory referential integrityrules.

Rule 15. Carefully restrict the use of methodsdeclared with the @ImmortalAllocation annotation
As a rule of thumb, ImmortalMemory should only be allocated during application startup. Any otherallocation of ImmortalMemory introduces the risk that the supply of ImmortalMemory will becomeexhausted in a long-running application.

Rule 16. Use @StaticAnalyzable annotation to identify methods withbounded resource needs
The @StaticAnalyzable annotation identifies methods that have bounded CPU time and memoryneeds. For any program component declared with the @StaticAnalyzable annotation,programmers should provide StaticLimit assertions to identify iterationlimits on loops and other resource constraints.

Rule 17. Use hierarchical organization of memory tosupport software modules
Organize software modules to support modular composition of componentsso that all memory allocation for individual components, including thememory for all of the threads that comprise the software module, ishierarchically organized. The memory for the complete module isincrementally divided into memory for sub-modules. Each sub-module mayfurther divide its memory for smaller sub-modules. All memoryreclamation is handled in last-in-first-out order with respect toallocation sequence. Use the ThreadStack data abstractions described in Part 1 in this series of articles.

Rule 18. Use the @TraditionalJavaShared conventions to share objects with traditional Java
When it is necessary or desirable to share hard real-time data and/orcontrol abstractions with the traditional Java domain, use the @TraditionalJavaShared and @TraditionalJavaMethod annotationsand protocols.

Rule 19. Avoid synchronized statements
When synchronization is required, use synchronized methods instead ofindividual statements.

Rule 20. Restrict invocations of Object.wait(), Object.notify() , andObject.notifyAll() tosynchronized methods associated with the target of the wait(), notify(), or notifyAll() invocation
To facilitate readability, maintenance, and analysis of synchronizationbehaviors, we recommend that all synchronization operations besyntactically bound to the corresponding lock object.

Rule 21. Inherit from PCP or Atomic in any classthat uses PriorityCeilingEmulation MonitorControl policy toimplement instance method synchronization
Developers should decide when the synchronization code is writtenwhether it will use PriorityCeilingEmulation or PriorityInheritance Monitor Control policy. Virtual methods that intend to use priorityceiling emulation for synchronization should inherit from the PCP orAtomic interfaces.

Use of the Atomic interface denotes that the synchronization lockwill not be held while the thread is blocked, and further imposes arestriction that the CPU time consumed by a thread while it holds theatomic lock is bounded by a constant. These restrictions, which makepossible a very efficient queue-free implementation, are enforced by aspecial byte-code verifier.

Rule 22. Inherit from StaticPCP orStaticAtomic in any class that uses PriorityCeilingEmulation MonitorControl policy toimplement static method synchronization
Developers should decide when the synchronization code is writtenwhether it will use PriorityCeilingEmulation or PriorityInheritance MonitorControl policy. Static methods that intend to use priorityceiling emulation should inherit from the StaticPCP or StaticAtomicinterfaces.

Use of the StaticAtomic interface denotes that the synchronizationlock will not be held while the thread is blocked, and further imposesa restriction that the CPU time consumed by a thread while it holds theatomic lock is bounded by a constant. These restrictions, which makepossible a very efficient queue-free implementation, are enforced by aspecial byte-code verifier.

Rule 23. Implement the Atomic or StaticAtomicinterfaces in any class containing synchronized methods that shareaccess to interrupt handler data
To reduce the likelihood that poorly written device drivers willcompromise reliable operation of the real-time application, allsynchronization with interrupt handling code must be time bounded.Otherwise, application code may hold interrupts disabled for durationsthat compromise reliable operation of the interrupt handler.<>

Rule 24. Do not inherit from PCP (or Atomic) if any ancestor class usespriority inheritance synchronization
Any class file that includes a synchronized method but does not extendPCP or Atomic is assumed to use priority inheritance in theimplementation of the synchronization lock. To simplify semantics andimplementation, we forbid mixing of priority inheritancesynchronization and priority ceiling synchronization in any class orsubclass definition.<>

Rule 25. Annotate the ceilingPriority() method of Atomic and PCP Classes with @Ceiling
The @Ceiling annotationexpects its value attribute to be set to the ceiling priority at whichthis object expects to synchronize. Availability of an object'sintended ceiling priority as a source code attribute makes it possibleto prove compatibility between components using static analysis tools.In particular, the static analyzer can demonstrate that nested lockshave strictly increasing ceiling priority values.

Rule 26 . Annotate the staticCeilingPriority() method ofStaticAtomic and StaticPCP Classes with @Ceiling
The @Ceiling annotationexpects its value attribute to be set to the ceiling priority at whichthis object expects to synchronize. Availability of an object'sintended ceiling priority as a source code attribute makes it possibleto prove compatibility between components using static analysis tools.In particular, the static analyzer can demonstrate that nested lockshave strictly increasing ceiling priority values.

Rule 27. Do Not Override Object.finalize()
In traditional Java code, an object'sfinalize() method is invoked by the garbage collector beforethe object's memory is reclaimed. In the hard real-time domain, we donot have a garbage collector. Memory is reclaimed as particular controlcontexts are left. If finalization code is required, place it in in thefinally clause of a try-finally statement.

Rule 28. Use development tools toenforce consistency with hard real-time guidelines
To enforce that programmers make proper use of the hard real-time APIsubsets and that all code is consistent with the intent of the hardreal-time programming annotations, use special byte-code verificationtools that help assure reliable and efficient implementation ofprogrammer intent.

Next in Part 4: Safety-CriticalJava Development Guidelines
To Read Part 1 go to Alternatives to garbage collection
To Read Part 2, go to  SoftReal-Time Java Development Guidelines

Kelvin Nilsen, Ph.D., is chief technology officer at Aonix NorthAmerica

References:

[1] Guidelines for ScalableJava Development of Real-Time Systems, available at http://research.aonix.com/jsc/rtjava.guidelines.3-28-06.pdf

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.