| 1 | =====================
|
| 2 | Restartable Sequences
|
| 3 | =====================
|
| 4 |
|
| 5 | Restartable Sequences allow to register a per thread userspace memory area
|
| 6 | to be used as an ABI between kernel and userspace for three purposes:
|
| 7 |
|
| 8 | * userspace restartable sequences
|
| 9 |
|
| 10 | * quick access to read the current CPU number, node ID from userspace
|
| 11 |
|
| 12 | * scheduler time slice extensions
|
| 13 |
|
| 14 | Restartable sequences (per-cpu atomics)
|
| 15 | ---------------------------------------
|
| 16 |
|
| 17 | Restartable sequences allow userspace to perform update operations on
|
| 18 | per-cpu data without requiring heavyweight atomic operations. The actual
|
| 19 | ABI is unfortunately only available in the code and selftests.
|
| 20 |
|
| 21 | Quick access to CPU number, node ID
|
| 22 | -----------------------------------
|
| 23 |
|
| 24 | Allows to implement per CPU data efficiently. Documentation is in code and
|
| 25 | selftests. :(
|
| 26 |
|
| 27 | Optimized RSEQ V2
|
| 28 | -----------------
|
| 29 |
|
| 30 | On architectures which utilize the generic entry code and generic TIF bits
|
| 31 | the kernel supports runtime optimizations for RSEQ, which also enable
|
| 32 | enhanced features like scheduler time slice extensions.
|
| 33 |
|
| 34 | To enable them a task has to register the RSEQ region with at least the
|
| 35 | length advertised by getauxval(AT_RSEQ_FEATURE_SIZE).
|
| 36 |
|
| 37 | If existing binaries register with RSEQ_ORIG_SIZE (32 bytes), the kernel
|
| 38 | keeps the legacy low performance mode enabled to fulfil the expectations
|
| 39 | of existing users regarding the original RSEQ implementation behaviour.
|
| 40 |
|
| 41 | The following table documents the ABI and behavioral guarantees of the
|
| 42 | legacy and the optimized V2 mode.
|
| 43 |
|
| 44 | .. list-table:: RSEQ modes
|
| 45 | :header-rows: 1
|
| 46 |
|
| 47 | * - Nr
|
| 48 | - What
|
| 49 |
|
| 50 | - Legacy
|
| 51 | - Optimized V2
|
| 52 |
|
| 53 | * - 1
|
| 54 | - The cpu_id_start, cpu_id, node_id and mm_cid fields (User mode read
|
| 55 | only)
|
| 56 | .. Legacy
|
| 57 | - Updated by the kernel unconditionally after each context switch and
|
| 58 | before signal delivery
|
| 59 | .. Optimized V2
|
| 60 | - Updated by the kernel if and only if they change, i.e. if the task
|
| 61 | is migrated or mm_cid changes
|
| 62 |
|
| 63 | * - 2
|
| 64 | - The rseq_cs critical section field
|
| 65 | .. Legacy
|
| 66 | - Evaluated and handled unconditionally after each context switch and
|
| 67 | before signal delivery
|
| 68 | .. Optimized V2
|
| 69 | - Evaluated and handled conditionally only when user space was
|
| 70 | interrupted and was scheduled out or before delivering a signal in
|
| 71 | the interrupted context.
|
| 72 |
|
| 73 | * - 3
|
| 74 | - Read only fields
|
| 75 | .. Legacy
|
| 76 | - No strict enforcement except in debug mode
|
| 77 | .. Optimized V2
|
| 78 | - Strict enforcement
|
| 79 |
|
| 80 | * - 4
|
| 81 | - membarrier(...RSEQ)
|
| 82 | .. Legacy
|
| 83 | - All running threads of the process are interrupted and the ID fields
|
| 84 | are rewritten and eventually active critical sections are aborted
|
| 85 | before they return to user space. All threads which are scheduled
|
| 86 | out whether voluntary or not are covered by #1/#2 above.
|
| 87 | .. Optimized V2
|
| 88 | - All running threads of the process are interrupted and eventually
|
| 89 | active critical sections are aborted before these threads return to
|
| 90 | user space. The ID fields are only updated if changed as a
|
| 91 | consequence of the interrupt. All threads which are scheduled out
|
| 92 | whether voluntary or not are covered by #1/#2 above.
|
| 93 |
|
| 94 | * - 5
|
| 95 | - Time slice extensions
|
| 96 | .. Legacy
|
| 97 | - Not supported
|
| 98 | .. Optimized V2
|
| 99 | - Supported
|
| 100 |
|
| 101 | The legacy mode is obviously less performant as it does unconditional
|
| 102 | updates and critical section checks even if not strictly required by the
|
| 103 | ABI contract. That can't be changed anymore as some users depend on that
|
| 104 | observed behavior, which in turn enables them to violate the ABI and
|
| 105 | overwrite the cpu_id_start field for their own purposes. This is obviously
|
| 106 | discouraged as it renders RSEQ incompatible with the intended usage and
|
| 107 | breaks the expectation of other libraries in the same application.
|
| 108 |
|
| 109 | The ABI compliant optimized v2 mode, which respects the read only fields,
|
| 110 | does not require unconditional updates and therefore is way more
|
| 111 | performant. The kernel validates the read only fields for compliance. If
|
| 112 | user space modifies them, the process is killed. Compliant usage allows
|
| 113 | multiple libraries in the same application to benefit from the RSEQ
|
| 114 | functionality without disturbing each other. The ABI compliant optimized v2
|
| 115 | mode also enables extended RSEQ features like time slice extensions.
|
| 116 |
|
| 117 |
|
| 118 | Scheduler time slice extensions
|
| 119 | -------------------------------
|
| 120 |
|
| 121 | This allows a thread to request a time slice extension when it enters a
|
| 122 | critical section to avoid contention on a resource when the thread is
|
| 123 | scheduled out inside of the critical section.
|
| 124 |
|
| 125 | The prerequisites for this functionality are:
|
| 126 |
|
| 127 | * Enabled in Kconfig
|
| 128 |
|
| 129 | * Enabled at boot time (default is enabled)
|
| 130 |
|
| 131 | * A rseq userspace pointer has been registered for the thread in
|
| 132 | optimized V2 mode
|
| 133 |
|
| 134 | The thread has to enable the functionality via prctl(2)::
|
| 135 |
|
| 136 | prctl(PR_RSEQ_SLICE_EXTENSION, PR_RSEQ_SLICE_EXTENSION_SET,
|
| 137 | PR_RSEQ_SLICE_EXT_ENABLE, 0, 0);
|
| 138 |
|
| 139 | prctl() returns 0 on success or otherwise with the following error codes:
|
| 140 |
|
| 141 | ========= ==============================================================
|
| 142 | Errorcode Meaning
|
| 143 | ========= ==============================================================
|
| 144 | EINVAL Functionality not available or invalid function arguments.
|
| 145 | Note: arg4 and arg5 must be zero
|
| 146 | ENOTSUPP Functionality was disabled on the kernel command line
|
| 147 | ENXIO Available, but no rseq user struct registered
|
| 148 | ========= ==============================================================
|
| 149 |
|
| 150 | The state can be also queried via prctl(2)::
|
| 151 |
|
| 152 | prctl(PR_RSEQ_SLICE_EXTENSION, PR_RSEQ_SLICE_EXTENSION_GET, 0, 0, 0);
|
| 153 |
|
| 154 | prctl() returns ``PR_RSEQ_SLICE_EXT_ENABLE`` when it is enabled or 0 if
|
| 155 | disabled. Otherwise it returns with the following error codes:
|
| 156 |
|
| 157 | ========= ==============================================================
|
| 158 | Errorcode Meaning
|
| 159 | ========= ==============================================================
|
| 160 | EINVAL Functionality not available or invalid function arguments.
|
| 161 | Note: arg3 and arg4 and arg5 must be zero
|
| 162 | ========= ==============================================================
|
| 163 |
|
| 164 | The availability and status is also exposed via the rseq ABI struct flags
|
| 165 | field via the ``RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE_BIT`` and the
|
| 166 | ``RSEQ_CS_FLAG_SLICE_EXT_ENABLED_BIT``. These bits are read-only for user
|
| 167 | space and only for informational purposes.
|
| 168 |
|
| 169 | If the mechanism was enabled via prctl(), the thread can request a time
|
| 170 | slice extension by setting rseq::slice_ctrl::request to 1. If the thread is
|
| 171 | interrupted and the interrupt results in a reschedule request in the
|
| 172 | kernel, then the kernel can grant a time slice extension and return to
|
| 173 | userspace instead of scheduling out. The length of the extension is
|
| 174 | determined by debugfs:rseq/slice_ext_nsec. The default value is 5 usec; which
|
| 175 | is the minimum value. It can be incremented to 50 usecs, however doing so
|
| 176 | can/will affect the minimum scheduling latency.
|
| 177 |
|
| 178 | Any proposed changes to this default will have to come with a selftest and
|
| 179 | rseq-slice-hist.py output that shows the new value has merrit.
|
| 180 |
|
| 181 | The kernel indicates the grant by clearing rseq::slice_ctrl::request and
|
| 182 | setting rseq::slice_ctrl::granted to 1. If there is a reschedule of the
|
| 183 | thread after granting the extension, the kernel clears the granted bit to
|
| 184 | indicate that to userspace.
|
| 185 |
|
| 186 | If the request bit is still set when the leaving the critical section,
|
| 187 | userspace can clear it and continue.
|
| 188 |
|
| 189 | If the granted bit is set, then userspace invokes rseq_slice_yield(2) when
|
| 190 | leaving the critical section to relinquish the CPU. The kernel enforces
|
| 191 | this by arming a timer to prevent misbehaving userspace from abusing this
|
| 192 | mechanism.
|
| 193 |
|
| 194 | If both the request bit and the granted bit are false when leaving the
|
| 195 | critical section, then this indicates that a grant was revoked and no
|
| 196 | further action is required by userspace.
|
| 197 |
|
| 198 | The required code flow is as follows::
|
| 199 |
|
| 200 | rseq->slice_ctrl.request = 1;
|
| 201 | barrier(); // Prevent compiler reordering
|
| 202 | critical_section();
|
| 203 | barrier(); // Prevent compiler reordering
|
| 204 | rseq->slice_ctrl.request = 0;
|
| 205 | if (rseq->slice_ctrl.granted)
|
| 206 | rseq_slice_yield();
|
| 207 |
|
| 208 | As all of this is strictly CPU local, there are no atomicity requirements.
|
| 209 | Checking the granted state is racy, but that cannot be avoided at all::
|
| 210 |
|
| 211 | if (rseq->slice_ctrl.granted)
|
| 212 | -> Interrupt results in schedule and grant revocation
|
| 213 | rseq_slice_yield();
|
| 214 |
|
| 215 | So there is no point in pretending that this might be solved by an atomic
|
| 216 | operation.
|
| 217 |
|
| 218 | If the thread issues a syscall other than rseq_slice_yield(2) within the
|
| 219 | granted timeslice extension, the grant is also revoked and the CPU is
|
| 220 | relinquished immediately when entering the kernel. This is required as
|
| 221 | syscalls might consume arbitrary CPU time until they reach a scheduling
|
| 222 | point when the preemption model is either NONE or VOLUNTARY and therefore
|
| 223 | might exceed the grant by far.
|
| 224 |
|
| 225 | The preferred solution for user space is to use rseq_slice_yield(2) which
|
| 226 | is side effect free. The support for arbitrary syscalls is required to
|
| 227 | support onion layer architectured applications, where the code handling the
|
| 228 | critical section and requesting the time slice extension has no control
|
| 229 | over the code within the critical section.
|
| 230 |
|
| 231 | The kernel enforces flag consistency and terminates the thread with SIGSEGV
|
| 232 | if it detects a violation.
|