Several new ThreadStack objects are allocated on lines 37, socket_reader_thread = new Thread-Stack(SocketReader.class); through 41 orchestrator_thread = new ThreadStack(Orchestrator.class);. Each allocation represents the stack memory to be used by the threads spawned by the main program. In general, it might be difficult for a static analysis tool to determine the amount of stack memory required to reliably execute these subthreads.
The argument to each ThreadStack constructor is the Class that supplies the code to be executed by the corresponding thread. The static analyzer requires each of the NoHeapRealtimeThread subclasses passed in this context to have a run() method declared with the @ StaticAnalyzable annotation and the enforce_ memory_analysis attribute set to true. If the ThreadStack constructor's argument derives instead from BoundAsyncEventHandler, as in the case of Orchestrator class, the static analyzer requires this class' asyncEventHandler() method to be declared with the @StaticAnalyzable annotation and the enforce_memory_analysis attribute set to true.
All temporary memory needs are satisfied from the run-time stack of the current thread. Note that we allocate two temporary BufferPair instances on lines 23, microphone_stream = new BufferPair(); and 24, speaker_stream = new Buffer-Pair();. References to these objects are then passed to the constructors for the threads that comprise the various functional components of this software application. One of the constraints enforced by the Hard Real-Time Verifier is that references to stack-allocated objects never survive longer than the referenced object itself. This also is enforced through an annotation mechanism. Consider the constructor for the SocketReader class:
@ScopedPure
@StaticAnalyzable(enforce_time_analysis = {false}, enforce_non_blocking = {false})
SocketReader(SimpleAudio sa, Buffer-Pair buffers, String socket_name) throws
FileNotFoundException
The @ScopedPure annotation denotes that each of the incoming reference parameters to this constructor may refer to objects that reside on the run-time stack of a more outer-nested scope. The byte-code verifier ensures that the contents of these parameters are never copied into variables that aren't likewise distinguished as having the @Scoped designation.
Furthermore, it prohibits the copying of values from inner-nested scoped variables to outer-nested scoped variables. One exception is under special circumstances, where it can demonstrate that the referenced object resides in a scope that's at the same or more outer-nested level than the variable to be assigned. If this constructor's parameters hadn't been designated with the @Scoped annotation, the byte-code verifier would not have allowed the main program to pass references to its stack-allocated BufferPair and SimpleAudio objects.
One of the RTSJ-supported real-time programming abstractions demonstrated in this application is the PeriodicTimer class. Note that this application instantiates a PeriodicTimer object at line 49, drumbeat = new PeriodicTimer(start_time, period, orchestrator); and assigns the result to the local drumbeat variable. One of the arguments is a reference to the orchestrator object, which itself is an instance of BoundAsyncEventHandler. This drumbeat periodic timer is configured to trigger execution of orchestrator's handleAsyncEvent() method 16 times per second, which is once every 62.5 ms.
Real-time developers who use the C or C++ languages can implement many of the same constructs supported by these real-time Java technologies. However, C and C++ programmers must be trusted to avoid creating dangling pointers and memory leaks. They also lack standard tool support to automate the analysis of execution times and stack sizes.
Additionally, there's no integrity checking to ensure that method implementations satisfy the documented real-time interface requirements and that method invocations pass arguments that likewise satisfy documented interface requirements. Finally, during the maintenance of existing software systems, the C and C++ programmer has no tool support to guarantee that modifications to the existing software are compatible with the compositional requirements assumed during the development of the original software.
Traditional Java delivers many productivity and cost benefits. Disciplined use of real-time Java technologies offers many of those same benefits. Compared with the use of C and C++, typical Java developers are about twice as productive during development of new code and five to 10 times as productive during maintenance of existing software. As embedded realtime software grows in size and complexity, the factors that motivate a switch to more modern software engineering technologies, such as those that are enabled by real-time Java, grow in importance .