Skip to content

Commit 1d11177

Browse files
jensmaurertkoeppe
authored andcommitted
P2545R4 Read-Copy Update (RCU)
1 parent 48b0a3b commit 1d11177

File tree

3 files changed

+360
-1
lines changed

3 files changed

+360
-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: 358 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,359 @@
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+
rcu_domain& rcu_default_domain() noexcept;
11739+
void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
11740+
void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
11741+
template<class T, class D = default_delete<T>>
11742+
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
11743+
}
11744+
\end{codeblock}
11745+
11746+
\rSec3[saferecl.rcu.base]{Class template \tcode{rcu_obj_base}}
11747+
11748+
\pnum
11749+
Objects of type \tcode{T} to be protected by RCU inherit from
11750+
a specialization of \tcode{rcu_obj_base<T,D>}.
11751+
11752+
\begin{codeblock}
11753+
namespace std {
11754+
template<class T, class D = default_delete<T>>
11755+
class rcu_obj_base {
11756+
public:
11757+
void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
11758+
protected:
11759+
rcu_obj_base() = default;
11760+
rcu_obj_base(const rcu_obj_base&) = default;
11761+
rcu_obj_base(rcu_obj_base&&) = default;
11762+
rcu_obj_base& operator=(const rcu_obj_base&) = default;
11763+
rcu_obj_base& operator=(rcu_obj_base&&) = default;
11764+
~rcu_obj_base() = default;
11765+
private:
11766+
D @\exposid{deleter}@; // \expos
11767+
};
11768+
}
11769+
\end{codeblock}
11770+
11771+
\pnum
11772+
The behavior of a program that adds specializations for \tcode{rcu_obj_base}
11773+
is undefined.
11774+
11775+
\pnum
11776+
\tcode{T} may be an incomplete type.
11777+
It shall be complete before any member of the resulting specialization of
11778+
\tcode{rcu_obj_base} is referenced.
11779+
11780+
\pnum
11781+
\tcode{D} shall be a
11782+
function object type\iref{function.objects} for which,
11783+
given a value \tcode{d} of type \tcode{D} and
11784+
a value \tcode{ptr} of type \tcode{T*},
11785+
the expression \tcode{d(ptr)} is valid.
11786+
11787+
\pnum
11788+
\tcode{D} shall meet the requirements for
11789+
\oldconcept{DefaultConstructible} and \oldconcept{MoveAssignable}.
11790+
11791+
\pnum
11792+
If \tcode{D} is trivially copyable,
11793+
all specializations of \tcode{rcu_obj_base<T,D>} are trivially copyable.
11794+
11795+
\begin{itemdecl}
11796+
void retire(D d = D(), rcu_domain& dom = rcu_default_domain()) noexcept;
11797+
\end{itemdecl}
11798+
11799+
\begin{itemdescr}
11800+
\pnum
11801+
\mandates
11802+
\tcode{T} is an rcu-protectable type.
11803+
11804+
\pnum
11805+
\expects
11806+
\tcode{*this} is
11807+
a base class subobject of an object \tcode{x} of type \tcode{T}.
11808+
The member function \tcode{rcu_obj_base<T, D>::retire}
11809+
was not invoked on \tcode{x} before.
11810+
The assignment to \exposid{deleter} does not exit via an exception.
11811+
11812+
\pnum
11813+
\effects
11814+
Evaluates \tcode{\exposid{deleter} = std::move(d)} and
11815+
schedules the evaluation of
11816+
the expression \tcode{\exposid{deleter}(\newline addressof(x))}
11817+
in the domain \tcode{dom};
11818+
the behavior is undefined if that evaluation exits via an exception.
11819+
May invoke scheduled evaluations in \tcode{dom}.
11820+
11821+
\begin{note}
11822+
If such evaluations acquire resources held across any invocation of
11823+
\tcode{retire} on \tcode{dom}, deadlock can occur.
11824+
\end{note}
11825+
\end{itemdescr}
11826+
11827+
\rSec3[saferecl.rcu.domain]{Class \tcode{rcu_domain}}
11828+
11829+
\rSec4[saferecl.rcu.domain.general]{General}
11830+
11831+
\pnum
11832+
This class meets the requirements of
11833+
\oldconcept{Lockable}\iref{thread.req.lockable.req} and
11834+
provides regions of RCU protection.
11835+
11836+
\begin{example}
11837+
\begin{codeblock}
11838+
std::scoped_lock<rcu_domain> rlock(rcu_default_domain());
11839+
\end{codeblock}
11840+
\end{example}
11841+
11842+
\begin{codeblock}
11843+
class rcu_domain {
11844+
public:
11845+
rcu_domain(const rcu_domain&) = delete;
11846+
rcu_domain& operator=(const rcu_domain&) = delete;
11847+
11848+
void lock() noexcept;
11849+
bool try_lock() noexcept;
11850+
void unlock() noexcept;
11851+
};
11852+
11853+
rcu_domain& rcu_default_domain() noexcept;
11854+
\end{codeblock}
11855+
11856+
\pnum
11857+
The functions \tcode{lock} and \tcode{unlock} establish
11858+
(possibly nested) regions of RCU protection.
11859+
11860+
\rSec4[saferecl.rcu.domain.members]{Member functions}
11861+
11862+
\indexlibrarymember{lock}{rcu_domain}%
11863+
\begin{itemdecl}
11864+
void lock() noexcept;
11865+
\end{itemdecl}
11866+
11867+
\begin{itemdescr}
11868+
\pnum
11869+
\effects
11870+
Opens a region of RCU protection.
11871+
11872+
\pnum
11873+
\remarks
11874+
Calls to \tcode{lock}
11875+
do not introduce a data race\iref{intro.races} involving \tcode{*this}.
11876+
\end{itemdescr}
11877+
11878+
\indexlibrarymember{try_lock}{rcu_domain}%
11879+
\begin{itemdecl}
11880+
bool try_lock() noexcept;
11881+
\end{itemdecl}
11882+
11883+
\begin{itemdescr}
11884+
\pnum
11885+
\effects
11886+
Equivalent to \tcode{lock()}.
11887+
11888+
\pnum
11889+
\returns
11890+
\tcode{true}.
11891+
\end{itemdescr}
11892+
11893+
\indexlibrarymember{unlock}{rcu_domain}%
11894+
\begin{itemdecl}
11895+
void unlock() noexcept;
11896+
\end{itemdecl}
11897+
11898+
\begin{itemdescr}
11899+
\pnum
11900+
\expects
11901+
A call to \tcode{lock}
11902+
that opened an unclosed region of RCU protection
11903+
is sequenced before the call to \tcode{unlock}.
11904+
11905+
\pnum
11906+
\effects
11907+
Closes the unclosed region of RCU protection
11908+
that was most recently opened.
11909+
May invoke scheduled evaluations in \tcode{*this}.
11910+
11911+
\pnum
11912+
\begin{note}
11913+
If such evaluations acquire resources
11914+
held across any invocation of \tcode{unlock} on \tcode{*this},
11915+
deadlock can occur.
11916+
\end{note}
11917+
Calls to \tcode{unlock} do not introduce a data race involving \tcode{*this}.
11918+
\begin{note}
11919+
Evaluation of scheduled evaluations can still cause a data race.
11920+
\end{note}
11921+
\end{itemdescr}
11922+
11923+
\rSec4[saferecl.rcu.domain.func]{Non-member functions}
11924+
11925+
\indexlibraryglobal{rcu_default_domain}%
11926+
\begin{itemdecl}
11927+
rcu_domain& rcu_default_domain() noexcept;
11928+
\end{itemdecl}
11929+
11930+
\begin{itemdescr}
11931+
\pnum
11932+
\returns
11933+
A reference to a static-duration object of type \tcode{rcu_domain}.
11934+
A reference to the same object is returned every time this function is called.
11935+
\end{itemdescr}
11936+
11937+
\indexlibraryglobal{rcu_synchronize}%
11938+
\begin{itemdecl}
11939+
void rcu_synchronize(rcu_domain& dom = rcu_default_domain()) noexcept;
11940+
\end{itemdecl}
11941+
11942+
\begin{itemdescr}
11943+
\pnum
11944+
\effects
11945+
If the call to \tcode{rcu_synchronize} does not strongly happen before
11946+
the lock opening an RCU protection region \tcode{R} on \tcode{dom},
11947+
blocks until the \tcode{unlock} closing \tcode{R} happens.
11948+
11949+
\pnum
11950+
\sync
11951+
The \tcode{unlock} closing \tcode{R}
11952+
strongly happens before the return from \tcode{rcu_synchronize}.
11953+
\end{itemdescr}
11954+
11955+
\indexlibraryglobal{rcu_barrier}%
11956+
\begin{itemdecl}
11957+
void rcu_barrier(rcu_domain& dom = rcu_default_domain()) noexcept;
11958+
\end{itemdecl}
11959+
11960+
\begin{itemdescr}
11961+
\pnum
11962+
\effects
11963+
May evaluate any scheduled evaluations in \tcode{dom}.
11964+
For any evaluation that happens before the call to \tcode{rcu_barrier} and
11965+
that schedules an evaluation $E$ in \tcode{dom},
11966+
blocks until $E$ has been evaluated.
11967+
11968+
\pnum
11969+
\sync
11970+
The evaluation of any such $E$
11971+
strongly happens before the return from \tcode{rcu_barrier}.
11972+
11973+
\begin{note}
11974+
A call to \tcode{rcu_barrier} does not imply
11975+
a call to \tcode{rcu_synchronize} and vice versa.
11976+
\end{note}
11977+
\end{itemdescr}
11978+
11979+
\indexlibraryglobal{rcu_retire}%
11980+
\begin{itemdecl}
11981+
template<class T, class D = default_delete<T>>
11982+
void rcu_retire(T* p, D d = D(), rcu_domain& dom = rcu_default_domain());
11983+
\end{itemdecl}
11984+
11985+
\begin{itemdescr}
11986+
\pnum
11987+
\mandates
11988+
\tcode{is_move_constructible_v<D>} is \tcode{true} and
11989+
the expression \tcode{d(p)} is well-formed.
11990+
11991+
\pnum
11992+
\expects
11993+
\tcode{D} meets the \oldconcept{MoveConstructible} and
11994+
\oldconcept{Destructible} requirements.
11995+
11996+
\pnum
11997+
\effects
11998+
May allocate memory.
11999+
It is unspecified whether the memory allocation
12000+
is performed by invoking \tcode{\keyword{operator} \keyword{new}}.
12001+
Initializes an object \tcode{d1} of type \tcode{D} from \tcode{std::move(d)}.
12002+
Schedules the evaluation of \tcode{d1(p)} in the domain \tcode{dom};
12003+
the behavior is undefined if that evaluation exits via an exception.
12004+
May invoke scheduled evaluations in \tcode{dom}.
12005+
\begin{note}
12006+
If \tcode{rcu_retire} exits via an exception, no evaluation
12007+
is scheduled.
12008+
\end{note}
12009+
12010+
\pnum
12011+
\throws
12012+
\tcode{bad_alloc} or any exception thrown by the initialization of \tcode{d1}.
12013+
12014+
\pnum
12015+
\begin{note}
12016+
If scheduled evaluations acquire resources
12017+
held across any invocation of \tcode{rcu_retire} on \tcode{dom},
12018+
deadlock can occur.
12019+
\end{note}
12020+
\end{itemdescr}

0 commit comments

Comments
 (0)