@@ -53,6 +53,45 @@ int sys_rseq(struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) {
5353 return raw_syscall (kRseqSyscall , rseq, rseq_len, flags, sig);
5454}
5555
56+ // RSeqRegistration represents a registered struct rseq, which is unregistered
57+ // when the RSeqRegistration is destroyed.
58+ class RSeqRegistration {
59+ public:
60+ ~RSeqRegistration () {
61+ if (rseq_) {
62+ sys_rseq (rseq_, rseq_len_, kRseqFlagUnregister , sig_);
63+ }
64+ }
65+
66+ RSeqRegistration (const RSeqRegistration&) = delete ;
67+ RSeqRegistration& operator =(const RSeqRegistration&) = delete ;
68+ RSeqRegistration (RSeqRegistration&&) = delete ;
69+ RSeqRegistration& operator =(RSeqRegistration&&) = delete ;
70+
71+ int errno () const { return errno_; }
72+
73+ private:
74+ RSeqRegistration (struct rseq * rseq, uint32_t rseq_len, uint32_t sig,
75+ int errno)
76+ : rseq_(rseq), rseq_len_(rseq_len), sig_(sig), errno_(errno) {}
77+
78+ struct rseq * rseq_;
79+ uint32_t rseq_len_;
80+ uint32_t sig_;
81+ int errno_;
82+
83+ friend RSeqRegistration RSeqRegister (struct rseq *, uint32_t , int , uint32_t );
84+ };
85+
86+ RSeqRegistration RSeqRegister (struct rseq * rseq, uint32_t rseq_len, int flags,
87+ uint32_t sig) {
88+ int ret = sys_rseq (rseq, rseq_len, flags, sig);
89+ if (int errno = sys_errno (ret); errno != 0 ) {
90+ return RSeqRegistration (nullptr , 0 , 0 , errno);
91+ }
92+ return RSeqRegistration (rseq, rseq_len, sig, 0 );
93+ }
94+
5695// Test that rseq must be aligned.
5796int TestUnaligned () {
5897 constexpr uintptr_t kRequiredAlignment = alignof (rseq);
@@ -64,8 +103,8 @@ int TestUnaligned() {
64103 ptr++;
65104 }
66105
67- int ret = sys_rseq (reinterpret_cast <rseq*>(ptr), sizeof (rseq), 0 , 0 );
68- if (sys_errno (ret ) != EINVAL) {
106+ auto reg = RSeqRegister (reinterpret_cast <rseq*>(ptr), sizeof (rseq), 0 , 0 );
107+ if (reg. errno ( ) != EINVAL) {
69108 return 1 ;
70109 }
71110 return 0 ;
@@ -74,8 +113,8 @@ int TestUnaligned() {
74113// Sanity test that registration works.
75114int TestRegister () {
76115 struct rseq r = {};
77- int ret = sys_rseq (&r, sizeof (r), 0 , 0 );
78- if (sys_errno (ret ) != 0 ) {
116+ auto reg = RSeqRegister (&r, sizeof (r), 0 , 0 );
117+ if (reg. errno ( ) != 0 ) {
79118 return 1 ;
80119 }
81120 return 0 ;
@@ -84,13 +123,13 @@ int TestRegister() {
84123// Registration can't be done twice.
85124int TestDoubleRegister () {
86125 struct rseq r = {};
87- int ret = sys_rseq (&r, sizeof (r), 0 , 0 );
88- if (sys_errno (ret ) != 0 ) {
126+ auto reg1 = RSeqRegister (&r, sizeof (r), 0 , 0 );
127+ if (reg1. errno ( ) != 0 ) {
89128 return 1 ;
90129 }
91130
92- ret = sys_rseq (&r, sizeof (r), 0 , 0 );
93- if (sys_errno (ret ) != EBUSY) {
131+ auto reg2 = RSeqRegister (&r, sizeof (r), 0 , 0 );
132+ if (reg2. errno ( ) != EBUSY) {
94133 return 1 ;
95134 }
96135
@@ -111,8 +150,8 @@ int TestRegisterUnregister() {
111150 return 1 ;
112151 }
113152
114- ret = sys_rseq (&r, sizeof (r), 0 , 0 );
115- if (sys_errno (ret ) != 0 ) {
153+ auto reg = RSeqRegister (&r, sizeof (r), 0 , 0 );
154+ if (reg. errno ( ) != 0 ) {
116155 return 1 ;
117156 }
118157
@@ -123,14 +162,14 @@ int TestRegisterUnregister() {
123162int TestUnregisterDifferentPtr () {
124163 struct rseq r = {};
125164
126- int ret = sys_rseq (&r, sizeof (r), 0 , 0 );
127- if (sys_errno (ret ) != 0 ) {
165+ auto reg = RSeqRegister (&r, sizeof (r), 0 , 0 );
166+ if (reg. errno ( ) != 0 ) {
128167 return 1 ;
129168 }
130169
131170 struct rseq r2 = {};
132171
133- ret = sys_rseq (&r2, sizeof (r2), kRseqFlagUnregister , 0 );
172+ int ret = sys_rseq (&r2, sizeof (r2), kRseqFlagUnregister , 0 );
134173 if (sys_errno (ret) != EINVAL) {
135174 return 1 ;
136175 }
@@ -143,12 +182,12 @@ int TestUnregisterDifferentSignature() {
143182 constexpr int kSignature = 0 ;
144183
145184 struct rseq r = {};
146- int ret = sys_rseq (&r, sizeof (r), 0 , kSignature );
147- if (sys_errno (ret ) != 0 ) {
185+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kSignature );
186+ if (reg. errno ( ) != 0 ) {
148187 return 1 ;
149188 }
150189
151- ret = sys_rseq (&r, sizeof (r), kRseqFlagUnregister , kSignature + 1 );
190+ int ret = sys_rseq (&r, sizeof (r), kRseqFlagUnregister , kSignature + 1 );
152191 if (sys_errno (ret) != EPERM) {
153192 return 1 ;
154193 }
@@ -161,8 +200,8 @@ int TestCPU() {
161200 struct rseq r = {};
162201 r.cpu_id = kRseqCPUIDUninitialized ;
163202
164- int ret = sys_rseq (&r, sizeof (r), 0 , 0 );
165- if (sys_errno (ret ) != 0 ) {
203+ auto reg = RSeqRegister (&r, sizeof (r), 0 , 0 );
204+ if (reg. errno ( ) != 0 ) {
166205 return 1 ;
167206 }
168207
@@ -179,8 +218,8 @@ int TestCPU() {
179218// Critical section is eventually aborted.
180219int TestAbort () {
181220 struct rseq r = {};
182- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature );
183- if (sys_errno (ret ) != 0 ) {
221+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature );
222+ if (reg. errno ( ) != 0 ) {
184223 return 1 ;
185224 }
186225
@@ -201,8 +240,8 @@ int TestAbort() {
201240// Abort may be before the critical section.
202241int TestAbortBefore () {
203242 struct rseq r = {};
204- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature );
205- if (sys_errno (ret ) != 0 ) {
243+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature );
244+ if (reg. errno ( ) != 0 ) {
206245 return 1 ;
207246 }
208247
@@ -223,8 +262,8 @@ int TestAbortBefore() {
223262// Signature must match.
224263int TestAbortSignature () {
225264 struct rseq r = {};
226- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature + 1 );
227- if (sys_errno (ret ) != 0 ) {
265+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature + 1 );
266+ if (reg. errno ( ) != 0 ) {
228267 return 1 ;
229268 }
230269
@@ -245,8 +284,8 @@ int TestAbortSignature() {
245284// Abort must not be in the critical section.
246285int TestAbortPreCommit () {
247286 struct rseq r = {};
248- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature + 1 );
249- if (sys_errno (ret ) != 0 ) {
287+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature + 1 );
288+ if (reg. errno ( ) != 0 ) {
250289 return 1 ;
251290 }
252291
@@ -267,8 +306,8 @@ int TestAbortPreCommit() {
267306// rseq.rseq_cs is cleared on abort.
268307int TestAbortClearsCS () {
269308 struct rseq r = {};
270- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature );
271- if (sys_errno (ret ) != 0 ) {
309+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature );
310+ if (reg. errno ( ) != 0 ) {
272311 return 1 ;
273312 }
274313
@@ -293,8 +332,8 @@ int TestAbortClearsCS() {
293332// rseq.rseq_cs is cleared on abort outside of critical section.
294333int TestInvalidAbortClearsCS () {
295334 struct rseq r = {};
296- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature );
297- if (sys_errno (ret ) != 0 ) {
335+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature );
336+ if (reg. errno ( ) != 0 ) {
298337 return 1 ;
299338 }
300339
@@ -306,6 +345,11 @@ int TestInvalidAbortClearsCS() {
306345 reinterpret_cast <uint64_t >(&rseq_loop_start);
307346 cs.abort_ip = reinterpret_cast <uint64_t >(&rseq_loop_abort);
308347
348+ // Ensure that the kernel, running on this CPU, will observe the preceding
349+ // stores to cs before the following store to r.rseq_cs. This is a compiler
350+ // barrier, equivalent to std::atomic_signal_fence() but without stdlib.
351+ asm volatile (" " ::: " memory" );
352+
309353 __atomic_store_n (&r.rseq_cs , &cs, __ATOMIC_RELAXED);
310354
311355 // When the next abort condition occurs, the kernel will clear cs once it
@@ -322,11 +366,11 @@ int TestInvalidAbortClearsCS() {
322366// rseq.cpu_id_start is overwritten by RSEQ fence.
323367int TestMembarrierResetsCpuIdStart () {
324368 struct rseq r = {};
325- int ret = sys_rseq (&r, sizeof (r), 0 , kRseqSignature );
326- if (sys_errno (ret ) != 0 ) {
369+ auto reg = RSeqRegister (&r, sizeof (r), 0 , kRseqSignature );
370+ if (reg. errno ( ) != 0 ) {
327371 return 1 ;
328372 }
329- ret = sys_membarrier (MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0 );
373+ int ret = sys_membarrier (MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0 );
330374 if (sys_errno (ret) != 0 ) {
331375 return 1 ;
332376 }
0 commit comments