tokio/runtime/io/
registration_set.rs1use crate::loom::sync::atomic::AtomicUsize;
2use crate::runtime::io::ScheduledIo;
3use crate::util::linked_list::{self, LinkedList};
4
5use crate::loom::sync::Arc;
6use std::io;
7use std::ptr::NonNull;
8use std::sync::atomic::Ordering::{Acquire, Release};
9
10const NOTIFY_AFTER: usize = 16;
12
13pub(super) struct RegistrationSet {
14 num_pending_release: AtomicUsize,
15}
16
17pub(super) struct Synced {
18 is_shutdown: bool,
21
22 registrations: LinkedList<Arc<ScheduledIo>>,
24
25 pending_release: Vec<Arc<ScheduledIo>>,
30}
31
32impl RegistrationSet {
33 pub(super) fn new() -> (RegistrationSet, Synced) {
34 let set = RegistrationSet {
35 num_pending_release: AtomicUsize::new(0),
36 };
37
38 let synced = Synced {
39 is_shutdown: false,
40 registrations: LinkedList::new(),
41 pending_release: Vec::with_capacity(NOTIFY_AFTER),
42 };
43
44 (set, synced)
45 }
46
47 pub(super) fn is_shutdown(&self, synced: &Synced) -> bool {
48 synced.is_shutdown
49 }
50
51 pub(super) fn needs_release(&self) -> bool {
53 self.num_pending_release.load(Acquire) != 0
54 }
55
56 pub(super) fn allocate(&self, synced: &mut Synced) -> io::Result<Arc<ScheduledIo>> {
57 if synced.is_shutdown {
58 return Err(io::Error::other(
59 crate::util::error::RUNTIME_SHUTTING_DOWN_ERROR,
60 ));
61 }
62
63 let ret = Arc::new(ScheduledIo::default());
64
65 synced.registrations.push_front(ret.clone());
67
68 Ok(ret)
69 }
70
71 pub(super) fn deregister(&self, synced: &mut Synced, registration: &Arc<ScheduledIo>) -> bool {
74 synced.pending_release.push(registration.clone());
75
76 let len = synced.pending_release.len();
77 self.num_pending_release.store(len, Release);
78
79 len == NOTIFY_AFTER
80 }
81
82 pub(super) fn shutdown(&self, synced: &mut Synced) -> Vec<Arc<ScheduledIo>> {
83 if synced.is_shutdown {
84 return vec![];
85 }
86
87 synced.is_shutdown = true;
88 synced.pending_release.clear();
89
90 let mut ret = vec![];
95
96 while let Some(io) = synced.registrations.pop_back() {
97 ret.push(io);
98 }
99
100 ret
101 }
102
103 pub(super) fn release(&self, synced: &mut Synced) {
104 let pending = std::mem::take(&mut synced.pending_release);
105
106 for io in pending {
107 unsafe { self.remove(synced, &io) }
109 }
110
111 self.num_pending_release.store(0, Release);
112 }
113
114 pub(super) unsafe fn remove(&self, synced: &mut Synced, io: &Arc<ScheduledIo>) {
117 let io = unsafe { NonNull::new_unchecked(Arc::as_ptr(io).cast_mut()) };
119
120 super::EXPOSE_IO.unexpose_provenance(io.as_ptr());
121 let _ = unsafe { synced.registrations.remove(io) };
123 }
124}
125
126unsafe impl linked_list::Link for Arc<ScheduledIo> {
128 type Handle = Arc<ScheduledIo>;
129 type Target = ScheduledIo;
130
131 fn as_raw(handle: &Self::Handle) -> NonNull<ScheduledIo> {
132 unsafe { NonNull::new_unchecked(Arc::as_ptr(handle) as *mut _) }
134 }
135
136 unsafe fn from_raw(ptr: NonNull<Self::Target>) -> Arc<ScheduledIo> {
137 unsafe { Arc::from_raw(ptr.as_ptr() as *const _) }
139 }
140
141 unsafe fn pointers(
142 target: NonNull<Self::Target>,
143 ) -> NonNull<linked_list::Pointers<ScheduledIo>> {
144 unsafe { NonNull::new_unchecked(target.as_ref().linked_list_pointers.get()) }
147 }
148}
149
150#[cfg(all(test, loom))]
151mod loom_tests {
152 use super::*;
153 use crate::io::ready::Ready;
154 use crate::loom::sync::Mutex;
155 use crate::loom::thread;
156
157 struct Registrations {
160 set: RegistrationSet,
161 synced: Mutex<Synced>,
162 }
163
164 impl Registrations {
165 fn new() -> Self {
166 let (set, synced) = RegistrationSet::new();
167 Self {
168 set,
169 synced: Mutex::new(synced),
170 }
171 }
172
173 fn allocate(&self) -> Arc<ScheduledIo> {
174 self.set.allocate(&mut self.synced.lock()).unwrap()
175 }
176
177 fn deregister(&self, io: &Arc<ScheduledIo>) {
178 self.set.deregister(&mut self.synced.lock(), io);
179 }
180
181 fn release(&self) {
182 if self.set.needs_release() {
183 self.set.release(&mut self.synced.lock());
184 }
185 }
186 }
187
188 #[test]
191 fn deregister_races_with_prior_event_delivery() {
192 loom::model(|| {
193 let handle = Arc::new(Registrations::new());
194 let scheduled_io = handle.allocate();
195 let token = scheduled_io.token();
196
197 let handle_clone = handle.clone();
198 let driver_th = thread::spawn(move || {
199 unsafe {
206 super::super::driver::dispatch_event(token, Ready::READABLE);
207 }
208 handle_clone.release();
210 });
211
212 handle.deregister(&scheduled_io);
214 drop(scheduled_io);
215
216 driver_th.join().unwrap();
217
218 handle.release();
220
221 assert!(!handle.set.needs_release());
222 });
223 }
224}