Client and backend. This class is shared: the same code is compiled into your app and into your server, so everything on this page works in both.
public class Realtime
- Object
- Realtime
Entry point to real-time threads: periodic tasks that run at a fixed operating-system priority, are released on an absolute clock, and are not paused by the garbage collector.
Realtime rt = Realtime.getInstance();
rt.lockMemory(); // no page faults in a period
rt.setMemoryLimit(64L * 1024 * 1024); // fail fast instead of thrashing
RealtimeThread motor = rt.start("motor",
new RealtimeParameters().setPeriodNanos(1000000L).setPriority(80).setCpu(3),
new MotorLoop());
...
Log.p(motor.getStatistics().toString());
How the collector is kept away
A real-time task allocates in setup() and never in cycle(). The build rejects an
allocation that cycle() reaches, and at run time an allocation it could not see
ends the steady state with a RealtimeAllocationError – so the thread never needs
the collector to make room. The collector in turn never stops it for a whole cycle:
collections stay concurrent while a real-time thread exists, its stack is scanned
while it sleeps between periods, and it is released as soon as that one stack has
been read. Normal threads run below it, the collector’s included, so a busy
collector slows them, not it.
What this is and is not
On Linux with a PREEMPT_RT kernel this is firm real time: release latency in tens
of microseconds, measured, not proven. It is not certified hard real time and makes
no claim under any safety standard. Measure the loop on the device, under load,
with RealtimeThread.getStatistics().
Platforms
- Linux (the embedded and desktop Linux targets, the backend on Linux): every
feature. Real-time scheduling needs
CAP_SYS_NICEor anrtpriolimit. - Other translated targets (iOS, macOS, Windows, the backend elsewhere): the collector isolation and the allocation check, with normal-priority threads and a relative sleep.
- The simulator, Android, JavaScript: a best-effort Java thread with the same API, so the application runs and can be tested anywhere; there is no isolation from the collector and no allocation check at run time.
For port implementors
A port subclasses this class and overrides the protected primitives, which act on the calling thread. The defaults are the best-effort Java implementation.
Fields
public static final int FEATURE_SCHEDULING = 1 | Real-time scheduling (SCHED_FIFO on Linux). |
public static final int FEATURE_MEMORY_LOCK = 2 | Locking the process’s memory so it is never paged out (lockMemory()). |
public static final int FEATURE_GC_ISOLATION = 4 | Real-time threads are not paused by the garbage collector. |
public static final int FEATURE_ALLOCATION_CHECK = 8 | Allocation in a cycle is detected at run time. |
public static final int FEATURE_PREEMPT_RT_KERNEL = 16 | The kernel is a PREEMPT_RT kernel, which bounds its own latency. |
public static final int FEATURE_CPU_AFFINITY = 32 | Threads can be pinned to a CPU. |
protected static final int APPLIED_SCHEDULING = 1 | rawEnter(RealtimeThread, int, int, boolean) result bit: scheduling applied. |
protected static final int APPLIED_AFFINITY = 2 | rawEnter(RealtimeThread, int, int, boolean) result bit: CPU pinned. |
protected static final int APPLIED_ISOLATION = 4 | rawEnter(RealtimeThread, int, int, boolean) result bit: other threads moved off. |
Constructors
protected Realtime() | Ports construct subclasses; applications call getInstance(). |
Methods
Inherited methods
Field details
FEATURE_SCHEDULING
public static final int FEATURE_SCHEDULING = 1SCHED_FIFO on Linux).FEATURE_MEMORY_LOCK
public static final int FEATURE_MEMORY_LOCK = 2lockMemory()).FEATURE_GC_ISOLATION
public static final int FEATURE_GC_ISOLATION = 4FEATURE_ALLOCATION_CHECK
public static final int FEATURE_ALLOCATION_CHECK = 8FEATURE_PREEMPT_RT_KERNEL
public static final int FEATURE_PREEMPT_RT_KERNEL = 16PREEMPT_RT kernel, which bounds its own latency.FEATURE_CPU_AFFINITY
public static final int FEATURE_CPU_AFFINITY = 32APPLIED_SCHEDULING
protected static final int APPLIED_SCHEDULING = 1rawEnter(RealtimeThread, int, int, boolean) result bit: scheduling applied.APPLIED_AFFINITY
protected static final int APPLIED_AFFINITY = 2rawEnter(RealtimeThread, int, int, boolean) result bit: CPU pinned.APPLIED_ISOLATION
protected static final int APPLIED_ISOLATION = 4rawEnter(RealtimeThread, int, int, boolean) result bit: other threads moved off.Constructor details
Realtime
protected Realtime()getInstance().Method details
getInstance
public static Realtime getInstance()null: where
nothing is installed this is the best-effort Java implementation.install
public static void install(Realtime realtime)realtime the instance getInstance() returns; null restores the
default. Display installs the port’s instance when it starts and the backend
installs its own, which is why this class never names Display.isSupported
public boolean isSupported(int feature)true when the platform provides the feature, one of the FEATURE_ constants.getSupportedFeatures
protected int getSupportedFeatures()FEATURE_ constants this platform provides. The default
provides none.start
public RealtimeThread start(String name, RealtimeParameters params, RealtimeTask task)task.Parameters
nameString- the thread’s name, for logs and debuggers
paramsRealtimeParameters- its scheduling; copied, so later changes do not affect it
taskRealtimeTask- the work it runs
Returns
lockMemory
public boolean lockMemory()Returns
true when the memory was locked; false where unsupported or refused (Linux
needs CAP_IPC_LOCK or a large enough memlock limit)setMemoryLimit
public void setMemoryLimit(long bytes)Caps the memory of the process. After a collection that leaves the process
above bytes, a normal thread that asks for more memory gets an
OutOfMemoryError at once, instead of waiting for collections that cannot
free enough – a failure the application can handle, in place of a device that
slows to a crawl. Real-time threads are never refused: they do not allocate.
The limit is on the process’s resident memory, because that is the memory a device runs out of; it includes memory the heap holds and has not returned yet. An allocation is refused when a collection leaves the process over the limit, or without waiting for one once the process is a quarter over it. Linux only; elsewhere this does nothing.
Parameters
byteslong- the limit, or 0 for none
rawEnter
protected int rawEnter(RealtimeThread thread, int priority, int cpu, boolean isolate)Returns
APPLIED_ bits for what took effect, or a negative errnorawLeave
protected void rawLeave(RealtimeThread thread)rawStartPeriod
protected void rawStartPeriod(RealtimeThread thread, long periodNanos)rawWaitNextPeriod
protected int rawWaitNextPeriod(RealtimeThread thread)Returns
rawFreeze
protected void rawFreeze(RealtimeThread thread, int budget, RealtimeAllocationError error)budget per period throws error. The default has no run-time check.rawThaw
protected void rawThaw(RealtimeThread thread)rawStatistics
protected void rawStatistics(RealtimeThread thread, long[] out)out
(RealtimeStatistics.COUNT values).rawLastViolation
protected String rawLastViolation(RealtimeThread thread)null.rawLockMemory
protected int rawLockMemory()rawSetMemoryLimit
protected void rawSetMemoryLimit(long bytes, OutOfMemoryError error)error is the instance to throw. The default does
nothing.