Skip to content

Commit d6ca3eb

Browse files
committed
New issue from Eric Niebler: "run_loop should not have a set_error completion"
1 parent 575029f commit d6ca3eb

File tree

1 file changed

+176
-0
lines changed

1 file changed

+176
-0
lines changed

xml/issue4476.xml

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
<?xml version='1.0' encoding='utf-8' standalone='no'?>
2+
<!DOCTYPE issue SYSTEM "lwg-issue.dtd">
3+
4+
<issue num="4476" status="New">
5+
<title>`run_loop` should not have a `set_error` completion</title>
6+
<section><sref ref="[exec.run.loop.general]"/></section>
7+
<submitter>Eric Niebler</submitter>
8+
<date>16 Nov 2025</date>
9+
<priority>99</priority>
10+
11+
<discussion>
12+
<p>
13+
When `run_loop` was proposed, the only implementation we had synchronized with a mutex and a condition variable.
14+
Operations on those can theoretically throw exceptions, so `run_loop` got a `set_error_t(exception_ptr)`
15+
completion signature.
16+
<p/>
17+
Since then, <a href="https://github.com/NVIDIA/cccl/blob/main/cudax/include/cuda/experimental/__execution/run_loop.cuh">a
18+
lock-free implementation of `run_loop` has been found</a>. Atomic operations cannot fail with an exception,
19+
so an atomic `run_loop` can never complete with an error.
20+
</p>
21+
</discussion>
22+
23+
<resolution>
24+
<p>
25+
This wording is relative to <paper num="N5014"/>.
26+
</p>
27+
28+
<ol>
29+
<li><p>Modify <sref ref="[exec.run.loop.general]"/>, class `run_loop` synopsis, as indicated:</p>
30+
31+
<blockquote>
32+
<pre>
33+
namespace std::execution {
34+
class run_loop {
35+
<i>// <sref ref="[exec.run.loop.types]"/>, associated types</i>
36+
class <i>run-loop-scheduler</i>; <i>// exposition only</i>
37+
class <i>run-loop-sender</i>; <i>// exposition only</i>
38+
struct <i>run-loop-opstate-base</i> { <i>// exposition only</i>
39+
virtual void <i>execute</i>() <ins>noexcept</ins> = 0; <i>// exposition only</i>
40+
run_loop* <i>loop</i>; <i>// exposition only</i>
41+
<i>run-loop-opstate-base</i>* <i>next</i>; <i>// exposition only</i>
42+
};
43+
template&lt;class Rcvr&gt;
44+
using <i>run-loop-opstate</i> = <i>unspecified</i>; <i>// exposition only</i>
45+
46+
<i>// <sref ref="[exec.run.loop.members]"/>, member functions</i>
47+
<i>run-loop-opstate-base</i>* <i>pop-front</i>() <ins>noexcept</ins>; <i>// exposition only</i>
48+
void <i>push-back</i>(<i>run-loop-opstate-base</i>*) <ins>noexcept</ins>; <i>// exposition only</i>
49+
50+
public:
51+
<i>// <sref ref="[exec.run.loop.ctor]"/>, constructor and destructor</i>
52+
run_loop() noexcept;
53+
run_loop(run_loop&amp;&amp;) = delete;
54+
~run_loop();
55+
56+
<i>// <sref ref="[exec.run.loop.members]"/> member functions</i>
57+
<i>run-loop-scheduler</i> get_scheduler() <ins>noexcept</ins>;
58+
void run() <ins>noexcept</ins>;
59+
void finish() <ins>noexcept</ins>;
60+
};
61+
}
62+
</pre>
63+
</blockquote>
64+
</li>
65+
66+
<li><p>Modify <sref ref="[exec.run.loop.types]"/> as indicated:</p>
67+
68+
<blockquote>
69+
<pre>
70+
class <i>run-loop-sender</i>;
71+
</pre>
72+
<p>
73+
-5- <tt><i>run-loop-sender</i></tt> is an exposition-only type that satisfies sender.
74+
<tt>completion_signatures_of_t&lt;<i>runloop-sender</i>&gt;</tt> is
75+
</p>
76+
<blockquote><pre>
77+
completion_signatures&lt;set_value_t(), <del>set_error_t(exception_ptr),</del> set_stopped_t()&gt;
78+
</pre></blockquote>
79+
<p>
80+
[&hellip;]
81+
<p/>
82+
-9- Let <tt><i>o</i></tt> be a non-const lvalue of type <tt><i>run-loop-opstate</i>&lt;Rcvr&gt;</tt>,
83+
and let <tt>REC(<i>o</i>)</tt> be a non-const lvalue reference to an instance of type `Rcvr` that
84+
was initialized with the expression <tt><i>rcvr</i></tt> passed to the invocation of connect that
85+
returned <tt><i>o</i></tt>. Then:
86+
</p>
87+
<ul style="list-style-type: none">
88+
<li>(9.1) &mdash; [&hellip;]
89+
</li>
90+
<li>(9.2) &mdash; [&hellip;]
91+
</li>
92+
<li>(9.3) &mdash;
93+
The expression <tt>start(<i>o</i>)</tt> is equivalent to:
94+
<blockquote><pre>
95+
<del>try {</del>
96+
<i>o</i>.<i>loop</i>-&gt;<i>push-back</i>(addressof(<i>o</i>));
97+
<del>} catch(...) {
98+
set_error(std::move(<i>REC</i>(<i>o</i>)), current_exception());
99+
}</del>
100+
</pre></blockquote>
101+
</li>
102+
</ul>
103+
</blockquote>
104+
</li>
105+
106+
107+
<li><p>Modify <sref ref="[exec.run.loop.members]"/> as indicated:</p>
108+
109+
<blockquote>
110+
<pre>
111+
<i>run-loop-opstate-base</i>* <i>pop-front</i>() <ins>noexcept</ins>;
112+
</pre>
113+
<blockquote>
114+
<p>
115+
-1- <i>Effects</i>: Blocks (<sref ref="[defns.block]"/>) until one of the following conditions is `true`: [&hellip;]
116+
</p>
117+
</blockquote>
118+
<pre>
119+
void <i>push-back</i>(<i>run-loop-opstate-base</i>* item) <ins>noexcept</ins>;
120+
</pre>
121+
<blockquote>
122+
<p>
123+
-2- <i>Effects</i>: Adds `item` to the back of the queue and increments <tt><i>count</i></tt> by `1`.
124+
<p/>
125+
-3- <i>Synchronization</i>: This operation synchronizes with the <tt><i>pop-front</i></tt> operation that
126+
obtains `item`.
127+
</p>
128+
</blockquote>
129+
<pre>
130+
<i>run-loop-scheduler</i> get_scheduler() <ins>noexcept</ins>;
131+
</pre>
132+
<blockquote>
133+
<p>
134+
-4- <i>Returns</i>: An instance of <tt><i>run-loop-scheduler</i></tt> that can be used to schedule work onto
135+
this `run_loop` instance.
136+
</p>
137+
</blockquote>
138+
<pre>
139+
void run() <ins>noexcept</ins>;
140+
</pre>
141+
<blockquote>
142+
<p>
143+
-5- <i>Preconditions</i>: is either <tt><i>starting</i></tt> or <tt><i>finishing</i></tt>.
144+
<p/>
145+
-6- <i>Effects</i>: If <tt><i>state</i></tt> is <tt><i>starting</i></tt>, sets the <tt><i>state</i></tt> to
146+
<tt><i>running</i></tt>, otherwise leaves <tt><i>state</i></tt> unchanged. Then, equivalent to:
147+
</p>
148+
<blockquote><pre>
149+
while (auto* op = <i>pop-front</i>()) {
150+
op-&gt;<i>execute</i>();
151+
}
152+
</pre></blockquote>
153+
<p>
154+
-7- <i>Remarks</i>: When <tt><i>state</i></tt> changes, it does so without introducing data races.
155+
</p>
156+
</blockquote>
157+
<pre>
158+
void finish() <ins>noexcept</ins>;
159+
</pre>
160+
<blockquote>
161+
<p>
162+
-8- <i>Preconditions</i>: <tt><i>state</i></tt> is either <tt><i>starting</i></tt> or <tt><i>running</i></tt>.
163+
<p/>
164+
-9- <i>Effects</i>: Changes <tt><i>state</i></tt> to <tt><i>finishing</i></tt>.
165+
<p/>
166+
-10- <i>Synchronization</i>: `finish` synchronizes with the <tt><i>pop-front</i></tt> operation that
167+
returns `nullptr`.
168+
</p>
169+
</blockquote>
170+
</blockquote>
171+
</li>
172+
173+
</ol>
174+
</resolution>
175+
176+
</issue>

0 commit comments

Comments
 (0)