This commit is contained in:
2025-10-25 03:02:53 +03:00
commit 043225d523
3416 changed files with 681196 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
[saferecl.rcu.base]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.base)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#base)
#### 32.11.2.3 Class template rcu_obj_base [saferecl.rcu.base]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12992)
Objects of type T to be protected by RCU inherit from
a specialization rcu_obj_base<T, D> for some D[.](#1.sentence-1)
namespace std {template<class T, class D = default_delete<T>>class rcu_obj_base {public:void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept; protected: rcu_obj_base() = default;
rcu_obj_base(const rcu_obj_base&) = default;
rcu_obj_base(rcu_obj_base&&) = default;
rcu_obj_base& operator=(const rcu_obj_base&) = default;
rcu_obj_base& operator=(rcu_obj_base&&) = default; ~rcu_obj_base() = default; private: D *deleter*; // *exposition only*};}
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13015)
The behavior of a program that adds specializations for rcu_obj_base is undefined[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13019)
T may be an incomplete type[.](#3.sentence-1)
It shall be complete before any member of the resulting specialization ofrcu_obj_base is referenced[.](#3.sentence-2)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13024)
D shall be a
function object type ([[function.objects]](function.objects "22.10Function objects")) for which,
given a value d of type D and
a value ptr of type T*,
the expression d(ptr) is valid[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13031)
D shall meet the requirements for[*Cpp17DefaultConstructible*](utility.arg.requirements#:Cpp17DefaultConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and [*Cpp17MoveAssignable*](utility.arg.requirements#:Cpp17MoveAssignable "16.4.4.2Template argument requirements[utility.arg.requirements]")[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13035)
If D is trivially copyable,
all specializations of rcu_obj_base<T, D> are trivially copyable[.](#6.sentence-1)
[🔗](#itemdecl:1)
`void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
`
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13044)
*Mandates*: T is an rcu-protectable type[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13048)
*Preconditions*: *this is
a base class subobject of an object x of type T[.](#8.sentence-1)
The member function rcu_obj_base<T, D>::retire was not invoked on x before[.](#8.sentence-2)
The assignment to *deleter* does not exit via an exception[.](#8.sentence-3)
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13056)
*Effects*: Evaluates *deleter* = std::move(d) and
schedules the evaluation of
the expression *deleter*(
addressof(x)) in the domain dom;
the behavior is undefined if that evaluation exits via an exception[.](#9.sentence-1)
May invoke scheduled evaluations in dom[.](#9.sentence-2)
[*Note [1](#note-1)*:
If such evaluations acquire resources held across any invocation ofretire on dom, deadlock can occur[.](#9.sentence-3)
— *end note*]

View File

@@ -0,0 +1,233 @@
[saferecl.rcu.domain]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.domain)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#domain)
#### 32.11.2.4 Class rcu_domain [saferecl.rcu.domain]
#### [32.11.2.4.1](#general) General [[saferecl.rcu.domain.general]](saferecl.rcu.domain.general)
namespace std {class rcu_domain {public: rcu_domain(const rcu_domain&) = delete;
rcu_domain& operator=(const rcu_domain&) = delete; void lock() noexcept; bool try_lock() noexcept; void unlock() noexcept; };}
[1](#general-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13089)
This class meets the requirements of[*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements")) and
provides regions of RCU protection[.](#general-1.sentence-1)
[*Example [1](#general-example-1)*: std::scoped_lock<rcu_domain> rlock(rcu_default_domain()); — *end example*]
[2](#general-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13099)
The functions lock and unlock establish
(possibly nested) regions of RCU protection[.](#general-2.sentence-1)
#### [32.11.2.4.2](#members) Member functions [[saferecl.rcu.domain.members]](saferecl.rcu.domain.members)
[🔗](#lib:lock,rcu_domain)
`void lock() noexcept;
`
[1](#members-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13111)
*Effects*: Opens a region of RCU protection[.](#members-1.sentence-1)
[2](#members-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13115)
*Remarks*: Calls to lock do not introduce a data race ([[intro.races]](intro.races "6.10.2.2Data races")) involving *this[.](#members-2.sentence-1)
[🔗](#lib:try_lock,rcu_domain)
`bool try_lock() noexcept;
`
[3](#members-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13127)
*Effects*: Equivalent to lock()[.](#members-3.sentence-1)
[4](#members-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13131)
*Returns*: true[.](#members-4.sentence-1)
[🔗](#lib:unlock,rcu_domain)
`void unlock() noexcept;
`
[5](#members-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13142)
*Preconditions*: A call to lock that opened an unclosed region of RCU protection
is sequenced before the call to unlock[.](#members-5.sentence-1)
[6](#members-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13148)
*Effects*: Closes the unclosed region of RCU protection
that was most recently opened[.](#members-6.sentence-1)
May invoke scheduled evaluations in *this[.](#members-6.sentence-2)
[7](#members-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13154)
[*Note [1](#members-note-1)*:
If such evaluations acquire resources
held across any invocation of unlock on *this,
deadlock can occur[.](#members-7.sentence-1)
— *end note*]
[8](#members-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13161)
*Remarks*: Calls to unlock do not introduce a data race involving *this[.](#members-8.sentence-1)
[*Note [2](#members-note-2)*:
Evaluation of scheduled evaluations can still cause a data race[.](#members-8.sentence-2)
— *end note*]
#### [32.11.2.4.3](#func) Non-member functions [[saferecl.rcu.domain.func]](saferecl.rcu.domain.func)
[🔗](#lib:rcu_default_domain)
`rcu_domain& rcu_default_domain() noexcept;
`
[1](#func-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13177)
*Returns*: A reference to a static-duration object of type rcu_domain[.](#func-1.sentence-1)
A reference to the same object is returned every time this function is called[.](#func-1.sentence-2)
[🔗](#lib:rcu_synchronize)
`void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
`
[2](#func-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13189)
*Effects*: If the call to rcu_synchronize does not strongly happen before
the lock opening an RCU protection region R on dom,
blocks until the unlock closing R happens[.](#func-2.sentence-1)
[3](#func-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13195)
*Synchronization*: The unlock closing R strongly happens before the return from rcu_synchronize[.](#func-3.sentence-1)
[🔗](#lib:rcu_barrier)
`void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
`
[4](#func-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13207)
*Effects*: May evaluate any scheduled evaluations in dom[.](#func-4.sentence-1)
For any evaluation that happens before the call to rcu_barrier and
that schedules an evaluation E in dom,
blocks until E has been evaluated[.](#func-4.sentence-2)
[5](#func-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13214)
*Synchronization*: The evaluation of any such E strongly happens before the return from rcu_barrier[.](#func-5.sentence-1)
[*Note [1](#func-note-1)*:
A call to rcu_barrier does not imply
a call to rcu_synchronize and vice versa[.](#func-5.sentence-2)
— *end note*]
[🔗](#lib:rcu_retire)
`template<class T, class D = default_delete<T>>
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
`
[6](#func-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13232)
*Mandates*: is_move_constructible_v<D> is true and
the expression d(p) is well-formed[.](#func-6.sentence-1)
[7](#func-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13237)
*Preconditions*: D meets the [*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") requirements[.](#func-7.sentence-1)
[8](#func-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13242)
*Effects*: May allocate memory[.](#func-8.sentence-1)
It is unspecified whether the memory allocation
is performed by invoking operator new[.](#func-8.sentence-2)
Initializes an object d1 of type D from std::move(d)[.](#func-8.sentence-3)
Schedules the evaluation of d1(p) in the domain dom;
the behavior is undefined if that evaluation exits via an exception[.](#func-8.sentence-4)
May invoke scheduled evaluations in dom[.](#func-8.sentence-5)
[*Note [2](#func-note-2)*:
If rcu_retire exits via an exception, no evaluation
is scheduled[.](#func-8.sentence-6)
— *end note*]
[9](#func-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13256)
*Throws*: bad_alloc or any exception thrown by the initialization of d1[.](#func-9.sentence-1)
[10](#func-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13260)
[*Note [3](#func-note-3)*:
If scheduled evaluations acquire resources
held across any invocation of rcu_retire on dom,
deadlock can occur[.](#func-10.sentence-1)
— *end note*]

View File

@@ -0,0 +1,131 @@
[saferecl.rcu.domain.func]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.domain.func)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#domain.func)
#### 32.11.2.4 Class rcu_domain [[saferecl.rcu.domain]](saferecl.rcu.domain#func)
#### 32.11.2.4.3 Non-member functions [saferecl.rcu.domain.func]
[🔗](#lib:rcu_default_domain)
`rcu_domain& rcu_default_domain() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13177)
*Returns*: A reference to a static-duration object of type rcu_domain[.](#1.sentence-1)
A reference to the same object is returned every time this function is called[.](#1.sentence-2)
[🔗](#lib:rcu_synchronize)
`void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
`
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13189)
*Effects*: If the call to rcu_synchronize does not strongly happen before
the lock opening an RCU protection region R on dom,
blocks until the unlock closing R happens[.](#2.sentence-1)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13195)
*Synchronization*: The unlock closing R strongly happens before the return from rcu_synchronize[.](#3.sentence-1)
[🔗](#lib:rcu_barrier)
`void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
`
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13207)
*Effects*: May evaluate any scheduled evaluations in dom[.](#4.sentence-1)
For any evaluation that happens before the call to rcu_barrier and
that schedules an evaluation E in dom,
blocks until E has been evaluated[.](#4.sentence-2)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13214)
*Synchronization*: The evaluation of any such E strongly happens before the return from rcu_barrier[.](#5.sentence-1)
[*Note [1](#note-1)*:
A call to rcu_barrier does not imply
a call to rcu_synchronize and vice versa[.](#5.sentence-2)
— *end note*]
[🔗](#lib:rcu_retire)
`template<class T, class D = default_delete<T>>
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
`
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13232)
*Mandates*: is_move_constructible_v<D> is true and
the expression d(p) is well-formed[.](#6.sentence-1)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13237)
*Preconditions*: D meets the [*Cpp17MoveConstructible*](utility.arg.requirements#:Cpp17MoveConstructible "16.4.4.2Template argument requirements[utility.arg.requirements]") and[*Cpp17Destructible*](utility.arg.requirements#:Cpp17Destructible "16.4.4.2Template argument requirements[utility.arg.requirements]") requirements[.](#7.sentence-1)
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13242)
*Effects*: May allocate memory[.](#8.sentence-1)
It is unspecified whether the memory allocation
is performed by invoking operator new[.](#8.sentence-2)
Initializes an object d1 of type D from std::move(d)[.](#8.sentence-3)
Schedules the evaluation of d1(p) in the domain dom;
the behavior is undefined if that evaluation exits via an exception[.](#8.sentence-4)
May invoke scheduled evaluations in dom[.](#8.sentence-5)
[*Note [2](#note-2)*:
If rcu_retire exits via an exception, no evaluation
is scheduled[.](#8.sentence-6)
— *end note*]
[9](#9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13256)
*Throws*: bad_alloc or any exception thrown by the initialization of d1[.](#9.sentence-1)
[10](#10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13260)
[*Note [3](#note-3)*:
If scheduled evaluations acquire resources
held across any invocation of rcu_retire on dom,
deadlock can occur[.](#10.sentence-1)
— *end note*]

View File

@@ -0,0 +1,30 @@
[saferecl.rcu.domain.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.domain.general)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#domain.general)
#### 32.11.2.4 Class rcu_domain [[saferecl.rcu.domain]](saferecl.rcu.domain#general)
#### 32.11.2.4.1 General [saferecl.rcu.domain.general]
namespace std {class rcu_domain {public: rcu_domain(const rcu_domain&) = delete;
rcu_domain& operator=(const rcu_domain&) = delete; void lock() noexcept; bool try_lock() noexcept; void unlock() noexcept; };}
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13089)
This class meets the requirements of[*Cpp17Lockable*](thread.req.lockable.req#:Cpp17Lockable "32.2.5.3Cpp17Lockable requirements[thread.req.lockable.req]") ([[thread.req.lockable.req]](thread.req.lockable.req "32.2.5.3Cpp17Lockable requirements")) and
provides regions of RCU protection[.](#1.sentence-1)
[*Example [1](#example-1)*: std::scoped_lock<rcu_domain> rlock(rcu_default_domain()); — *end example*]
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13099)
The functions lock and unlock establish
(possibly nested) regions of RCU protection[.](#2.sentence-1)

View File

@@ -0,0 +1,90 @@
[saferecl.rcu.domain.members]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.domain.members)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#domain.members)
#### 32.11.2.4 Class rcu_domain [[saferecl.rcu.domain]](saferecl.rcu.domain#members)
#### 32.11.2.4.2 Member functions [saferecl.rcu.domain.members]
[🔗](#lib:lock,rcu_domain)
`void lock() noexcept;
`
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13111)
*Effects*: Opens a region of RCU protection[.](#1.sentence-1)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13115)
*Remarks*: Calls to lock do not introduce a data race ([[intro.races]](intro.races "6.10.2.2Data races")) involving *this[.](#2.sentence-1)
[🔗](#lib:try_lock,rcu_domain)
`bool try_lock() noexcept;
`
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13127)
*Effects*: Equivalent to lock()[.](#3.sentence-1)
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13131)
*Returns*: true[.](#4.sentence-1)
[🔗](#lib:unlock,rcu_domain)
`void unlock() noexcept;
`
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13142)
*Preconditions*: A call to lock that opened an unclosed region of RCU protection
is sequenced before the call to unlock[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13148)
*Effects*: Closes the unclosed region of RCU protection
that was most recently opened[.](#6.sentence-1)
May invoke scheduled evaluations in *this[.](#6.sentence-2)
[7](#7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13154)
[*Note [1](#note-1)*:
If such evaluations acquire resources
held across any invocation of unlock on *this,
deadlock can occur[.](#7.sentence-1)
— *end note*]
[8](#8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L13161)
*Remarks*: Calls to unlock do not introduce a data race involving *this[.](#8.sentence-1)
[*Note [2](#note-2)*:
Evaluation of scheduled evaluations can still cause a data race[.](#8.sentence-2)
— *end note*]

View File

@@ -0,0 +1,75 @@
[saferecl.rcu.general]
# 32 Concurrency support library [[thread]](./#thread)
## 32.11 Safe reclamation [[saferecl]](saferecl#rcu.general)
### 32.11.2 Read-copy update (RCU) [[saferecl.rcu]](saferecl.rcu#general)
#### 32.11.2.1 General [saferecl.rcu.general]
[1](#1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12920)
RCU is a synchronization mechanism
that can be used for linked data structures
that are frequently read, but seldom updated[.](#1.sentence-1)
RCU does not provide mutual exclusion,
but instead allows the user to schedule specified actions
such as deletion at some later time[.](#1.sentence-2)
[2](#2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12928)
A class type T is [*rcu-protectable*](#def:rcu-protectable "32.11.2.1General[saferecl.rcu.general]") if it has exactly one base class of type rcu_obj_base<T, D> for some D, and that base is public and non-virtual, and
it has no base classes of type rcu_obj_base<X, Y> for any other combination X, Y[.](#2.sentence-1)
An object is rcu-protectable if it is of rcu-protectable type[.](#2.sentence-2)
[3](#3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12936)
An invocation of unlock U on an rcu_domain dom corresponds to an invocation of lock L on dom if L is sequenced before U and either
- [(3.1)](#3.1)
no other invocation of lock on dom is sequenced after L and before U, or
- [(3.2)](#3.2)
every invocation of unlock U2 on dom such that L is sequenced before U2 and U2 is sequenced before U corresponds to an invocation of lock L2 on dom such that L is sequenced before L2 and L2 is sequenced before U2[.](#3.sentence-1)
[*Note [1](#note-1)*:
This pairs nested locks and unlocks on a given domain in each thread[.](#3.sentence-2)
— *end note*]
[4](#4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12954)
A [*region of RCU protection*](#def:region_of_RCU_protection "32.11.2.1General[saferecl.rcu.general]") on a domain dom starts with a lock L on dom and
ends with its corresponding unlock U[.](#4.sentence-1)
[5](#5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12959)
Given a region of RCU protection R on a domain dom and
given an evaluation E that scheduled another evaluation F in dom,
if E does not strongly happen before the start of R,
the end of R strongly happens before evaluating F[.](#5.sentence-1)
[6](#6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/threads.tex#L12965)
The evaluation of a scheduled evaluation is potentially concurrent with
any other scheduled evaluation[.](#6.sentence-1)
Each scheduled evaluation is evaluated at most once[.](#6.sentence-2)