1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
// Copyright (c) Mike Grier
//! Registering a [`Responses`] for one ring (M35.1, [D-85](../../DESIGN-NOTES.md#d-85)).
//!
//! # One ring, any thread
//!
//! A responder registered here answers the seam calls of the one ring it was
//! registered for, on whatever thread makes them. That is what a ring used
//! from more than one thread needs -- a pool thread draining it, a consumer
//! submitting to it -- and what the thread-local form it replaced (`M35.2`)
//! could not give: there, a call from a thread with nothing installed reached
//! the kernel silently, so an injected failure could be undone by a real call
//! on another thread and a test pass for the wrong reason.
//!
//! Tests still cannot answer each other's calls, which is what made the
//! thread-local form thread-local: two tests do not share a ring. The key is
//! the ring's `RingId`, which is process-unique and never reused, where a raw
//! handle value can be reused once `CloseIoRing` has run.
//!
//! # How long a registration lasts
//!
//! **Until its ring drops**, after the ring's rundown and before
//! `CloseIoRing` -- so a responder holding operations the kernel never saw
//! still answers the rundown that pops them -- or until
//! [`Registration::end`] ends it earlier. **Dropping the [`Registration`]
//! ends nothing.** That is deliberate: locals drop in reverse declaration
//! order, so a registration ended by its handle's drop would, in the ordinary
//! `let ring = ..; let registration = register(&ring, ..);` shape, end before
//! the ring's rundown ran -- the very ordering hazard this form exists to
//! remove.
//!
//! # Re-entrancy and concurrency
//!
//! - A responder is not consulted re-entrantly for its own ring. A call it
//! makes into the seam for that ring finds it already answering on this
//! thread and falls through to the kernel.
//! - Calls on one ring from two threads are serialized on the responder's
//! lock. A ring is not `Sync`, so they do not overlap in practice; a call
//! that did would wait rather than fall through to the kernel, which would
//! be wrong silently.
use RefCell;
use ;
use Responses;
use crateIoRing;
use crateRingId;
/// A registered responder, behind its own lock so one ring's call never waits
/// on another ring's. `None` once the registration has ended, for a call that
/// cloned it just before.
type Slot = ;
/// Every live registration. A `Vec` rather than a map: it holds a handful of
/// entries at most, and `Mutex::new(Vec::new())` is `const`.
static REGISTRY: = new;
thread_local!
/// Lock `mutex`. A responder that panicked while answering leaves its own
/// state as the panic found it; the registry itself is only ever pushed to and
/// removed from, so neither is left inconsistent.
/// Marks `ring` as being answered on this thread until dropped.
;
/// Run `f` against `ring`'s responder, if it has one and this thread is not
/// already answering for it. `None` is the seam's signal to make the real
/// call.
pub
/// Register `responder` for the ring identified by `ring`.
///
/// # Panics
///
/// If that ring already has one: which of two answered a call would depend on
/// registration order.
pub
/// End `ring`'s registration, if it has one, handing its responder back.
///
/// The responder is taken under its own lock, so a call answering for the ring
/// on another thread finishes first, and a call that had already found the
/// slot finds it empty and falls through.
/// `ring` is dropping, and its rundown has run: end its registration, if it
/// has one. Called by `IoRing`'s `Drop` before `CloseIoRing`.
pub
/// Register `responder` to answer `ring`'s seam calls, on whatever thread
/// makes them, until the ring drops or [`Registration::end`] is called.
///
/// See the module documentation for why dropping the returned
/// [`Registration`] does **not** end it.
///
/// # Panics
///
/// If `ring` already has a responder registered.
/// A responder's registration for one ring (D-85).
///
/// Ends when its ring drops, or at [`Registration::end`]. Dropping this value
/// ends nothing; see the module documentation for why.