Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save atmouse-/b0c6a4b93a228bb0dafe32f0b7f94d76 to your computer and use it in GitHub Desktop.
Save atmouse-/b0c6a4b93a228bb0dafe32f0b7f94d76 to your computer and use it in GitHub Desktop.
From 07749a072830864211d045ea196490b2f56c4e1d Mon Sep 17 00:00:00 2001
From: jingjiezhuang <jingjie.zhuang@igg.com>
Date: Sun, 5 Dec 2021 19:23:35 +0800
Subject: [PATCH] Use an AtomicPtr for PulseStream's drain_timer
There is a race condition between `drained_cb` and `PulseStream::stop` that
happens reliably on Firefox CI with rust 1.56 beta (LLVM 13) and PGO
instrumentation. Here's how it goes:
- in the Firefox AudioIPC Server RPC thread, `PulseStream::stop` is
called
- `PulseStream::stop enters the loop waiting for drain, and blocks on
`mainloop.wait`
- Later, some other thread calls `drained_cb`, which resets `drain_timer`,
and signals the mainloop.
- Back the other AudioIPC Server RPC thread, `mainloop.wait` returns,
looping back to the test for `drain_timer`... which this thread
doesn't know had been updated yet, so it blocks on `mainloop.wait`
again.
---
third_party/rust/cubeb-pulse/.cargo-checksum.json | 2 +-
third_party/rust/cubeb-pulse/src/backend/stream.rs | 33 +++++++++++++++++++--------------
2 file changed, 20 insertions(+), 15 deletions(-)
diff --git a/third_party/rust/cubeb-pulse/src/backend/stream.rs b/third_party/rust/cubeb-pulse/src/backend/stream.rs
index a210e2d..b9d4580 100644
--- a/third_party/rust/cubeb-pulse/src/backend/stream.rs
+++ b/third_party/rust/cubeb-pulse/src/backend/stream.rs
@@ -13,7 +13,7 @@ use std::{mem, ptr};
use std::ffi::{CStr, CString};
use std::os::raw::{c_long, c_void};
use std::slice;
-use std::sync::atomic::{AtomicUsize, Ordering};
+use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use ringbuf::RingBuffer;
use self::RingBufferConsumer::*;
@@ -267,7 +267,7 @@ pub struct PulseStream<'ctx> {
input_stream: Option<pulse::Stream>,
data_callback: ffi::cubeb_data_callback,
state_callback: ffi::cubeb_state_callback,
- drain_timer: *mut pa_time_event,
+ drain_timer: AtomicPtr<pa_time_event>,
output_sample_spec: pulse::SampleSpec,
input_sample_spec: pulse::SampleSpec,
output_frame_count: AtomicUsize,
@@ -399,7 +399,7 @@ impl<'ctx> PulseStream<'ctx> {
data_callback: data_callback,
state_callback: state_callback,
user_ptr: user_ptr,
- drain_timer: ptr::null_mut(),
+ drain_timer: AtomicPtr::new(ptr::null_mut()),
output_sample_spec: pulse::SampleSpec::default(),
input_sample_spec: pulse::SampleSpec::default(),
output_frame_count: AtomicUsize::new(0),
@@ -564,9 +564,10 @@ impl<'ctx> PulseStream<'ctx> {
self.context.mainloop.lock();
{
if let Some(stm) = self.output_stream.take() {
- if !self.drain_timer.is_null() {
+ let drain_timer = self.drain_timer.load(Ordering::Acquire);
+ if !drain_timer.is_null() {
/* there's no pa_rttime_free, so use this instead. */
- self.context.mainloop.get_api().time_free(self.drain_timer);
+ self.context.mainloop.get_api().time_free(drain_timer);
}
stm.clear_state_callback();
stm.clear_write_callback();
@@ -626,7 +627,7 @@ impl<'ctx> StreamOps for PulseStream<'ctx> {
self.context.mainloop.lock();
self.shutdown = true;
// If draining is taking place wait to finish
- while !self.drain_timer.is_null() {
+ while !self.drain_timer.load(Ordering::Acquire).is_null() {
self.context.mainloop.wait();
}
self.context.mainloop.unlock();
@@ -974,11 +975,12 @@ impl<'ctx> PulseStream<'ctx> {
u: *mut c_void,
) {
let stm = unsafe { &mut *(u as *mut PulseStream) };
- debug_assert_eq!(stm.drain_timer, e);
+ let drain_timer = stm.drain_timer.load(Ordering::Acquire);
+ debug_assert_eq!(drain_timer, e);
stm.state_change_callback(ffi::CUBEB_STATE_DRAINED);
/* there's no pa_rttime_free, so use this instead. */
- a.time_free(stm.drain_timer);
- stm.drain_timer = ptr::null_mut();
+ a.time_free(drain_timer);
+ stm.drain_timer.store(ptr::null_mut(), Ordering::Release);
stm.context.mainloop.signal();
}
@@ -1070,13 +1072,16 @@ impl<'ctx> PulseStream<'ctx> {
/* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */
/* arbitrary safety margin: double the current latency. */
- debug_assert!(self.drain_timer.is_null());
+ debug_assert!(self.drain_timer.load(Ordering::Acquire).is_null());
let stream_ptr = self as *const _ as *mut _;
if let Some(ref context) = self.context.context {
- self.drain_timer = context.rttime_new(
- pulse::rtclock_now() + 2 * latency,
- drained_cb,
- stream_ptr,
+ self.drain_timer.store(
+ context.rttime_new(
+ pulse::rtclock_now() + 2 * latency,
+ drained_cb,
+ stream_ptr,
+ ),
+ Ordering::Release,
);
}
self.shutdown = true;
diff --git a/third_party/rust/cubeb-pulse/.cargo-checksum.json b/third_party/rust/cubeb-pulse/.cargo-checksum.json
index f93b0fe..1da0be0 100644
--- a/third_party/rust/cubeb-pulse/.cargo-checksum.json
+++ b/third_party/rust/cubeb-pulse/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".travis.yml":"0394e2adb041175457685cde5ee05ff04bdab8885fd8a62551f2ff43d9e48872","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"56e90cb82ec36ead07e551a28fc2455fa658fa8308c3d73f8d856d85bfcd2122","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"e6a98ee5630b9ce1a096a2907d095454f2770e298a5b0976ab552cc53ca96cfc","src/backend/context.rs":"33d9fdf1504fe1ae43d301e288daf6eaeabeb47aa0ef86efa135c6d984425fc4","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"374a9a3bd79fddc47739dda1dbfc5929aea5a91946794fe65fba3c8d130fbda9","src/backend/mod.rs":"06ce9250865abf0ea461f215b128470636d072a6776821efef3caf5a7b992fb9","src/backend/stream.rs":"b8700fffb4d1537bc2fd3f0e26e7bbb16bc6e7cc7a803723e06704610ca1f6f5","src/capi.rs":"b2c1be8128cadd36caa65c80950440f9d6f2aa0c24cc7bae6a9eaf6347ac454d","src/lib.rs":"7282560d84b134b09acfd8d6282600982e42fb3557f72454c535637cc26c7bf6"},"package":null}
\ No newline at end of file
+{"files":{".editorconfig":"bf047bd1da10cabb99eea666d1e57c321eba4716dccb3e4ed0e2c5fe3ca53858",".travis.yml":"0394e2adb041175457685cde5ee05ff04bdab8885fd8a62551f2ff43d9e48872","AUTHORS":"0e0ac930a68ce2f6b876126b195add177f0d3886facb9260f4d9b69f1988f0cc","Cargo.toml":"56e90cb82ec36ead07e551a28fc2455fa658fa8308c3d73f8d856d85bfcd2122","LICENSE":"44c6b5ae5ec3fe2fbc608b00e6f4896f4d2d5c7e525fcbaa3eaa3cf2f3d5a983","README.md":"e6a98ee5630b9ce1a096a2907d095454f2770e298a5b0976ab552cc53ca96cfc","src/backend/context.rs":"33d9fdf1504fe1ae43d301e288daf6eaeabeb47aa0ef86efa135c6d984425fc4","src/backend/cork_state.rs":"4a0f1afc7d9f333dac89218cc56d7d32fbffb487cd48c1c9a4e03d79cb3b5e28","src/backend/intern.rs":"374a9a3bd79fddc47739dda1dbfc5929aea5a91946794fe65fba3c8d130fbda9","src/backend/mod.rs":"06ce9250865abf0ea461f215b128470636d072a6776821efef3caf5a7b992fb9","src/backend/stream.rs":"07a29b8086774123e22dff2252a5cd2ee4c337a55e72beee1d60c4164b75280e","src/capi.rs":"b2c1be8128cadd36caa65c80950440f9d6f2aa0c24cc7bae6a9eaf6347ac454d","src/lib.rs":"7282560d84b134b09acfd8d6282600982e42fb3557f72454c535637cc26c7bf6"},"package":null}
\ No newline at end of file
--
2.32.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment