1use std::marker::PhantomData;
10
11use crate::point_to_point::Status;
12use crate::transport;
13use crate::{Count, Rank, Tag};
14
15pub unsafe trait Scope<'a> {}
24
25#[derive(Clone, Copy, Debug)]
27pub struct StaticScope;
28
29unsafe impl Scope<'static> for StaticScope {}
31
32pub struct LocalScope<'a> {
34 _invariant: PhantomData<std::cell::Cell<&'a ()>>,
35}
36
37unsafe impl<'a> Scope<'a> for &LocalScope<'a> {}
40
41pub fn scope<'a, F, R>(f: F) -> R
44where
45 F: FnOnce(&LocalScope<'a>) -> R,
46{
47 let scope = LocalScope {
48 _invariant: PhantomData,
49 };
50 f(&scope)
51}
52
53fn complete_recv(ctx: u32, source: Rank, tag: Tag, ptr: *mut u8, len: usize) -> Status {
57 let (src, t, count, _dt, payload) = transport::runtime().recv(ctx, source, tag);
58 let n = len.min(payload.len());
59 unsafe {
62 std::ptr::copy_nonoverlapping(payload.as_ptr(), ptr, n);
63 }
64 Status::new(src, t, count as Count, payload.len())
65}
66
67enum State {
68 Completed { status: Status },
70 PendingRecv {
72 ctx: u32,
73 source: Rank,
74 tag: Tag,
75 ptr: *mut u8,
76 len: usize,
77 },
78 PendingJoin {
81 handle: Option<std::thread::JoinHandle<()>>,
82 },
83 Consumed,
85}
86
87pub struct Request<'a, D: ?Sized = [u8], S = StaticScope> {
91 state: State,
92 _life: PhantomData<&'a mut ()>,
94 _data: PhantomData<*mut D>,
95 _scope: PhantomData<S>,
96}
97
98impl<'a, D: ?Sized, S: Scope<'a>> Request<'a, D, S> {
99 pub(crate) fn completed(_scope: S) -> Request<'a, D, S> {
101 Request {
102 state: State::Completed {
103 status: Status::new(0, 0, 0, 0),
104 },
105 _life: PhantomData,
106 _data: PhantomData,
107 _scope: PhantomData,
108 }
109 }
110
111 pub(crate) fn pending_recv(
113 _scope: S,
114 ptr: *mut u8,
115 len: usize,
116 ctx: u32,
117 source: Rank,
118 tag: Tag,
119 ) -> Request<'a, D, S> {
120 Request {
121 state: State::PendingRecv {
122 ctx,
123 source,
124 tag,
125 ptr,
126 len,
127 },
128 _life: PhantomData,
129 _data: PhantomData,
130 _scope: PhantomData,
131 }
132 }
133
134 pub(crate) fn from_join(_scope: S, handle: std::thread::JoinHandle<()>) -> Request<'a, D, S> {
137 Request {
138 state: State::PendingJoin {
139 handle: Some(handle),
140 },
141 _life: PhantomData,
142 _data: PhantomData,
143 _scope: PhantomData,
144 }
145 }
146
147 fn ready(&self) -> bool {
149 match &self.state {
150 State::Completed { .. } => true,
151 State::Consumed => true,
152 State::PendingRecv {
153 ctx, source, tag, ..
154 } => transport::runtime().probe(*ctx, *source, *tag).is_some(),
155 State::PendingJoin { handle } => {
156 handle.as_ref().map(|h| h.is_finished()).unwrap_or(true)
157 }
158 }
159 }
160
161 pub fn wait(mut self) -> Status {
163 let state = std::mem::replace(&mut self.state, State::Consumed);
164 match state {
165 State::Completed { status } => status,
166 State::PendingRecv {
167 ctx,
168 source,
169 tag,
170 ptr,
171 len,
172 } => complete_recv(ctx, source, tag, ptr, len),
173 State::PendingJoin { mut handle } => {
174 if let Some(h) = handle.take() {
175 let _ = h.join();
176 }
177 Status::new(0, 0, 0, 0)
178 }
179 State::Consumed => unreachable!("request already consumed"),
180 }
181 }
182
183 pub fn wait_without_status(self) {
185 let _ = self.wait();
186 }
187
188 pub fn test(mut self) -> Result<Status, Request<'a, D, S>> {
191 let is_ready = self.ready();
192 if !is_ready {
193 return Err(self);
194 }
195 let state = std::mem::replace(&mut self.state, State::Consumed);
196 let status = match state {
197 State::Completed { status } => status,
198 State::PendingRecv {
199 ctx,
200 source,
201 tag,
202 ptr,
203 len,
204 } => complete_recv(ctx, source, tag, ptr, len),
205 State::PendingJoin { mut handle } => {
206 if let Some(h) = handle.take() {
207 let _ = h.join();
208 }
209 Status::new(0, 0, 0, 0)
210 }
211 State::Consumed => unreachable!(),
212 };
213 Ok(status)
214 }
215
216 pub fn cancel(mut self) {
219 self.state = State::Consumed;
220 }
221}
222
223impl<D: ?Sized, S> Drop for Request<'_, D, S> {
224 fn drop(&mut self) {
225 match &mut self.state {
226 State::PendingJoin { handle } => {
230 if let Some(h) = handle.take() {
231 let _ = h.join();
232 }
233 }
234 State::Completed { .. } | State::PendingRecv { .. } => {
235 if !std::thread::panicking() {
236 panic!(
237 "an in-flight mpi::request::Request was dropped; complete it with \
238 wait()/test()/cancel() or hold it in a WaitGuard"
239 );
240 }
241 }
242 State::Consumed => {}
243 }
244 }
245}
246
247pub struct WaitGuard<'a, D: ?Sized = [u8], S = StaticScope>(Option<Request<'a, D, S>>);
250
251impl<'a, D: ?Sized, S: Scope<'a>> From<Request<'a, D, S>> for WaitGuard<'a, D, S> {
252 fn from(r: Request<'a, D, S>) -> Self {
253 WaitGuard(Some(r))
254 }
255}
256
257impl<'a, D: ?Sized, S: Scope<'a>> WaitGuard<'a, D, S> {
258 pub fn wait(mut self) -> Status {
260 self.0.take().unwrap().wait()
261 }
262}
263
264impl<D: ?Sized, S> Drop for WaitGuard<'_, D, S> {
265 fn drop(&mut self) {
266 if let Some(r) = self.0.take() {
267 let mut r = std::mem::ManuallyDrop::new(r);
269 let state = std::mem::replace(&mut r.state, State::Consumed);
270 match state {
271 State::PendingRecv {
272 ctx,
273 source,
274 tag,
275 ptr,
276 len,
277 } => {
278 let _ = complete_recv(ctx, source, tag, ptr, len);
279 }
280 State::PendingJoin { mut handle } => {
281 if let Some(h) = handle.take() {
282 let _ = h.join();
283 }
284 }
285 State::Completed { .. } | State::Consumed => {}
286 }
287 }
288 }
289}
290
291pub struct CancelGuard<'a, D: ?Sized = [u8], S = StaticScope>(Option<Request<'a, D, S>>);
294
295impl<'a, D: ?Sized, S: Scope<'a>> From<Request<'a, D, S>> for CancelGuard<'a, D, S> {
296 fn from(r: Request<'a, D, S>) -> Self {
297 CancelGuard(Some(r))
298 }
299}
300
301impl<D: ?Sized, S> Drop for CancelGuard<'_, D, S> {
302 fn drop(&mut self) {
303 if let Some(r) = self.0.take() {
304 let mut r = std::mem::ManuallyDrop::new(r);
305 if let State::PendingJoin { handle } = &mut r.state {
308 if let Some(h) = handle.take() {
309 let _ = h.join();
310 }
311 }
312 r.state = State::Consumed;
313 }
314 }
315}
316
317pub fn wait_any<'a, D: ?Sized, S: Scope<'a>>(
321 requests: &mut Vec<Request<'a, D, S>>,
322) -> Option<(usize, Status)> {
323 if requests.is_empty() {
324 return None;
325 }
326 loop {
327 for i in 0..requests.len() {
328 if requests[i].ready() {
329 let r = requests.remove(i);
330 return Some((i, r.wait()));
331 }
332 }
333 std::thread::yield_now();
334 }
335}
336
337pub fn wait_all<'a, D: ?Sized, S: Scope<'a>>(requests: Vec<Request<'a, D, S>>) -> Vec<Status> {
339 requests.into_iter().map(|r| r.wait()).collect()
340}
341
342use std::sync::atomic::{AtomicBool, Ordering};
345use std::sync::Arc;
346
347struct GReqState {
348 done: AtomicBool,
349 status: std::sync::Mutex<Option<Status>>,
350}
351
352pub struct GeneralizedRequest {
358 state: Arc<GReqState>,
359}
360
361pub struct GeneralizedRequestCompleter {
364 state: Arc<GReqState>,
365}
366
367impl GeneralizedRequest {
368 pub fn start() -> (GeneralizedRequest, GeneralizedRequestCompleter) {
371 let state = Arc::new(GReqState {
372 done: AtomicBool::new(false),
373 status: std::sync::Mutex::new(None),
374 });
375 (
376 GeneralizedRequest {
377 state: Arc::clone(&state),
378 },
379 GeneralizedRequestCompleter { state },
380 )
381 }
382
383 pub fn is_complete(&self) -> bool {
385 self.state.done.load(Ordering::Acquire)
386 }
387
388 pub fn wait(self) -> Status {
390 while !self.state.done.load(Ordering::Acquire) {
391 std::thread::yield_now();
392 }
393 self.state
394 .status
395 .lock()
396 .unwrap()
397 .unwrap_or(Status::new(0, 0, 0, 0))
398 }
399
400 pub fn test(self) -> Result<Status, GeneralizedRequest> {
402 if self.state.done.load(Ordering::Acquire) {
403 Ok(self
404 .state
405 .status
406 .lock()
407 .unwrap()
408 .unwrap_or(Status::new(0, 0, 0, 0)))
409 } else {
410 Err(self)
411 }
412 }
413}
414
415impl GeneralizedRequestCompleter {
416 pub fn complete(self) {
418 *self.state.status.lock().unwrap() = Some(Status::new(0, 0, 0, 0));
419 self.state.done.store(true, Ordering::Release);
420 }
421}
422
423enum PersistentKind {
426 Send {
427 src: Rank,
428 dest_world: i32,
429 dt: u32,
430 count: u64,
431 },
432 Recv {
433 source: Rank,
434 },
435}
436
437pub struct PersistentRequest<'a> {
442 ctx: u32,
443 tag: Tag,
444 kind: PersistentKind,
445 ptr: *mut u8,
446 len: usize,
447 last: Option<Status>,
448 _life: PhantomData<&'a mut ()>,
449}
450
451impl<'a> PersistentRequest<'a> {
452 #[allow(clippy::too_many_arguments)]
453 pub(crate) fn new_send(
454 ctx: u32,
455 src: Rank,
456 dest_world: i32,
457 tag: Tag,
458 dt: u32,
459 count: u64,
460 ptr: *const u8,
461 len: usize,
462 ) -> PersistentRequest<'a> {
463 PersistentRequest {
464 ctx,
465 tag,
466 kind: PersistentKind::Send {
467 src,
468 dest_world,
469 dt,
470 count,
471 },
472 ptr: ptr as *mut u8,
473 len,
474 last: None,
475 _life: PhantomData,
476 }
477 }
478
479 pub(crate) fn new_recv(
480 ctx: u32,
481 source: Rank,
482 tag: Tag,
483 ptr: *mut u8,
484 len: usize,
485 ) -> PersistentRequest<'a> {
486 PersistentRequest {
487 ctx,
488 tag,
489 kind: PersistentKind::Recv { source },
490 ptr,
491 len,
492 last: None,
493 _life: PhantomData,
494 }
495 }
496
497 pub fn start(&mut self) {
499 match self.kind {
500 PersistentKind::Send {
501 src,
502 dest_world,
503 dt,
504 count,
505 } => {
506 let bytes = unsafe { std::slice::from_raw_parts(self.ptr, self.len) };
508 transport::runtime()
509 .send(self.ctx, src, dest_world, self.tag, count, dt, bytes)
510 .expect("persistent send failed");
511 self.last = Some(Status::new(dest_world, self.tag, count as Count, self.len));
512 }
513 PersistentKind::Recv { .. } => {}
514 }
515 }
516
517 pub fn wait(&mut self) -> Status {
519 match self.kind {
520 PersistentKind::Send { .. } => self.last.take().unwrap_or(Status::new(0, 0, 0, 0)),
521 PersistentKind::Recv { source } => {
522 let (s, t, count, _dt, payload) =
523 transport::runtime().recv(self.ctx, source, self.tag);
524 let n = self.len.min(payload.len());
525 unsafe {
527 std::ptr::copy_nonoverlapping(payload.as_ptr(), self.ptr, n);
528 }
529 Status::new(s, t, count as Count, payload.len())
530 }
531 }
532 }
533}