Skip to content

Commit 04b65ba

Browse files
authored
Merge 2023-06 LWG Motion 6
P2545R4 Read-Copy Update (RCU)
2 parents 48b0a3b + 81111d6 commit 04b65ba

File tree

3 files changed

+364
-1
lines changed

3 files changed

+364
-1
lines changed

source/lib-intro.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1114,6 +1114,7 @@
11141114
\tcode{<random>} \\
11151115
\tcode{<ranges>} \\
11161116
\tcode{<ratio>} \\
1117+
\tcode{<rcu>} \\
11171118
\tcode{<regex>} \\
11181119
\tcode{<scoped_allocator>} \\
11191120
\tcode{<semaphore>} \\

source/support.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@
706706
#define @\defnlibxname{cpp_lib_ranges_to_container}@ 202202L // also in \libheader{ranges}
707707
#define @\defnlibxname{cpp_lib_ranges_zip}@ 202110L // also in \libheader{ranges}, \libheader{tuple}, \libheader{utility}
708708
#define @\defnlibxname{cpp_lib_raw_memory_algorithms}@ 201606L // also in \libheader{memory}
709+
#define @\defnlibxname{cpp_lib_rcu}@ 202306L // also in \libheader{rcu}
709710
#define @\defnlibxname{cpp_lib_reference_from_temporary}@ 202202L // also in \libheader{type_traits}
710711
#define @\defnlibxname{cpp_lib_remove_cvref}@ 201711L // also in \libheader{type_traits}
711712
#define @\defnlibxname{cpp_lib_result_of_sfinae}@ 201210L // also in \libheader{functional}, \libheader{type_traits}

source/threads.tex

Lines changed: 362 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
\ref{thread.condition}& Condition variables & \tcode{<condition_variable>} \\ \rowsep
2121
\ref{thread.sema} & Semaphores & \tcode{<semaphore>} \\ \rowsep
2222
\ref{thread.coord} & Coordination types & \tcode{<latch>} \tcode{<barrier>} \\ \rowsep
23-
\ref{futures} & Futures & \tcode{<future>} \\
23+
\ref{futures} & Futures & \tcode{<future>} \\ \rowsep
24+
\ref{saferecl} & Safe reclamation & \tcode{<rcu>} \\
2425
\end{libsumtab}
2526

2627
\rSec1[thread.req]{Requirements}
@@ -11661,3 +11662,363 @@
1166111662
\effects
1166211663
As if by \tcode{x.swap(y)}.
1166311664
\end{itemdescr}
11665+
11666+
\rSec1[saferecl]{Safe reclamation}
11667+
11668+
\rSec2[saferecl.general]{General}
11669+
11670+
\pnum
11671+
Subclause \ref{saferecl} contains safe-reclamation techniques, which are most
11672+
frequently used to straightforwardly resolve access-deletion races.
11673+
11674+
\rSec2[saferecl.rcu]{Read-copy update (RCU)}
11675+
11676+
\rSec3[saferecl.rcu.general]{General}
11677+
11678+
\pnum
11679+
RCU is a synchronization mechanism
11680+
that can be used for linked data structures
11681+
that are frequently read, but seldom updated.
11682+
RCU does not provide mutual exclusion,
11683+
but instead allows the user to schedule specified actions
11684+
such as deletion at some later time.
11685+
11686+
\pnum
11687+
A class type \tcode{T} is \defn{rcu-protectable}
11688+
if it has exactly one base class of type \tcode{rcu_obj_base<T, D>}
11689+
for some \tcode{D}, and that base is public and non-virtual, and
11690+
it has no base classes of type \tcode{rcu_obj_base<X, Y>}
11691+
for any other combination \tcode{X}, \tcode{Y}.
11692+
An object is rcu-protectable if it is of rcu-protectable type.
11693+
11694+
\pnum
11695+
An invocation of \tcode{unlock} $U$ on an \tcode{rcu_domain dom}
11696+
corresponds to an invocation of \tcode{lock} $L$ on \tcode{dom}
11697+
if $L$ is sequenced before $U$ and either
11698+
\begin{itemize}
11699+
\item
11700+
no other invocation of \tcode{lock} on \tcode{dom}
11701+
is sequenced after $L$ and before $U$, or
11702+
\item
11703+
every invocation of \tcode{unlock} $U2$ on \tcode{dom}
11704+
such that $L$ is sequenced before $U2$ and $U2$ is sequenced before $U$
11705+
corresponds to an invocation of \tcode{lock} $L2$ on \tcode{dom}
11706+
such that $L$ is sequenced before $L2$ and $L2$ is sequenced before $U2$.
11707+
\end{itemize}
11708+
\begin{note}
11709+
This pairs nested locks and unlocks on a given domain in each thread.
11710+
\end{note}
11711+
11712+
\pnum
11713+
A \defn{region of RCU protection} on a domain \tcode{dom}
11714+
starts with a \tcode{lock} $L$ on \tcode{dom} and
11715+
ends with its corresponding \tcode{unlock} $U$.
11716+
11717+
\pnum
11718+
Given a region of RCU protection $R$ on a domain \tcode{dom} and
11719+
given an evaluation $E$ that scheduled another evaluation $F$ in \tcode{dom},
11720+
if $E$ does not strongly happen before the start of $R$,
11721+
the end of $R$ strongly happens before evaluating $F$.
11722+
11723+
\pnum
11724+
The evaluation of a scheduled evaluation is potentially concurrent with
11725+
any other scheduled evaluation.
11726+
Each scheduled evaluation is evaluated at most once.
11727+
11728+
\rSec3[rcu.syn]{Header \tcode{<rcu>} synopsis}
11729+
11730+
\indexheader{rcu}
11731+
\begin{codeblock}
11732+
namespace std {
11733+
// \ref{saferecl.rcu.base}, class template \tcode{rcu_obj_base}
11734+
template<class T, class D = default_delete<T>> class rcu_obj_base;
11735+
11736+
// \ref{saferecl.rcu.domain}, class \tcode{rcu_domain}
11737+
class rcu_domain;
11738+
11739+
// \ref{saferecl.rcu.domain.func} non-member functions
11740+
rcu_domain& rcu_default_domain() noexcept;
11741+
void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
11742+
void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
11743+
template<class T, class D = default_delete<T>>
11744+
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
11745+
}
11746+
\end{codeblock}
11747+
11748+
\rSec3[saferecl.rcu.base]{Class template \tcode{rcu_obj_base}}
11749+
11750+
\pnum
11751+
Objects of type \tcode{T} to be protected by RCU inherit from
11752+
a specialization \tcode{rcu_obj_base<T, D>} for some \tcode{D}.
11753+
11754+
\begin{codeblock}
11755+
namespace std {
11756+
template<class T, class D = default_delete<T>>
11757+
class rcu_obj_base {
11758+
public:
11759+
void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
11760+
protected:
11761+
rcu_obj_base() = default;
11762+
rcu_obj_base(const rcu_obj_base&) = default;
11763+
rcu_obj_base(rcu_obj_base&&) = default;
11764+
rcu_obj_base& operator=(const rcu_obj_base&) = default;
11765+
rcu_obj_base& operator=(rcu_obj_base&&) = default;
11766+
~rcu_obj_base() = default;
11767+
private:
11768+
D @\exposid{deleter}@; // \expos
11769+
};
11770+
}
11771+
\end{codeblock}
11772+
11773+
\pnum
11774+
The behavior of a program that adds specializations for \tcode{rcu_obj_base}
11775+
is undefined.
11776+
11777+
\pnum
11778+
\tcode{T} may be an incomplete type.
11779+
It shall be complete before any member of the resulting specialization of
11780+
\tcode{rcu_obj_base} is referenced.
11781+
11782+
\pnum
11783+
\tcode{D} shall be a
11784+
function object type\iref{function.objects} for which,
11785+
given a value \tcode{d} of type \tcode{D} and
11786+
a value \tcode{ptr} of type \tcode{T*},
11787+
the expression \tcode{d(ptr)} is valid.
11788+
11789+
\pnum
11790+
\tcode{D} shall meet the requirements for
11791+
\oldconcept{DefaultConstructible} and \oldconcept{MoveAssignable}.
11792+
11793+
\pnum
11794+
If \tcode{D} is trivially copyable,
11795+
all specializations of \tcode{rcu_obj_base<T, D>} are trivially copyable.
11796+
11797+
\begin{itemdecl}
11798+
void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
11799+
\end{itemdecl}
11800+
11801+
\begin{itemdescr}
11802+
\pnum
11803+
\mandates
11804+
\tcode{T} is an rcu-protectable type.
11805+
11806+
\pnum
11807+
\expects
11808+
\tcode{*this} is
11809+
a base class subobject of an object \tcode{x} of type \tcode{T}.
11810+
The member function \tcode{rcu_obj_base<T, D>::retire}
11811+
was not invoked on \tcode{x} before.
11812+
The assignment to \exposid{deleter} does not exit via an exception.
11813+
11814+
\pnum
11815+
\effects
11816+
Evaluates \tcode{\exposid{deleter} = std::move(d)} and
11817+
schedules the evaluation of
11818+
the expression \tcode{\exposid{deleter}(\newline addressof(x))}
11819+
in the domain \tcode{dom};
11820+
the behavior is undefined if that evaluation exits via an exception.
11821+
May invoke scheduled evaluations in \tcode{dom}.
11822+
11823+
\begin{note}
11824+
If such evaluations acquire resources held across any invocation of
11825+
\tcode{retire} on \tcode{dom}, deadlock can occur.
11826+
\end{note}
11827+
\end{itemdescr}
11828+
11829+
\rSec3[saferecl.rcu.domain]{Class \tcode{rcu_domain}}
11830+
11831+
\rSec4[saferecl.rcu.domain.general]{General}
11832+
11833+
\begin{codeblock}
11834+
namespace std {
11835+
class rcu_domain {
11836+
public:
11837+
rcu_domain(const rcu_domain&) = delete;
11838+
rcu_domain& operator=(const rcu_domain&) = delete;
11839+
11840+
void lock() noexcept;
11841+
bool try_lock() noexcept;
11842+
void unlock() noexcept;
11843+
};
11844+
}
11845+
\end{codeblock}
11846+
11847+
\pnum
11848+
This class meets the requirements of
11849+
\oldconcept{Lockable}\iref{thread.req.lockable.req} and
11850+
provides regions of RCU protection.
11851+
\begin{example}
11852+
\begin{codeblock}
11853+
std::scoped_lock<rcu_domain> rlock(rcu_default_domain());
11854+
\end{codeblock}
11855+
\end{example}
11856+
11857+
\pnum
11858+
The functions \tcode{lock} and \tcode{unlock} establish
11859+
(possibly nested) regions of RCU protection.
11860+
11861+
\rSec4[saferecl.rcu.domain.members]{Member functions}
11862+
11863+
\indexlibrarymember{lock}{rcu_domain}%
11864+
\begin{itemdecl}
11865+
void lock() noexcept;
11866+
\end{itemdecl}
11867+
11868+
\begin{itemdescr}
11869+
\pnum
11870+
\effects
11871+
Opens a region of RCU protection.
11872+
11873+
\pnum
11874+
\remarks
11875+
Calls to \tcode{lock}
11876+
do not introduce a data race\iref{intro.races} involving \tcode{*this}.
11877+
\end{itemdescr}
11878+
11879+
\indexlibrarymember{try_lock}{rcu_domain}%
11880+
\begin{itemdecl}
11881+
bool try_lock() noexcept;
11882+
\end{itemdecl}
11883+
11884+
\begin{itemdescr}
11885+
\pnum
11886+
\effects
11887+
Equivalent to \tcode{lock()}.
11888+
11889+
\pnum
11890+
\returns
11891+
\tcode{true}.
11892+
\end{itemdescr}
11893+
11894+
\indexlibrarymember{unlock}{rcu_domain}%
11895+
\begin{itemdecl}
11896+
void unlock() noexcept;
11897+
\end{itemdecl}
11898+
11899+
\begin{itemdescr}
11900+
\pnum
11901+
\expects
11902+
A call to \tcode{lock}
11903+
that opened an unclosed region of RCU protection
11904+
is sequenced before the call to \tcode{unlock}.
11905+
11906+
\pnum
11907+
\effects
11908+
Closes the unclosed region of RCU protection
11909+
that was most recently opened.
11910+
May invoke scheduled evaluations in \tcode{*this}.
11911+
11912+
\pnum
11913+
\begin{note}
11914+
If such evaluations acquire resources
11915+
held across any invocation of \tcode{unlock} on \tcode{*this},
11916+
deadlock can occur.
11917+
\end{note}
11918+
11919+
\pnum
11920+
\remarks
11921+
Calls to \tcode{unlock} do not introduce a data race involving \tcode{*this}.
11922+
\begin{note}
11923+
Evaluation of scheduled evaluations can still cause a data race.
11924+
\end{note}
11925+
\end{itemdescr}
11926+
11927+
\rSec4[saferecl.rcu.domain.func]{Non-member functions}
11928+
11929+
\indexlibraryglobal{rcu_default_domain}%
11930+
\begin{itemdecl}
11931+
rcu_domain& rcu_default_domain() noexcept;
11932+
\end{itemdecl}
11933+
11934+
\begin{itemdescr}
11935+
\pnum
11936+
\returns
11937+
A reference to a static-duration object of type \tcode{rcu_domain}.
11938+
A reference to the same object is returned every time this function is called.
11939+
\end{itemdescr}
11940+
11941+
\indexlibraryglobal{rcu_synchronize}%
11942+
\begin{itemdecl}
11943+
void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
11944+
\end{itemdecl}
11945+
11946+
\begin{itemdescr}
11947+
\pnum
11948+
\effects
11949+
If the call to \tcode{rcu_synchronize} does not strongly happen before
11950+
the lock opening an RCU protection region \tcode{R} on \tcode{dom},
11951+
blocks until the \tcode{unlock} closing \tcode{R} happens.
11952+
11953+
\pnum
11954+
\sync
11955+
The \tcode{unlock} closing \tcode{R}
11956+
strongly happens before the return from \tcode{rcu_synchronize}.
11957+
\end{itemdescr}
11958+
11959+
\indexlibraryglobal{rcu_barrier}%
11960+
\begin{itemdecl}
11961+
void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
11962+
\end{itemdecl}
11963+
11964+
\begin{itemdescr}
11965+
\pnum
11966+
\effects
11967+
May evaluate any scheduled evaluations in \tcode{dom}.
11968+
For any evaluation that happens before the call to \tcode{rcu_barrier} and
11969+
that schedules an evaluation $E$ in \tcode{dom},
11970+
blocks until $E$ has been evaluated.
11971+
11972+
\pnum
11973+
\sync
11974+
The evaluation of any such $E$
11975+
strongly happens before the return from \tcode{rcu_barrier}.
11976+
11977+
\begin{note}
11978+
A call to \tcode{rcu_barrier} does not imply
11979+
a call to \tcode{rcu_synchronize} and vice versa.
11980+
\end{note}
11981+
\end{itemdescr}
11982+
11983+
\indexlibraryglobal{rcu_retire}%
11984+
\begin{itemdecl}
11985+
template<class T, class D = default_delete<T>>
11986+
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
11987+
\end{itemdecl}
11988+
11989+
\begin{itemdescr}
11990+
\pnum
11991+
\mandates
11992+
\tcode{is_move_constructible_v<D>} is \tcode{true} and
11993+
the expression \tcode{d(p)} is well-formed.
11994+
11995+
\pnum
11996+
\expects
11997+
\tcode{D} meets the \oldconcept{MoveConstructible} and
11998+
\oldconcept{Destructible} requirements.
11999+
12000+
\pnum
12001+
\effects
12002+
May allocate memory.
12003+
It is unspecified whether the memory allocation
12004+
is performed by invoking \tcode{\keyword{operator} \keyword{new}}.
12005+
Initializes an object \tcode{d1} of type \tcode{D} from \tcode{std::move(d)}.
12006+
Schedules the evaluation of \tcode{d1(p)} in the domain \tcode{dom};
12007+
the behavior is undefined if that evaluation exits via an exception.
12008+
May invoke scheduled evaluations in \tcode{dom}.
12009+
\begin{note}
12010+
If \tcode{rcu_retire} exits via an exception, no evaluation
12011+
is scheduled.
12012+
\end{note}
12013+
12014+
\pnum
12015+
\throws
12016+
\tcode{bad_alloc} or any exception thrown by the initialization of \tcode{d1}.
12017+
12018+
\pnum
12019+
\begin{note}
12020+
If scheduled evaluations acquire resources
12021+
held across any invocation of \tcode{rcu_retire} on \tcode{dom},
12022+
deadlock can occur.
12023+
\end{note}
12024+
\end{itemdescr}

0 commit comments

Comments
 (0)