LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Find Resources
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Cvs-checkins > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    From: cvs at opencores.org<cvs@o...>
    Date: Sat Aug 25 20:03:52 CEST 2007
    Subject: [cvs-checkins] MODIFIED: jop ...
    Top
    Date: 00/07/08 25:20:03

    Added: jop/doc/book/runtime rt_user_interaction.pdf rt_intro.tex
    rt_profile.tex rt_user.tex
    Log:
    Handbook update


    Revision Changes Path
    1.1 jop/doc/book/runtime/rt_user_interaction.pdf

    http://www.opencores.org/cvsweb.shtml/jop/doc/book/runtime/rt_user_interaction.pdf?rev=1.1&content-type=text/x-cvsweb-markup

    <<Binary file>>


    1.1 jop/doc/book/runtime/rt_intro.tex

    http://www.opencores.org/cvsweb.shtml/jop/doc/book/runtime/rt_intro.tex?rev=1.1&content-type=text/x-cvsweb-markup

    Index: rt_intro.tex
    ===================================================================
    A Java processor alone is not a complete JVM. This chapter describes
    the definition of a real-time profile for Java and a framework for a
    user-defined scheduler in Java. It concludes with the description of
    the JVM internal data structures to represent classes and objects.



    1.1 jop/doc/book/runtime/rt_profile.tex

    http://www.opencores.org/cvsweb.shtml/jop/doc/book/runtime/rt_profile.tex?rev=1.1&content-type=text/x-cvsweb-markup

    Index: rt_profile.tex
    ===================================================================

    \section{A Real-Time Profile for Embedded Java}
    \label{sec:rtprof}

    As standard Java is under-specified for real-time systems and the
    RTSJ does not fit for small embedded systems a new and simpler
    real-time profile is defined in this section and implemented on JOP.
    The guidelines of the specification are:

    \begin{itemize}
    \item High-integrity profile
    \item Easy syntax, simplicity
    \item Easy to implement
    \item Low runtime overhead
    \item No syntactic extension of Java
    \item Minimum change of Java semantics
    \item Support for time measurement if a WCET analysis tool is not available
    \item Known overheads (documentation of runtime behavior and memory
    requirements of every JVM operation and all methods have to be
    provided)
    \end{itemize}

    The real-time profile under discussion is inspired by the restricted
    versions of the RTSJ described in \cite{Pusch01} and \cite{583825}
    (see Section~\ref{subsec:restr:rtsj}). It is intended for
    high-integrity real-time applications and as a test case to evaluate
    the architecture of JOP as a Java processor for real-time systems.

    The proposed definition is not compatible with the RTSJ. Since the
    application domain for the RTSJ is different from high-integrity
    systems, it makes sense for it \emph{not} to be compatible with the
    RTSJ. Restrictions can be enforced by defining new classes (e.g.\
    setting thread priority in the constructor of a real-time thread
    alone, enforcing minimum interarrival times for sporadic events).

    %Hardware interrupts, that are usually handled by device drivers, are
    %part of this profile. These interrupts are mapped to events and
    %scheduled in the same way as application threads. This feature
    %allows priority assignment to the device drivers and the execution
    %time can be incorporated in the schedulability analysis with normal
    %tasks. This solution also avoids problems with preemption latency
    %caused by device drivers.

    All hardware interrupts are represented by threads under the control
    of the scheduler. With this solution, a priority is assigned to the
    device drivers and the execution time can be incorporated in the
    schedulability analysis with normal tasks. This solution also avoids
    problems with preemption latency provoked by device drivers. One
    example of this problem is the \emph{caps-lock} issue in Linux
    \cite{REDLinux2003}: A device driver performs a spinlock wait for
    keyboard acknowledgement and produces preemption latency up to
    9166$\mu$s. With the proposed concept of hardware interrupts under
    scheduler control, a lower assigned priority to such a device driver
    avoids preemption delays of \emph{more important} real-time threads
    and events.

    %This specification is functional compatible with Ravenscar-Java (RJ)
    %\cite{583825}, but avoids inheritance of complex RTSJ classes. In
    %fact, it is possible (and has been done) to implement RJ with the
    %additional necessary RTSJ classes on top of it.

    To verify that this specification is expressive enough for
    high-integrity real-time applications, Ravenscar-Java (RJ)
    \cite{583825} (see Section~\ref{subsec:rj}), with the additional
    necessary RTSJ classes, has been implemented on top of it. However,
    RJ inherits some of the complexity of the RTSJ. Therefore, the
    implementation of RJ has a larger memory and runtime overhead than
    this simple specification. \subsection{Application Structure} The application is divided in two different phases: \emph{initialization} and \emph{mission}. All non time-critical initialization, global object allocations, thread creation and startup are performed in the initialization phase. All classes need to be loaded and initialized in this phase. The mission phase starts after invocation of \code{startMission()}. The number of threads is fixed and the assigned priorities remain unchanged. The following restrictions apply to the application: \begin{itemize} \item Initialization and mission phase \item Fixed number of threads \item Threads are created at initialization phase \item All shared objects are allocated at initialization \end{itemize} \subsection{Threads} Concurrency is expressed with two types of \emph{schedulable objects}: \begin{description} \item[Periodic activities] are represented by threads that execute in an infinite loop invoking \code{waitForNextPeriod()} to get rescheduled in predefined time intervals. \item[Asynchronous sporadic activities] are represented by event handlers. Each event handler is in fact a thread, which is released by an hardware interrupt or a software generated event (invocation of \code{fire()}). Minimum interarrival time has to be specified on creation of the event handler. \end{description} % The classes that implement the \emph{schedulable objects} are: % \begin{description} \item[RtThread] represents a periodic task. As usual task work is coded in \code{run()}, which gets invoked on \code{missionStart()}. A scoped memory object can be attached to an \code{RtThread} at creation. \item[HwEvent] represents an interrupt with a minimum interarrival time. If the hardware generates more interrupts, they get lost. \item[SwEvent] represents a software-generated event. It is triggered by \code{fire()} and needs to override \code{handle()}. \end{description} % Listing~\ref{lst:arch:rt:profile:schobj} shows the definition of the basic classes. \begin{lstlisting}[float,caption={Schedulable objects}, label=lst:arch:rt:profile:schobj,{emph=RtThread,enterMemory, exitMemory,run,waitForNextPeriod,startMission,HwEvent,handle, SwEvent,fire,handle}] public class RtThread { public RtThread(int priority, int period) public RtThread(int priority, int period, int offset) public RtThread(int priority, int period, Memory mem) public RtThread(int priority, int period, int offset, Memory mem) public void enterMemory() public void exitMemory() public void run() public boolean waitForNextPeriod() public static void startMission() } public class HwEvent extends RtThread { public HwEvent(int priority, int minTime, int number) public HwEvent(int priority, int minTime, Memory mem, int number) public void handle() } public class SwEvent extends RtThread { public SwEvent(int priority, int minTime) public SwEvent(int priority, int minTime, Memory mem) public final void fire() public void handle() } \end{lstlisting} Listing~\ref{lst:arch:rt:profile:example} shows the principle coding of a worker thread. An example for creation of two real-time threads and an event handler can be seen in Listing~\ref{lst:arch:rt:profile:usage}. \subsection{Scheduling} The scheduler is a preemptive, priority-based scheduler with unlimited priority levels and a unique priority value for each schedulable object. No real-time threads or events are scheduled during the initialization phase. The design decision to use unique priority levels, instead of FIFO within priorities, is based on following facts: Two common ways to assign priorities are rate monotonic and, in a more general form, deadline monotonic assignment. When two tasks are given the same priority, we can choose one of them and assign a higher priority to that task and the task set will still be schedulable. This results in a strictly monotonic priority order and we do not need to deal with FIFO order. This eliminates queues for each priority level and results in a single, priority ordered task list with unlimited priority levels. Synchronized blocks are executed with priority ceiling emulation protocol. An object, used for synchronization, for which the priority is not set, top priority is assumed. This avoids priority inversions on objects that are not accessible from the application (e.g. objects inside a library). In addition, the scheduler contains methods for worst-case time measurement for both the periodic work and handler methods. These measured execution times can be used during development when no WCET analysis tool is available. \subsection{Memory} The profile does not support a garbage collector. All memory should be allocated at the initialization phase. Without a garbage collector, the heap implicitly becomes immortal memory (as defined by the RTSJ). For objects created during the mission phase, a scoped memory is provided. Each scoped memory area is assigned to one \code{RtThread}. A scoped memory area cannot be shared between threads. No references are allowed from the heap to scoped memory. Scoped memory is explicitly entered and left using invocations from the application logic. Memory areas are cleared both on creation and when leaving the scope (invocation of \code{exitMemory()}), leading to a memory area with constant allocation time, as opposed to memory with linear allocation time (as the memory type \code{LTMemory} in the RTSJ) \cite{Corsaro:2003:DPR}. \subsection{Restriction of Java} A list of some of the language features that should be avoided for WCET analyzable real-time threads and bound memory usage: \begin{description} \item[WCET:] Only analyzable language constructs are allowed (see \cite{84850}). \item[Static class initialization:] Since the definition when to call the static class initializer is problematic (see Section~\ref{para:restrict:clinit}), they are disallowed. Move this code to a static method (e.g. \code{init()}) and invoke it explicit in the initialization phase. \item[Inheritance:] Reduce usage of interfaces and overridden methods. \item[String concatenation:] In immortal memory scope only string concatenation with string literals is allowed. \item[Finalization:] \code{finalize()} has a weak definition in Java. Because real-time systems run \emph{forever}, objects in the heap, which is immortal in this specification, will never be finalized. Objects in scoped memory are released on \code{exitMemory()}. However, finalizations on these objects complicate WCET analysis of \code{exitMemory()}. \item[Dynamic Class Loading:] Due to the implementation and WCET analysis complexity dynamic class loading is avoided. \end{description} % A program analysis tool can greatly help in enforcing these restrictions. \begin{lstlisting}[float,caption={A periodic real-time thread}, label=lst:arch:rt:profile:example] public class Worker extends RtThread { private SwEvent event; public Worker(int p, int t, SwEvent ev) { super(p, t, // create a scoped memory area new Memory(10000) ); event = ev; init(); } private void init() { // all initialzation stuff // has to be placed here } public void run() { for (;;) { work(); // do some work event.fire(); // and fire an event // some work in scoped memory enterMemory(); workWithMem(); exitMemory(); // wait for next period if (!waitForNextPeriod()) { missedDeadline(); } } // should never reach this point } } \end{lstlisting} \begin{lstlisting}[float,caption={Start of the application}, label=lst:arch:rt:profile:usage] // create an Event Handler h = new Handler(3, 1000); // create two worker threads with // priorities according to their periods FastWorker fw = new FastWorker(2, 2000); Worker w = new Worker(1, 10000, h); // change to mission phase for all // periodic threads and event handler RtThread.startMission(); // do some non real-time work // and invoke sleep() or yield() for (;;) { watchdogBlink(); Thread.sleep(500); } \end{lstlisting} \subsection{Implementation Results} The initial idea was to implement scheduling and dispatching in microcode. However, many Java bytecodes have a one to one mapping to a microcode instruction, resulting in a single cycle execution. The performance gain of an algorithm coded in microcode is therefore negligible. As a result, almost all of the scheduling is implemented in Java. Only a small part of the dispatcher, a memory copy, is implemented in microcode and exposed with a special bytecode. Experimental results of basic scheduling benchmarks, such as periodic thread jitter, context switch time for threads and asynchronous events, can be found in Section~\ref{subsec:rt:perf}. To implement system functions, such as scheduling, in Java, access to JVM and processor internal data structures have to be available. However, Java does not allow memory access or access to hardware devices. In JOP, this access is provided by way of additional bytecodes. In the Java environment, these bytecodes are represented as static native methods. The compiled invoke instruction for these methods (\code{invokestatic}) is replaced by these additional bytecodes in the class file. This solution provides a very efficient way to incorporate low-level functions into a pure Java system. The translation can be performed during class loading to avoid non-standard class files. A pure Java system, without an underlying RTOS, is an unusual system with some interesting new properties. Java is a safer execution environment than C (e.g.\ no pointers) and the boundary between \emph{kernel} and \emph{user space} can become quite loose. Scheduling, usually part of the operating system or the JVM, is implemented in Java and executed in the same context as the application. This property provides an easy path to a framework for user-defined scheduling. 1.1 jop/doc/book/runtime/rt_user.tex http://www.opencores.org/cvsweb.shtml/jop/doc/book/runtime/rt_user.tex?rev=1.1&content-type=text/x-cvsweb-markup Index: rt_user.tex =================================================================== \section{User-Defined Scheduler} \label{sec:usersched} \emph{TODO: rewrite and explain the scheduler in detail.} The novel approach to implement a real-time scheduler in Java opens up new possibilities. An obvious next step is to extend this system to provide a framework for user-defined scheduling in Java. New applications, such as multimedia streaming, result in \emph{soft} real-time systems that need a more flexible scheduler than the traditional fixed priority based ones. This section provides a simple-to-use framework to evaluate new scheduling concepts for these applications in real-time Java. The following section analyzes which events are exposed to the scheduler and which functions from the JVM need to be available in the user space. It is followed by the definition of the framework and examples of how to implement a scheduler using this framework. \subsection{Schedule Events} The most important element of the user-defined scheduler is to define which events result in the scheduling of a new task. When such an event occurs, the user-defined scheduler is invoked. It can update its task list and decide which task is dispatched. \begin{description} \item[Timer interrupt:] For timed scheduling decisions, a programmable timer generates exact timed interrupts. The scheduler controls the time interval for the next interrupt. \item[HW interrupt:] Each hardware-generated interrupt can be associated with an asynchronous event. This allows the execution of a device driver under the control of the scheduler. Latencies of the device driver can be controlled by assigning the right priority in a priority scheduler. \item[Monitor:] To allow different implementations of priority inversion protocols, hooks for \code{monitorenter} and \code{monitorexit} are provided. \item[Thread block:] Each thread can cease execution via a call of the scheduler. This function is used to implement methods such as \code{waitForNextPeriod()} or \code{sleep()}. The reason for blocking (e.g. end of periodic work) has to be communicated to the scheduler (e.g. next time to be unblocked for a periodic task). \item[SW event:] Invoking \code{fire()} on an event provides support for signaling. \code{wait()}, \code{notify()} or \code{notifyAll()} are not necessary. However, this mechanism is not part of the scheduling framework. It can be implemented with the user-defined scheduler and an associated thread class. \end{description} \subsection{Data Structures} To implement a scheduler in Java, some JVM internal data structures need to be accessible. \begin{description} \item[Object:] In Java, any object (including an object from the class \code{Class} for static methods) can be used for synchronization. Different priority inversion protocols require different data structures to be associated with an object. Each object provides a field, accessed through a \code{Scheduler} method, in which these data structures can be attached. \item[Thread:] A list of all threads is provided to the scheduler. The scheduler is also notified when a new thread object is created or a thread terminates. The scheduler controls the start of threads. \end{description} \subsection{Services for the Scheduler} The real-time JVM and the hardware platform have to provide some minimum services. These services are exposed through \code{Scheduler}: \begin{description} \item[Dispatch:] The current active thread is interrupted and a new thread is placed in the run state. \item[Time:] System time with high resolution (microseconds, if the hardware can provide it) is used for time derived scheduling decisions. \item[Timer:] A programmable timer interrupt (not a timer tick) is necessary for accurate time triggered scheduling. \item[Interrupts:] To protect the data structures of the scheduler all interrupts can be disabled and enabled. \end{description} \subsection{Class Scheduler} The class \code{Scheduler} has to be extended to implement a user-defined scheduler. The class \code{Task} represents \emph{schedulable objects}. For non-trivial scheduling algorithms, \code{Task} is also extended. The scheduler lives in normal thread space. There is no special context such as kernel space. The methods of \code{Scheduler} are categorized by the caller module and described in detail below. \paragraph{Application} To use a scheduler in an application, the application only has to create one instance of the scheduler class and has to decide when scheduling starts. \begin{lstlisting}[emph=Scheduler] public Scheduler() \end{lstlisting} A single instance of the scheduler is created by the application. \begin{lstlisting}[emph=start] public void start() \end{lstlisting} This method initiates the transition to the mission phase of the application. All created tasks are started and scheduled under the control of the user scheduler. \paragraph{Task} A user-defined scheduler usually needs an associated user-defined thread class (an extension of \code{Task}). This class interacts with the scheduler by invoking following methods from \code{Scheduler}: \begin{lstlisting}[emph=addTask] void addTask(Task t) \end{lstlisting} The scheduler has access to the list of created tasks to use at the start of scheduling. For dynamic task creation after the start of the scheduler, this method is called by the constructor of Task, to notify the scheduler to update its list. \begin{lstlisting}[emph=isDead] void isDead(Task t) \end{lstlisting} The scheduler is notified when a Task returns from the \code{run()} method. The scheduler removes this Task from the list of schedulable objects. \begin{lstlisting}[emph=block] void block() \end{lstlisting} Every \code{Task} can cease execution via a call of the scheduler. This method is used to implement methods such as \code{waitForNextPeriod()} or \code{sleep()} in a user defined thread class. \paragraph{Java Virtual Machine} The methods listed below provide the essential points of communication between the JVM and the scheduler. As a response to an interrupt (hardware or timer), entrance or exit of a synchronized method/block the JVM invokes a method from the scheduler. \begin{lstlisting}[emph=schedule] abstract void schedule() \end{lstlisting} This is the main entry point for the scheduler. This method has to be overridden to implement the scheduling algorithm. It is called from the JVM on a timed event or a software interrupt (see \code{genInt()}) is issued (e.g. when a \code{Task} gives up execution). \begin{lstlisting}[emph=interrupt] void interrupt(int nr) \end{lstlisting} The scheduler is notified on a hardware event. It can directly call an associated device driver or use this information to unblock a waiting task. \begin{lstlisting}[emph={monitorEnter,monitorExit}] void monitorEnter(Object o) void monitorExit(Object o) \end{lstlisting} These methods are invoked by the JVM on synchronized methods and blocks (JVM bytecodes \code{monitorenter} and \code{monitorexit}). They provide hooks for executing dynamic priority changes in the scheduler. \paragraph{Scheduler} Services of the JVM needed to implement a scheduler are provided through static methods. \begin{lstlisting}[emph=genInt] static final void genInt() \end{lstlisting} This service from the JVM schedules a software interrupt. As a result, \code{schedule()} is called. This method is the standard way of switching control to the scheduler. It is e.g. invoked by \code{block()}. \begin{lstlisting}[emph={enableInt,disableInt}] static final void enableInt() static final void disableInt() \end{lstlisting} The scheduler cannot use monitors to protect its data structures as the scheduler itself is in charge of handling monitors. To protect the data structures of the scheduler, it can globally enable and disable interrupts. \begin{lstlisting}[emph=dispatch] static final void dispatch(Task nextTask, int nextTim) \end{lstlisting} This method dispatches a \code{Task} and schedules a timer interrupt at \code{nextTim}. \begin{lstlisting}[emph={attachData,getAttachedData}] static final void attachData(Object obj, Object data) static final Object getAttachedData(Object obj) \end{lstlisting} The behavior of the priority inversion avoidance protocol is defined by the user scheduler. The root of the Java class hierarchy (\code{java.lang.Object}) contains a JVM internal reference of generic type Object that can be used by the scheduler to attach data structures for monitors. The first argument of these methods is the object that is used as monitor. \paragraph{Scheduler or Task} The following two methods are utility functions useful for the scheduler and the thread implementation. \begin{lstlisting}[emph=getNow] static final int getNow() \end{lstlisting} To support time-triggered scheduling, the system provides access to a high-resolution time or counter. The returned value is the time since startup in microseconds. The exact resolution is implementation-dependent. \begin{lstlisting}[emph=getRunningTask] static final Task getRunningTask() \end{lstlisting} The current running \code{Task} (in which context the scheduler is called) is returned by this method. \subsection{Class Task} A basic structure for schedulable objects is shown in Listing~\ref{lst:arch:rt:user:task}. This class is usually extended to provide a thread implementation that fits to the user-defined scheduler. The class \code{Task} is intended to be minimal. To avoid inheriting methods that do not fit for some applications, it does not extend \code{java.lang.Thread}. However, \code{Task} can be used to \emph{implement} \code{java.lang.Thread}. \begin{lstlisting}[float,caption=A basic schedulable object, label=lst:arch:rt:user:task, emph={Task, start, enterMemory, exitMemory,run,getFirstTask,getNextTask}] public class Task { public Task() public Task(Memory mem) void start() public void enterMemory() public void exitMemory() public void run() static Task getFirstTask() static Task getNextTask() } \end{lstlisting} The methods \code{enterMemory} and \code{exitMemory} are used by the application to provide scoped memory for temporary allocated objects. \code{Task} provides a list of active tasks for the scheduler. One issue, raised by the implementation of the framework is the way in which access rights to methods need to be defined in Java. All methods, except \code{start()}, should be \code{private} or \code{protected}. However, some methods, such as \code{schedule()}, are invoked by a part of the JVM, which is also written in Java but resides in a different package. This results in defining the methods as public and \emph{hoping} that they are not invoked by the application code. The C++ concept of friends would greatly help in sharing information over package boundaries without making this information public. \subsection{A Simple Example Scheduler} Listing~\ref{lst:arch:rt:user:example} shows a full example of using this framework to implement a simple round robin scheduler. The only method that needs to be supplied is \code{schedule()}. For a more advanced scheduler, it is necessary to provide a combination of a user defined thread class and a scheduler class. These two classes have to be tightly integrated, as the scheduler uses information provided by the thread objects for its scheduling decisions. \pagebreak \begin{lstlisting}[caption=A very simple scheduler, label=lst:arch:rt:user:example] public class RoundRobin extends Scheduler { // // test threads // static class Work extends Task { private int c; Work(int ch) { c = ch; } public void run() { for (;;) { Dbg.wr(c); // debug output // busy wait to simulate // 3 ms workload in Work. int ts = Scheduler.getNow(); ts += 3000; while (ts-Scheduler.getNow()>0) ; } } } // // user scheduler starts here // public void addTask(Task t) { // we do not allow tasks to be // added after start(). } // // called by the JVM // public void schedule() { Task t = getRunningTask().getNextTask(); if (t==null) t = Task.getFirstTask(); dispatch(t, getNow()+10000); } public static void main(String[] args) { new Work('a'); new Work('b'); new Work('c'); RoundRobin rr = new RoundRobin(); rr.start(); } } \end{lstlisting} \subsection{Interaction of Task, Scheduler and the JVM} The framework is used to re-implement the scheduler described in Section~\ref{sec:rtprof}. In the original implementation, the interaction between scheduling and threads was simple, as the scheduling was part of the thread class. Using the framework, these functions have to be split to two classes, extending \code{Task} and \code{Scheduler}. Both classes are placed in the same package to provide simpler information sharing with some protection from the rest of the application. For performance reasons data structures are directly exposed from one class to the other. The resulting implementation is compatible with the first definition, with the exception that \code{RtThread} now extends \code{Task}. However, no changes in the application code are necessary. \figurename~\ref{fig_arch_rt_user_interaction} is an interaction example of this scheduler within the framework. The interaction diagram shows the message sequences between two application tasks, the scheduler, the JVM and the hardware. The hardware represents interrupt and timer logic. The corresponding code fragments of the application, \code{RtThread} and \code{PriorityScheduler} are shown in Listing~\ref{lst:arch:rt:user:app}, \ref{lst:arch:rt:user:rtthr} and \ref{lst:arch:rt:user:prsched}. Task 2 is a periodic task with a higher priority than Task 1. \begin{figure*} \centering \includegraphics[scale=\picscale]{runtime/rt_user_interaction} \caption[Interaction diagram of the user scheduler framework] {Interaction and message exchange between the application, the scheduler, the JVM and the hardware} \label{fig_arch_rt_user_interaction} \end{figure*} The first event is a timer event to unblock Task 2 for a new period. The generated timer event results in a call of the user defined scheduler. The scheduler performs its scheduling decision and issues a context switch to Task 2. With every context switch the timer is reprogrammed to generate an interrupt at the next time triggered event for a higher priority task. Task 2 performs the periodic work and ceases execution by invocation of \code{waitForNextPeriod()}. The scheduler is called and requests an interrupt from the hardware resulting in the same call sequence as with a timer or other hardware interrupt. The software generated interrupt imposes negligible overhead and results in a single entry point for the scheduler. Task 1 is the only ready task in this example and is resumed by the scheduler. Using a general scheduling framework for a real-time scheduler is not without its costs. Additional methods are invoked from a scheduling event until the actual dispatch takes place. The context switch is about 20\% slower than in the original implementation. It is the opinion of the author that the additional cost is outweighed by the flexibility of the framework. \begin{lstlisting}[float,caption={Code fragment oft the application}, label=lst:arch:rt:user:app] for (;;) { doPeriodicWork(); waitForNextPeriod(); } \end{lstlisting} \begin{lstlisting}[float,caption={Implementation in RtThread}, label=lst:arch:rt:user:rtthr] public boolean waitForNextPeriod() { synchronized(monitor) { // ps is the instance of // the PriorityScheduler int nxt = ps.next[nr] + period; int now = Scheduler.getNow() if (nxt-now < 0) { // missed deadline doMissAction(); return false; } else { // time for the next unblock ps.next[nr] = nxt; } // just schedule an interrupt // schedule() gets called. ps.block(); } return true; } \end{lstlisting} \begin{lstlisting}[float,caption={Implementation of the PriorityScheduler}, label=lst:arch:rt:user:prsched] public void schedule() { // Find the ready thread with // the highest priority. int nr = getReady(); // Search the list of sleeping threads // to find the nearest release time // in the future of a higher priority // thread than the one that will be // released now. int time = getNextTimer(nr); // This time is used for the next // timer interrupt. // Perform the context switch. dispatch(task[nr], time); // No access to locals after this point. // We are running in the NEW context! } \end{lstlisting} \subsection{Predictability} The architecture of JOP is designed to simplify WCET analysis. Every JVM bytecode maps to one ore more microcode instructions. Every microcode instruction takes exactly one cycle to execute. Thus, the execution time at the bytecode level is known cycle accurately. The microcode contains no data dependent or unbound loops that would compromise the WCET analysis (see Section~\ref{sec:wcet}). The worst-case time for dispatching is known cycle accurately on this architecture. Only the time behavior of the user scheduler needs to be analyzed. With the known WCET of every bytecode, as listed in Appendix~\ref{appx:bytecode}, the WCET of the scheduler can be obtained by examining it at the bytecode level. This can be done manually or with a WCET analysis tool. \subsection{Related Work} Several implementations of user-level schedulers in standard operating systems have been proposed. In \cite{REDLinux2003}, the Linux scheduling mechanism is enhanced. It is divided into a dispatcher and an allocator. The dispatcher remains in kernel space; while the allocator is implemented as a user space function. The allocator transforms four basic scheduling parameters (priority, start time, finish time and budget) into scheduling attributes to be used by the dispatcher. Many existing schedulers can be supported with this parameter set, but others that are based on different parameters cannot be implemented. This solution does not address the implementation of protocols for shared resources. A different approach defines a new API to enable applications to use application-defined scheduling in a way compatible with the scheduling model defined in POSIX \cite{787339}. It is implemented in the MaRTE OS, a minimal real-time kernel that provides the C and Ada language POSIX interface. This interface has been submitted to the Real-Time POSIX Working Group for consideration. One approach to user-level scheduling in Java can be found in \cite{Feizabadi:2003:UAS}. A thread \emph{multiplexor}, as part of the FLEX ahead-of-time compiler system for Java, is used for utility accrual scheduling. However, the underlying operating system -- in this case Linux -- can still be seen through the framework and there is no support for Java synchronization. \subsection{Summary} This section and Section~\ref{sec:rtprof} consider the implementation of real-time scheduling on a Java processor. The novelty of the described approach is in implementing functions usually associated with an RTOS in Java. That means that real-time Java is not based on an RTOS, and therefore not restricted to the functionality provided by the RTOS. With JOP, a self-contained real-time system in pure Java becomes possible. This system is augmented with a framework to provide scheduling functions at the application level. The implementation of the specification, described in Section~\ref{sec:rtprof}, is successfully used as the basis for a commercial real-time application in the railway industry. Future work will extend this framework to support multiple schedulers. A useful combination of schedulers would be: one for standard \code{java.lang.Thread} (optimized for throughput), one for soft real-time tasks and one for hard real-time tasks.

     
    Copyright (c) 1999 OPENCORES.ORG. All rights reserved.