Thanks for using Compiler Explorer
Sponsors
Jakt
C++
Ada
Algol68
Analysis
Android Java
Android Kotlin
Assembly
C
C3
Carbon
C with Coccinelle
C++ with Coccinelle
C++ (Circle)
CIRCT
Clean
Clojure
CMake
CMakeScript
COBOL
C++ for OpenCL
MLIR
Cppx
Cppx-Blue
Cppx-Gold
Cpp2-cppfront
Crystal
C#
CUDA C++
D
Dart
Elixir
Erlang
Fortran
F#
GLSL
Go
Haskell
HLSL
Helion
Hook
Hylo
IL
ispc
Java
Julia
Kotlin
LLVM IR
LLVM MIR
Modula-2
Mojo
Nim
Numba
Nix
Objective-C
Objective-C++
OCaml
Odin
OpenCL C
Pascal
Pony
PTX
Python
Racket
Raku
Ruby
Rust
Sail
Snowball
Scala
Slang
Solidity
Spice
SPIR-V
Swift
LLVM TableGen
Toit
Triton
TypeScript Native
V
Vala
Visual Basic
Vyper
WASM
Yul (Solidity IR)
Zig
Javascript
GIMPLE
Ygen
sway
rust source #1
Output
Compile to binary object
Link to binary
Execute the code
Intel asm syntax
Demangle identifiers
Verbose demangling
Filters
Unused labels
Library functions
Directives
Comments
Horizontal whitespace
Debug intrinsics
Compiler
mrustc (master)
rustc 1.0.0
rustc 1.1.0
rustc 1.10.0
rustc 1.11.0
rustc 1.12.0
rustc 1.13.0
rustc 1.14.0
rustc 1.15.1
rustc 1.16.0
rustc 1.17.0
rustc 1.18.0
rustc 1.19.0
rustc 1.2.0
rustc 1.20.0
rustc 1.21.0
rustc 1.22.0
rustc 1.23.0
rustc 1.24.0
rustc 1.25.0
rustc 1.26.0
rustc 1.27.0
rustc 1.27.1
rustc 1.28.0
rustc 1.29.0
rustc 1.3.0
rustc 1.30.0
rustc 1.31.0
rustc 1.32.0
rustc 1.33.0
rustc 1.34.0
rustc 1.35.0
rustc 1.36.0
rustc 1.37.0
rustc 1.38.0
rustc 1.39.0
rustc 1.4.0
rustc 1.40.0
rustc 1.41.0
rustc 1.42.0
rustc 1.43.0
rustc 1.44.0
rustc 1.45.0
rustc 1.45.2
rustc 1.46.0
rustc 1.47.0
rustc 1.48.0
rustc 1.49.0
rustc 1.5.0
rustc 1.50.0
rustc 1.51.0
rustc 1.52.0
rustc 1.53.0
rustc 1.54.0
rustc 1.55.0
rustc 1.56.0
rustc 1.57.0
rustc 1.58.0
rustc 1.59.0
rustc 1.6.0
rustc 1.60.0
rustc 1.61.0
rustc 1.62.0
rustc 1.63.0
rustc 1.64.0
rustc 1.65.0
rustc 1.66.0
rustc 1.67.0
rustc 1.68.0
rustc 1.69.0
rustc 1.7.0
rustc 1.70.0
rustc 1.71.0
rustc 1.72.0
rustc 1.73.0
rustc 1.74.0
rustc 1.75.0
rustc 1.76.0
rustc 1.77.0
rustc 1.78.0
rustc 1.79.0
rustc 1.8.0
rustc 1.80.0
rustc 1.81.0
rustc 1.82.0
rustc 1.83.0
rustc 1.84.0
rustc 1.85.0
rustc 1.86.0
rustc 1.87.0
rustc 1.88.0
rustc 1.89.0
rustc 1.9.0
rustc 1.90.0
rustc 1.91.0
rustc beta
rustc nightly
rustc-cg-gcc (master)
x86-64 GCCRS (GCC master)
x86-64 GCCRS (GCCRS master)
x86-64 GCCRS 14.1 (GCC assertions)
x86-64 GCCRS 14.1 (GCC)
x86-64 GCCRS 14.2 (GCC assertions)
x86-64 GCCRS 14.2 (GCC)
x86-64 GCCRS 14.3 (GCC assertions)
x86-64 GCCRS 14.3 (GCC)
x86-64 GCCRS 15.1 (GCC assertions)
x86-64 GCCRS 15.1 (GCC)
x86-64 GCCRS 15.2 (GCC assertions)
x86-64 GCCRS 15.2 (GCC)
Options
Source code
use std::{ fmt::{Debug, Formatter}, future::Future, mem::replace, pin::Pin, sync::{Arc, Condvar}, }; #[cfg(feature = "hanging_detection")] use std::{ sync::{Arc}, task::{Poll, ready}, time::Duration, }; #[cfg(feature = "hanging_detection")] use tokio::time::{Timeout, timeout}; pub struct Event { #[cfg(feature = "hanging_detection")] description: Arc<dyn Fn() -> String + Sync + Send>, event: Arc<Condvar>, // event_listener::Event, } impl Event { /// See [`event_listener::Event::new`]. May attach a description that may optionally be read /// later. /// /// This confusingly takes a closure ([`FnOnce`]) that returns a nested closure ([`Fn`]). /// /// When `hanging_detection` is disabled, `description` is never called. /// /// When `hanging_detection` is enabled, the outer closure is called immediately. The outer /// closure can have an ephemeral lifetime. The inner closer must be `'static`, but is called /// only when the `description` is actually read. /// /// The outer closure allow avoiding extra lookups (e.g. task type info) that may be needed to /// capture information needed for constructing (moving into) the inner closure. #[inline(always)] pub fn new<InnerFn>(_description: impl FnOnce() -> InnerFn) -> Self where InnerFn: Fn() -> String + Sync + Send + 'static, { #[cfg(not(feature = "hanging_detection"))] return Self { event: Arc::new(Condvar::new()), }; #[cfg(feature = "hanging_detection")] return Self { description: Arc::new((_description)()), event: event_listener::Event::new(), }; } /// See [`event_listener::Event::listen`]. pub fn listen(&self) -> EventListener { #[cfg(not(feature = "hanging_detection"))] return EventListener { listener: self.event.clone(), }; #[cfg(feature = "hanging_detection")] return EventListener { description: self.description.clone(), note: Arc::new(String::new), future: Some(Box::pin(timeout( Duration::from_secs(10), self.event.listen(), ))), duration: Duration::from_secs(10), }; } /// See [`event_listener::Event::listen`]. May attach a note that may optionally be read later. /// /// This confusingly takes a closure ([`FnOnce`]) that returns a nested closure ([`Fn`]). /// /// When `hanging_detection` is disabled, `note` is never called. /// /// When `hanging_detection` is enabled, the outer closure is called immediately. The outer /// closure can have an ephemeral lifetime. The inner closer must be `'static`, but is called /// only when the `note` is actually read. /// /// The outer closure allow avoiding extra lookups (e.g. task type info) that may be needed to /// capture information needed for constructing (moving into) the inner closure. pub fn listen_with_note<InnerFn>(&self, _note: impl FnOnce() -> InnerFn) -> EventListener where InnerFn: Fn() -> String + Sync + Send + 'static, { #[cfg(not(feature = "hanging_detection"))] return EventListener { listener: self.event.clone(), }; #[cfg(feature = "hanging_detection")] return EventListener { description: self.description.clone(), note: Arc::new((_note)()), future: Some(Box::pin(timeout( Duration::from_secs(10), self.event.listen(), ))), duration: Duration::from_secs(10), }; } /// pulls out the event listener, leaving a new, empty event in its place. pub fn take(&mut self) -> Event { #[cfg(not(feature = "hanging_detection"))] return Self { event: replace(&mut self.event, Arc::new(Condvar::new())), }; #[cfg(feature = "hanging_detection")] return Self { description: self.description.clone(), event: replace(&mut self.event, event_listener::Event::new()), }; } } impl Event { /// see [event_listener::Event]::notify pub fn notify(&self, _n: usize) { self.event.notify_all(); } } impl Debug for Event { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut t = f.debug_tuple("Event"); #[cfg(feature = "hanging_detection")] t.field(&(self.description)()); t.finish() } } #[cfg(not(feature = "hanging_detection"))] pub struct EventListener { listener: Arc<Condvar>, } #[cfg(not(feature = "hanging_detection"))] impl Debug for EventListener { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_tuple("EventListener").finish() } } #[cfg(not(feature = "hanging_detection"))] impl Future for EventListener { type Output = (); fn poll( self: Pin<&mut Self>, _cx: &mut std::task::Context<'_>, ) -> std::task::Poll<Self::Output> { let mutex = std::sync::Mutex::new(()); let _guard = self.listener.wait(mutex.lock().unwrap()).unwrap(); std::task::Poll::Ready(()) } } #[cfg(feature = "hanging_detection")] pub struct EventListener { description: Arc<dyn Fn() -> String + Sync + Send>, note: Arc<dyn Fn() -> String + Sync + Send>, // Timeout need to stay pinned while polling and also while it's dropped. // So it's important to put it into a pinned Box to be able to take it out of the Option. future: Option<std::pin::Pin<Box<Timeout<event_listener::EventListener>>>>, duration: Duration, } #[cfg(feature = "hanging_detection")] impl Debug for EventListener { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut t = f.debug_tuple("EventListener"); t.field(&(self.description)()); let note = (self.note)(); if !note.is_empty() { t.field(¬e); } t.finish() } } #[cfg(feature = "hanging_detection")] impl Future for EventListener { type Output = (); fn poll( mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll<Self::Output> { while let Some(future) = self.future.as_mut() { match ready!(future.as_mut().poll(cx)) { Ok(_) => { self.future = None; return Poll::Ready(()); } Err(_) => { use crate::util::FormatDuration; eprintln!( "{:?} is potentially hanging (waiting for {})", self, FormatDuration(self.duration) ); self.duration *= 2; // SAFETY: Taking from Option is safe because the value is inside of a pinned // Box. Pinning must continue until dropped. let future = self.future.take().unwrap(); self.future = Some(Box::pin(timeout( self.duration, // SAFETY: We can move the inner future since it's an EventListener and // that is Unpin. unsafe { std::pin::Pin::into_inner_unchecked(future) }.into_inner(), ))); } } } // EventListener was awaited again after completion Poll::Ready(()) } } pub fn main(){ let event = std::hint::black_box(Event::new(|| || "description".to_string())); let mut listener = std::hint::black_box(event.listen_with_note(|| || "note".to_string())); let mut cx = std::hint::black_box(std::task::Context::from_waker(&std::task::Waker::noop())); let _ = std::hint::black_box(<EventListener as Future>::poll(Pin::new(&mut listener), &mut cx)); }
Become a Patron
Sponsor on GitHub
Donate via PayPal
Compiler Explorer Shop
Source on GitHub
Mailing list
Installed libraries
Wiki
Report an issue
How it works
Contact the author
CE on Mastodon
CE on Bluesky
Statistics
Changelog
Version tree