<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl.xml"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
    <title>Changes in mod.rs</title>
    <description></description>
    <language>en</language>
    <copyright>Copyright 2015</copyright>
    <generator>Java</generator><item>
        <title>5b79f08a - remove unnecessary async in public API (#338)</title>
        <link>http://172.16.0.5:8080/history/webrtc/turn/src/client/mod.rs#5b79f08a</link>
        <description>remove unnecessary async in public API (#338)&gt; mind if i create a PR that makes all callback setters (e.g. RTCPeerConnection::on_ice_candidate()) non async? Currently callbacks are stored behind tokio::Mutex&apos;es, i believe that ArcSwap can be used here, so we can use atomic load/store. It wont affect performance in any way, just some quality of life improvements.&gt; All good with me. I&apos;d like to get rid of  tokio::Mutex, replacing it with sync variants, where that&apos;s possibleSo i&apos;ve refactored all public callback setters here. Regarding removing `tokio::Mutex`es that you&apos;ve mentioned, well, i&apos;ve replaced some of those, but i don&apos;t want this PR to become even bigger, and it would be nice if you provide some feedback first. I&apos;ve used both `ArcSwap` and `std::Mutex`, i guess its ok to use blocking mutex in simple cases, when you don&apos;t need to hold it, e.g. copy, store, swap, take one-liners. I will prepare follow-up PRs on this issue if this PR looks good to you.And one more thing regarding the callbacks, maybe it makes sense to make them just dumb `Box&lt;dyn Fn(_)&gt;`? So `Box&lt;dyn (FnMut(ConnectionState) -&gt; Pin&lt;Box&lt;dyn Future&lt;Output = ()&gt; + Send + &apos;static&gt;&gt;) + Send + Sync&gt;` =&gt; `Box&lt;dyn (Fn(ConnectionState)) + Send + Sync&gt;`.  Yeah, that might hurt users in some rare cases, but it would make everything simpler.Been using this to play around with detecting deadlocks, didn&apos;t find anything though. ```diffdiff --git a/util/src/sync/mod.rs b/util/src/sync/mod.rsindex 6a101299..d5eb835d 100644--- a/util/src/sync/mod.rs+++ b/util/src/sync/mod.rs@@ -1,4 +1,150 @@-use std::{ops, sync};+use std::backtrace::Backtrace;+use std::sync::atomic::{AtomicBool, Ordering};+use std::sync::Arc;+use std::time::{Duration, Instant};+use std::{fmt, ops, sync, thread};++const MAX_AGE: Duration = Duration::from_millis(5000);+const CHECK_INTERVAL: Duration = Duration::from_millis(20);+static DEADLOCK_THREAD_STARTED: AtomicBool = AtomicBool::new(false);+lazy_static! {+    static ref TRACKED_LOCKS: Arc&lt;sync::RwLock&lt;Vec&lt;TrackedLock&gt;&gt;&gt; =+        Arc::new(sync::RwLock::new(Vec::new()));+}++struct TrackedLock {+    backtrace: Backtrace,+    tracker: AliveTracker,+    typ: Type,+    reported: AtomicBool,+}++impl TrackedLock {+    fn mark_reported(&amp;self) -&gt; bool {+        self.reported+            .compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)+            .is_ok()+    }+}++#[derive(Debug)]+enum Type {+    MutexLock,+    RwReadLock,+    RwWriteLock,+}++impl fmt::Display for Type {+    fn fmt(&amp;self, f: &amp;mut std::fmt::Formatter&lt;&apos;_&gt;) -&gt; std::fmt::Result {+        match self {+            Type::MutexLock =&gt; write!(f, &quot;MutexLock&quot;),+            Type::RwReadLock =&gt; write!(f, &quot;RwReadLock&quot;),+            Type::RwWriteLock =&gt; write!(f, &quot;RwWriteLock&quot;),+        }+    }+}++struct Alive {+    live: Arc&lt;AtomicBool&gt;,+    born_at: Instant,+}++impl Alive {+    fn new() -&gt; Self {+        Self {+            live: Arc::new(AtomicBool::new(true)),+            born_at: Instant::now(),+        }+    }++    fn track(&amp;self) -&gt; AliveTracker {+        AliveTracker {+            live: self.live.clone(),+            born_at: self.born_at.clone(),+        }+    }++    fn mark_dead(&amp;self) {+        self.live.store(false, Ordering::Release);+    }+}++impl Drop for Alive {+    fn drop(&amp;mut self) {+        self.mark_dead();+    }+}++struct AliveTracker {+    live: Arc&lt;AtomicBool&gt;,+    born_at: Instant,+}++impl AliveTracker {+    fn is_dead(&amp;self) -&gt; bool {+        !self.live.load(Ordering::Acquire)+    }++    fn age(&amp;self) -&gt; Option&lt;Duration&gt; {+        if self.is_dead() {+            None+        } else {+            Some(Instant::now() - self.born_at)+        }+    }+}++fn start_deadlock_thread() {+    if DEADLOCK_THREAD_STARTED+        .compare_exchange(false, true, Ordering::Acquire, Ordering::Acquire)+        .is_err()+    {+        return;+    }++    thread::spawn(|| loop {+        let lock = TRACKED_LOCKS.read().unwrap();+        let mut needs_cleanup = false;++        for tracked in lock.iter() {+            let age = tracked.tracker.age();+            match age {+                Some(age) if age &gt; MAX_AGE =&gt; {+                    if tracked.mark_reported() {+                        println!(+                            &quot;Potential deadlock on {}. Backtrace:\n{}Held for: {}s&quot;,+                            tracked.typ,+                            tracked.backtrace,+                            age.as_secs_f64()+                        );+                    }+                }+                None =&gt; {+                    // Lock is dead+                    needs_cleanup = true;+                }+                _ =&gt; {}+            }+        }+        drop(lock);++        if needs_cleanup {+            let mut write = TRACKED_LOCKS.write().unwrap();+            write.retain(|tracked| !tracked.tracker.is_dead());+        }+    });+}++fn track(backtrace: Backtrace, alive: &amp;Alive, typ: Type) {+    start_deadlock_thread();+    let mut write = TRACKED_LOCKS.write().unwrap();+    write.push(TrackedLock {+        backtrace,+        tracker: alive.track(),+        typ,+        reported: AtomicBool::new(false),+    });+}  /// A synchronous mutual exclusion primitive useful for protecting shared data. #[derive(Default, Debug)]@@ -13,8 +159,10 @@ impl&lt;T&gt; Mutex&lt;T&gt; {     /// Acquires a mutex, blocking the current thread until it is able to do so.     pub fn lock(&amp;self) -&gt; MutexGuard&lt;&apos;_, T&gt; {         let guard = self.0.lock().unwrap();+        let alive = Alive::new();+        track(Backtrace::capture(), &amp;alive, Type::MutexLock); -        MutexGuard(guard)+        MutexGuard(guard, alive)     }      /// Consumes this mutex, returning the underlying data.@@ -25,7 +173,7 @@ impl&lt;T&gt; Mutex&lt;T&gt; {  /// An RAII implementation of a &quot;scoped lock&quot; of a mutex. When this structure is /// dropped (falls out of scope), the lock will be unlocked.-pub struct MutexGuard&lt;&apos;a, T&gt;(sync::MutexGuard&lt;&apos;a, T&gt;);+pub struct MutexGuard&lt;&apos;a, T&gt;(sync::MutexGuard&lt;&apos;a, T&gt;, Alive);  impl&lt;&apos;a, T&gt; ops::Deref for MutexGuard&lt;&apos;a, T&gt; {     type Target = T;@@ -55,22 +203,26 @@ impl&lt;T&gt; RwLock&lt;T&gt; {     /// until it can be acquired.     pub fn read(&amp;self) -&gt; RwLockReadGuard&lt;&apos;_, T&gt; {         let guard = self.0.read().unwrap();+        let alive = Alive::new();+        track(Backtrace::capture(), &amp;alive, Type::MutexLock); -        RwLockReadGuard(guard)+        RwLockReadGuard(guard, alive)     }      /// Locks this rwlock with exclusive write access, blocking the current     /// thread until it can be acquired.     pub fn write(&amp;self) -&gt; RwLockWriteGuard&lt;&apos;_, T&gt; {         let guard = self.0.write().unwrap();+        let alive = Alive::new();+        track(Backtrace::capture(), &amp;alive, Type::MutexLock); -        RwLockWriteGuard(guard)+        RwLockWriteGuard(guard, alive)     } }  /// RAII structure used to release the shared read access of a lock when /// dropped.-pub struct RwLockReadGuard&lt;&apos;a, T&gt;(sync::RwLockReadGuard&lt;&apos;a, T&gt;);+pub struct RwLockReadGuard&lt;&apos;a, T&gt;(sync::RwLockReadGuard&lt;&apos;a, T&gt;, Alive);  impl&lt;&apos;a, T&gt; ops::Deref for RwLockReadGuard&lt;&apos;a, T&gt; {     type Target = T;@@ -82,7 +234,7 @@ impl&lt;&apos;a, T&gt; ops::Deref for RwLockReadGuard&lt;&apos;a, T&gt; {  /// RAII structure used to release the shared read access of a lock when /// dropped.-pub struct RwLockWriteGuard&lt;&apos;a, T&gt;(sync::RwLockWriteGuard&lt;&apos;a, T&gt;);+pub struct RwLockWriteGuard&lt;&apos;a, T&gt;(sync::RwLockWriteGuard&lt;&apos;a, T&gt;, Alive);  impl&lt;&apos;a, T&gt; ops::Deref for RwLockWriteGuard&lt;&apos;a, T&gt; {     type Target = T;```

            List of files:
            /webrtc/turn/src/client/mod.rs</description>
        <pubDate>Mon, 14 Nov 2022 01:51:36 +0000</pubDate>
        <dc:creator>alexlapa &lt;36732824+alexlapa@users.noreply.github.com&gt;</dc:creator>
    </item>
<item>
        <title>d897e473 - Fix clippy for 1.65.0</title>
        <link>http://172.16.0.5:8080/history/webrtc/turn/src/client/mod.rs#d897e473</link>
        <description>Fix clippy for 1.65.0

            List of files:
            /webrtc/turn/src/client/mod.rs</description>
        <pubDate>Thu, 10 Nov 2022 11:18:52 +0000</pubDate>
        <dc:creator>Hugo Tunius &lt;hugo@lookback.io&gt;</dc:creator>
    </item>
<item>
        <title>ffe74184 - Move all to top level</title>
        <link>http://172.16.0.5:8080/history/webrtc/turn/src/client/mod.rs#ffe74184</link>
        <description>Move all to top level

            List of files:
            /webrtc/turn/src/client/mod.rs</description>
        <pubDate>Tue, 23 Aug 2022 10:27:13 +0000</pubDate>
        <dc:creator>Martin Algesten &lt;martin@algesten.se&gt;</dc:creator>
    </item>
</channel>
</rss>
