Bug 1619005 - Update cubeb-coreaudio to 799518a. r=padenot

Pick commits:
799518a - Rework threading model (#55)
6e3e8e8 - Fix memory leak (#54)
996fcfa - Revise messages in test_switch_device
6fac4a6 - Isolate device tests (#53)
b78e817 - Save the duplicate tests and compilings when running sanitizers (#52)

Differential Revision: https://phabricator.services.mozilla.com/D67536

--HG--
rename : third_party/rust/cubeb-coreaudio/run_tests.sh => third_party/rust/cubeb-coreaudio/run_device_tests.sh
extra : moz-landing-system : lando
This commit is contained in:
Chun-Min Chang 2020-03-20 16:41:27 +00:00
Родитель 773f537bd6
Коммит 4c786bae99
15 изменённых файлов: 419 добавлений и 266 удалений

Просмотреть файл

@ -75,7 +75,7 @@ rev = "5e870faf6f95d79d11efc813e56370ad124bbed5"
[source."https://github.com/ChunMinChang/cubeb-coreaudio-rs"]
git = "https://github.com/ChunMinChang/cubeb-coreaudio-rs"
replace-with = "vendored-sources"
rev = "4acd80233efa645ac79769f37b07d495c1b42070"
rev = "799518a033a0c780cfdb82a4eaabfd9681cb7f3b"
[source.crates-io]
replace-with = "vendored-sources"

4
Cargo.lock сгенерированный
Просмотреть файл

@ -686,7 +686,7 @@ dependencies = [
[[package]]
name = "coreaudio-sys-utils"
version = "0.1.0"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=4acd80233efa645ac79769f37b07d495c1b42070#4acd80233efa645ac79769f37b07d495c1b42070"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=799518a033a0c780cfdb82a4eaabfd9681cb7f3b#799518a033a0c780cfdb82a4eaabfd9681cb7f3b"
dependencies = [
"core-foundation-sys",
"coreaudio-sys",
@ -923,7 +923,7 @@ dependencies = [
[[package]]
name = "cubeb-coreaudio"
version = "0.1.0"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=4acd80233efa645ac79769f37b07d495c1b42070#4acd80233efa645ac79769f37b07d495c1b42070"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=799518a033a0c780cfdb82a4eaabfd9681cb7f3b#799518a033a0c780cfdb82a4eaabfd9681cb7f3b"
dependencies = [
"atomic",
"audio-mixer",

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"35acbd2f8633a6109f3d3e554bef8d847c049ce6ef7a5f570468819e41344d7f","src/aggregate_device.rs":"7d2bd5f5fd7f3d008ebb69ad81f522ca0cb73db6d7b3e50ed1a63ea26ff721f4","src/audio_object.rs":"df10160d9fd83a2c23a49e69b78d39db3a9d6389607df6acfc05821293b6af5f","src/audio_unit.rs":"d783878930df4923b57ad230138c0f3fd6b0b9bb80a39725092ff4c6615162d8","src/cf_mutable_dict.rs":"fc42edd270c6dfb02f123214d2d8e487bbd62b5bd923b71eec13190fd0104d2a","src/dispatch.rs":"195ca94cbc61948637bfdcbe22070a1e6d41e97cec22301df4e45dcef7b1c208","src/lib.rs":"bcc559d69ef6ed0cbea5b2a36fec89d8c011eb9da70e2f26c00f881ad97a2546","src/string.rs":"28f88b816c768bcfcc674a60d962b93f1c94e5e0f4cc8ed2a1301138b91039e7"},"package":null}
{"files":{"Cargo.toml":"35acbd2f8633a6109f3d3e554bef8d847c049ce6ef7a5f570468819e41344d7f","src/aggregate_device.rs":"7d2bd5f5fd7f3d008ebb69ad81f522ca0cb73db6d7b3e50ed1a63ea26ff721f4","src/audio_object.rs":"df10160d9fd83a2c23a49e69b78d39db3a9d6389607df6acfc05821293b6af5f","src/audio_unit.rs":"d783878930df4923b57ad230138c0f3fd6b0b9bb80a39725092ff4c6615162d8","src/cf_mutable_dict.rs":"fc42edd270c6dfb02f123214d2d8e487bbd62b5bd923b71eec13190fd0104d2a","src/dispatch.rs":"0f4b05076bf4ce8e9ce2a98c65149fcdd716b772a7ab111f37f9d12678552e1e","src/lib.rs":"bcc559d69ef6ed0cbea5b2a36fec89d8c011eb9da70e2f26c00f881ad97a2546","src/string.rs":"28f88b816c768bcfcc674a60d962b93f1c94e5e0f4cc8ed2a1301138b91039e7"},"package":null}

Просмотреть файл

@ -4,148 +4,203 @@ use std::ffi::CString;
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
pub const DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t = ptr::null_mut::<dispatch_queue_attr_s>();
// Queue: A wrapper around `dispatch_queue_t`.
// ------------------------------------------------------------------------------------------------
#[derive(Debug)]
pub struct Queue(dispatch_queue_t);
pub fn create_dispatch_queue(
label: &'static str,
queue_attr: dispatch_queue_attr_t,
) -> dispatch_queue_t {
let label = CString::new(label).unwrap();
let c_string = label.as_ptr();
unsafe { dispatch_queue_create(c_string, queue_attr) }
}
pub fn release_dispatch_queue(queue: dispatch_queue_t) {
// TODO: This is incredibly unsafe. Find another way to release the queue.
unsafe {
dispatch_release(mem::transmute::<dispatch_queue_t, dispatch_object_t>(queue));
impl Queue {
pub fn new(label: &str) -> Self {
const DISPATCH_QUEUE_SERIAL: dispatch_queue_attr_t =
ptr::null_mut::<dispatch_queue_attr_s>();
let label = CString::new(label).unwrap();
let c_string = label.as_ptr();
let queue = Self(unsafe { dispatch_queue_create(c_string, DISPATCH_QUEUE_SERIAL) });
queue.set_should_cancel(Box::new(AtomicBool::new(false)));
queue
}
}
pub fn async_dispatch<F>(queue: dispatch_queue_t, work: F)
where
F: Send + FnOnce(),
{
let (closure, executor) = create_closure_and_executor(work);
unsafe {
dispatch_async_f(queue, closure, executor);
pub fn run_async<F>(&self, work: F)
where
F: Send + FnOnce(),
{
let should_cancel = self.get_should_cancel();
let (closure, executor) = Self::create_closure_and_executor(|| {
if should_cancel.map_or(false, |v| v.load(Ordering::SeqCst)) {
return;
}
work();
});
unsafe {
dispatch_async_f(self.0, closure, executor);
}
}
}
pub fn sync_dispatch<F>(queue: dispatch_queue_t, work: F)
where
F: Send + FnOnce(),
{
let (closure, executor) = create_closure_and_executor(work);
unsafe {
dispatch_sync_f(queue, closure, executor);
pub fn run_sync<F>(&self, work: F)
where
F: Send + FnOnce(),
{
let should_cancel = self.get_should_cancel();
let (closure, executor) = Self::create_closure_and_executor(|| {
if should_cancel.map_or(false, |v| v.load(Ordering::SeqCst)) {
return;
}
work();
});
unsafe {
dispatch_sync_f(self.0, closure, executor);
}
}
}
// Return an raw pointer to a (unboxed) closure and an executor that
// will run the closure (after re-boxing the closure) when it's called.
fn create_closure_and_executor<F>(closure: F) -> (*mut c_void, dispatch_function_t)
where
F: FnOnce(),
{
extern "C" fn closure_executer<F>(unboxed_closure: *mut c_void)
pub fn run_final<F>(&self, work: F)
where
F: Send + FnOnce(),
{
let should_cancel = self.get_should_cancel();
let (closure, executor) = Self::create_closure_and_executor(|| {
work();
should_cancel
.expect("dispatch context should be allocated!")
.store(true, Ordering::SeqCst);
});
unsafe {
dispatch_sync_f(self.0, closure, executor);
}
}
fn get_should_cancel(&self) -> Option<&mut AtomicBool> {
unsafe {
let context = dispatch_get_context(
mem::transmute::<dispatch_queue_t, dispatch_object_t>(self.0),
) as *mut AtomicBool;
context.as_mut()
}
}
fn set_should_cancel(&self, context: Box<AtomicBool>) {
unsafe {
let queue = mem::transmute::<dispatch_queue_t, dispatch_object_t>(self.0);
// Leak the context from Box.
dispatch_set_context(queue, Box::into_raw(context) as *mut c_void);
extern "C" fn finalizer(context: *mut c_void) {
// Retake the leaked context into box and then drop it.
let _ = unsafe { Box::from_raw(context as *mut AtomicBool) };
}
// The `finalizer` is only run if the `context` in `queue` is set by `dispatch_set_context`.
dispatch_set_finalizer_f(queue, Some(finalizer));
}
}
fn release(&self) {
unsafe {
// This will release the inner `dispatch_queue_t` asynchronously.
// TODO: It's incredibly unsafe to call `transmute` directly.
// Find another way to release the queue.
dispatch_release(mem::transmute::<dispatch_queue_t, dispatch_object_t>(
self.0,
));
}
}
fn create_closure_and_executor<F>(closure: F) -> (*mut c_void, dispatch_function_t)
where
F: FnOnce(),
{
// Retake the leaked closure.
let closure = unsafe { Box::from_raw(unboxed_closure as *mut F) };
// Execute the closure.
(*closure)();
// closure is released after finishing this function call.
extern "C" fn closure_executer<F>(unboxed_closure: *mut c_void)
where
F: FnOnce(),
{
// Retake the leaked closure.
let closure = unsafe { Box::from_raw(unboxed_closure as *mut F) };
// Execute the closure.
(*closure)();
// closure is released after finishing this function call.
}
let closure = Box::new(closure); // Allocate closure on heap.
let executor: dispatch_function_t = Some(closure_executer::<F>);
(
Box::into_raw(closure) as *mut c_void, // Leak the closure.
executor,
)
}
let closure = Box::new(closure); // Allocate closure on heap.
let executor: dispatch_function_t = Some(closure_executer::<F>);
(
Box::into_raw(closure) as *mut c_void, // Leak the closure.
executor,
)
}
#[cfg(test)]
mod test {
use super::*;
use std::sync::{Arc, Mutex};
const COUNT: u32 = 10;
#[test]
fn test_async_dispatch() {
use std::sync::mpsc::channel;
get_queue_and_resource("Run with async dispatch api wrappers", |queue, resource| {
let (tx, rx) = channel();
for i in 0..COUNT {
let (res, tx) = (Arc::clone(&resource), tx.clone());
async_dispatch(queue, move || {
let mut res = res.lock().unwrap();
assert_eq!(res.last_touched, if i == 0 { None } else { Some(i - 1) });
assert_eq!(res.touched_count, i);
res.touch(i);
if i == COUNT - 1 {
tx.send(()).unwrap();
}
});
}
rx.recv().unwrap(); // Wait until it's touched COUNT times.
let resource = resource.lock().unwrap();
assert_eq!(resource.touched_count, COUNT);
assert_eq!(resource.last_touched.unwrap(), COUNT - 1);
});
impl Drop for Queue {
fn drop(&mut self) {
self.release();
}
}
#[test]
fn test_sync_dispatch() {
get_queue_and_resource("Run with sync dispatch api wrappers", |queue, resource| {
for i in 0..COUNT {
let res = Arc::clone(&resource);
sync_dispatch(queue, move || {
let mut res = res.lock().unwrap();
assert_eq!(res.last_touched, if i == 0 { None } else { Some(i - 1) });
assert_eq!(res.touched_count, i);
res.touch(i);
});
}
let resource = resource.lock().unwrap();
assert_eq!(resource.touched_count, COUNT);
assert_eq!(resource.last_touched.unwrap(), COUNT - 1);
});
}
struct Resource {
last_touched: Option<u32>,
touched_count: u32,
}
impl Resource {
fn new() -> Self {
Resource {
last_touched: None,
touched_count: 0,
}
}
fn touch(&mut self, who: u32) {
self.last_touched = Some(who);
self.touched_count += 1;
impl Clone for Queue {
fn clone(&self) -> Self {
// TODO: It's incredibly unsafe to call `transmute` directly.
// Find another way to release the queue.
unsafe {
dispatch_retain(mem::transmute::<dispatch_queue_t, dispatch_object_t>(
self.0,
));
}
Self(self.0)
}
}
#[test]
fn run_tasks_in_order() {
let mut visited = Vec::<u32>::new();
// Rust compilter doesn't allow a pointer to be passed across threads.
// A hacky way to do that is to cast the pointer into a value, then
// the value, which is actually an address, can be copied into threads.
let ptr = &mut visited as *mut Vec<u32> as usize;
fn visit(v: u32, visited_ptr: usize) {
let visited = unsafe { &mut *(visited_ptr as *mut Vec<u32>) };
visited.push(v);
};
let queue = Queue::new("Run tasks in order");
queue.run_sync(move || visit(1, ptr));
queue.run_sync(move || visit(2, ptr));
queue.run_async(move || visit(3, ptr));
queue.run_async(move || visit(4, ptr));
// Call sync here to block the current thread and make sure all the tasks are done.
queue.run_sync(move || visit(5, ptr));
assert_eq!(visited, vec![1, 2, 3, 4, 5]);
}
#[test]
fn run_final_task() {
let mut visited = Vec::<u32>::new();
fn get_queue_and_resource<F>(label: &'static str, callback: F)
where
F: FnOnce(dispatch_queue_t, Arc<Mutex<Resource>>),
{
let queue = create_dispatch_queue(label, DISPATCH_QUEUE_SERIAL);
let resource = Arc::new(Mutex::new(Resource::new()));
// Rust compilter doesn't allow a pointer to be passed across threads.
// A hacky way to do that is to cast the pointer into a value, then
// the value, which is actually an address, can be copied into threads.
let ptr = &mut visited as *mut Vec<u32> as usize;
callback(queue, resource);
fn visit(v: u32, visited_ptr: usize) {
let visited = unsafe { &mut *(visited_ptr as *mut Vec<u32>) };
visited.push(v);
};
// Release the queue.
release_dispatch_queue(queue);
let queue = Queue::new("Task after run_final will be cancelled");
queue.run_sync(move || visit(1, ptr));
queue.run_async(move || visit(2, ptr));
queue.run_final(move || visit(3, ptr));
queue.run_async(move || visit(4, ptr));
queue.run_sync(move || visit(5, ptr));
}
// `queue` will be dropped asynchronously and then the `finalizer` of the `queue`
// should be fired to clean up the `context` set in the `queue`.
assert_eq!(visited, vec![1, 2, 3]);
}

Просмотреть файл

@ -1 +1 @@
{"files":{".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".travis.yml":"878d9519da0844cd3de2999f81fce966452f0fb65150605c25a1abf3523360ab","Cargo.toml":"bcb3ec3785c3cbe799bb41c07176afdd0028328be79932a4e44bc97a364e8c69","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"fa323b7386a8a0c75478b77a30a3c5d33f1df23d9775b97570fa0501ef784e95","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_sanitizers.sh":"913efec447b4c37751af93eef4a974f293426c20c720d37c5bbe69e955d105eb","run_tests.sh":"fcdae57b81426c5dbfc8873a9ff1ac07924ed0717f822b50a67934cac2e9d4f1","src/backend/aggregate_device.rs":"ae21129aa6b3c7bd3376751b6a94d1ebe6c9f7afcd1db3107fb4d703d04da6b3","src/backend/auto_array.rs":"5f35545baba2b005e13a2225bd1cbdd94ffc2097554d61479929bfc5442a6dd6","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/device_property.rs":"324a7c9672daa49ee2221a56d140e1c8298719dab66f204b19d10f3632f96602","src/backend/mixer.rs":"0c237bd5ca63b028c4b22ddc5bc026d7e21c0fa9b4e337f00b6131ed0a0806a5","src/backend/mod.rs":"250cf24aabe1f1e9e8eafd375a538554523accaa6b514588b157d0c413d39b86","src/backend/resampler.rs":"fd1281d28a4db1659d2f75e43b8457651745e1b6eb5a53a77f04d752135f6dc7","src/backend/tests/aggregate_device.rs":"107f5c637844cd5ae43d2b42cec4ef3369bb702751586078c0a9d50f039161cd","src/backend/tests/api.rs":"d81128f0982ecc816666e91f57e722cc21ba9cc09a2a36103acc7c981f57b36d","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"2138e7ed4721872ce3a41f3652bfa4e7eca97fd136473af6472313c61ff24ed3","src/backend/tests/device_property.rs":"b1a9ae79aa5b9a3f180040d0ef0954b134680d586882d2062c5e017b555bff57","src/backend/tests/interfaces.rs":"14943e84a79976a7ef52882edeb9330350705d5190db6647f98b4ffa851a8396","src/backend/tests/manual.rs":"dc707836dab31f83d4b325afbc4dc4c8104ac8036e87f59ade3309ee83fe2d3f","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"16150438317ce501986734167b5fb97bfec567228acbcd8f3b4c4484c22f29e0","src/backend/tests/utils.rs":"1bb99ef71d3c18545bca49767e7b6bfffbe11896246994f41be7ed372772fd48","src/backend/utils.rs":"5ce1b753af0ffb654b6b2038d649aea88eebd27390a607a6d5988a9e40a4a717","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"29545b4d9c516396f82bd392797e2713d4602036eaba0f151b384af764f8515f"},"package":null}
{"files":{".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".travis.yml":"878d9519da0844cd3de2999f81fce966452f0fb65150605c25a1abf3523360ab","Cargo.toml":"bcb3ec3785c3cbe799bb41c07176afdd0028328be79932a4e44bc97a364e8c69","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0d5a4c39e737aeeccfd5a54914e8927631ad86e3da8c24f62594f2f89a3302bf","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"e66d32da5439818eee30fc5e7ed9ab9990723ffafe684870efe82dac11be07ef","run_sanitizers.sh":"54970203e86eed00245de3d9b53584d5d8868be983f90b27c603b310ba5554e5","run_tests.sh":"257ac9b30e0ff3775d713668a9704f15ad4ed2334aca7d8c544d079cde197e8a","src/backend/aggregate_device.rs":"ae21129aa6b3c7bd3376751b6a94d1ebe6c9f7afcd1db3107fb4d703d04da6b3","src/backend/auto_array.rs":"5f35545baba2b005e13a2225bd1cbdd94ffc2097554d61479929bfc5442a6dd6","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/device_property.rs":"324a7c9672daa49ee2221a56d140e1c8298719dab66f204b19d10f3632f96602","src/backend/mixer.rs":"0c237bd5ca63b028c4b22ddc5bc026d7e21c0fa9b4e337f00b6131ed0a0806a5","src/backend/mod.rs":"e6ed4937f9ca52626a0ab6728631a88c9ae1369fd1ff61a377dfa64c3d406fb3","src/backend/resampler.rs":"fd1281d28a4db1659d2f75e43b8457651745e1b6eb5a53a77f04d752135f6dc7","src/backend/tests/aggregate_device.rs":"107f5c637844cd5ae43d2b42cec4ef3369bb702751586078c0a9d50f039161cd","src/backend/tests/api.rs":"58cbf67e3f4588f5e644ebcdc24942fcd6299c26f42a7e27fb4b6b9d8e5245f8","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"8261f561f69dabd374ac47d69aa484812b65070a9e9581dfb2605e8404eaad6d","src/backend/tests/device_property.rs":"b1a9ae79aa5b9a3f180040d0ef0954b134680d586882d2062c5e017b555bff57","src/backend/tests/interfaces.rs":"14943e84a79976a7ef52882edeb9330350705d5190db6647f98b4ffa851a8396","src/backend/tests/manual.rs":"dc707836dab31f83d4b325afbc4dc4c8104ac8036e87f59ade3309ee83fe2d3f","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"16150438317ce501986734167b5fb97bfec567228acbcd8f3b4c4484c22f29e0","src/backend/tests/utils.rs":"1bb99ef71d3c18545bca49767e7b6bfffbe11896246994f41be7ed372772fd48","src/backend/utils.rs":"5ce1b753af0ffb654b6b2038d649aea88eebd27390a607a6d5988a9e40a4a717","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"29545b4d9c516396f82bd392797e2713d4602036eaba0f151b384af764f8515f"},"package":null}

21
third_party/rust/cubeb-coreaudio/README.md поставляемый
Просмотреть файл

@ -43,14 +43,22 @@ by `sh run_sanitizers.sh`.
The above command will run all the test suits in *run_tests.sh* by all the available _sanitizers_.
However, it takes a long time for finshing the tests.
### Device Switching
### Device Tests
Run `run_device_tests.sh`.
If you'd like to run all the device tests with sanitizers,
use `RUSTFLAGS="-Z sanitizer=<SAN>" sh run_device_tests.sh`
with valid `<SAN>` such as `address` or `thread`.
#### Device Switching
The system default device will be changed during our tests.
All the available devices will take turns being the system default device.
However, after finishing the tests, the default device will be set to the original one.
The sounds in the tests should be able to continue whatever the system default device is.
### Device Plugging/Unplugging
#### Device Plugging/Unplugging
We implement APIs simulating plugging or unplugging a device
by adding or removing an aggregate device programmatically.
@ -68,6 +76,15 @@ It's used to verify our callbacks for minitoring the system devices work.
- Device collection change
- `cargo test test_device_collection_change -- --ignored --nocapture`
- Plug/Unplug devices to see events log.
- Manual Stream Tester
- `cargo test test_stream_tester -- --ignored --nocapture`
- `c` to create a stream
- `d` to destroy a stream
- `s` to start the created stream
- `t` to stop the created stream
- `q` to quit the test
- It's useful to simulate the stream bahavior to reproduce the bug we found,
with some modified code.
## TODO

38
third_party/rust/cubeb-coreaudio/run_device_tests.sh поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
echo "\n\nRun device-changed tests\n===================="
if [[ -z "${RUST_BACKTRACE}" ]]; then
# Display backtrace for debugging
export RUST_BACKTRACE=1
fi
echo "RUST_BACKTRACE is set to ${RUST_BACKTRACE}\n"
cargo test test_switch_device -- --ignored --nocapture
cargo test test_plug_and_unplug_device -- --ignored --nocapture
# cargo test test_register_device_changed_callback -- --ignored --nocapture --test-threads=1
cargo test test_register_device_changed_callback_to_check_default_device_changed_input -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_default_device_changed_output -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_default_device_changed_duplex -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_input_alive_changed_input -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_input_alive_changed_duplex -- --ignored --nocapture
cargo test test_destroy_input_stream_after_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_destroy_input_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_destroy_output_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_output_stream_after_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_reinit_input_stream_by_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_reinit_input_stream_by_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_reinit_output_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_reinit_output_stream_by_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_reinit_duplex_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_default_output_device -- --ignored --nocapture

Просмотреть файл

@ -6,42 +6,15 @@
toolchain=$(rustup default)
echo "\nUse Rust toolchain: $toolchain"
if [[ $toolchain == nightly-* ]]
then
echo "Run sanitizers!"
else
if [[ $toolchain != nightly-* ]]; then
echo "The sanitizer is only available on Rust Nightly only. Skip."
exit
fi
# Run tests in the sub crate
# -------------------------------------------------------------------------------------------------
cd coreaudio-sys-utils
echo "\n\nRun ASan\n-----------\n"
RUSTFLAGS="-Z sanitizer=address" cargo test
echo "\n\nRun LSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=leak" cargo test
echo "\n\nRun MSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=memory" cargo test
echo "\n\nRun TSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=thread" cargo test
cd ..
# Run tests in the main crate
# -------------------------------------------------------------------------------------------------
echo "\n\nRun ASan\n-----------\n"
RUSTFLAGS="-Z sanitizer=address" sh run_tests.sh
echo "\n\nRun LSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=leak" sh run_tests.sh
echo "\n\nRun MSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=memory" sh run_tests.sh
echo "\n\nRun TSan\n-----------\n"
RUSTFLAGS="-Z sanitizer=thread" sh run_tests.sh
sanitizers=("address" "leak" "memory" "thread")
for san in "${sanitizers[@]}"
do
San="$(tr '[:lower:]' '[:upper:]' <<< ${san:0:1})${san:1}"
echo "\n\nRun ${San}Sanitizer\n------------------------------"
RUSTFLAGS="-Z sanitizer=${san}" sh run_tests.sh
done

55
third_party/rust/cubeb-coreaudio/run_tests.sh поставляемый
Просмотреть файл

@ -1,20 +1,30 @@
# display backtrace for debugging
export RUST_BACKTRACE=1
echo "\n\nTest suite for cubeb-coreaudio\n========================================"
if [[ -z "${RUST_BACKTRACE}" ]]; then
# Display backtrace for debugging
export RUST_BACKTRACE=1
fi
echo "RUST_BACKTRACE is set to ${RUST_BACKTRACE}\n"
# Run tests in the sub crate
# Run the tests by `cargo * -p <SUB_CRATE>` if it's possible. By doing so, the duplicate compiling
# between this crate and the <SUB_CRATE> can be saved. The compiling for <SUB_CRATE> can be reused
# when running `cargo *` with this crate.
# -------------------------------------------------------------------------------------------------
cd coreaudio-sys-utils
SUB_CRATE="coreaudio-sys-utils"
# Format check
# `cargo fmt -p *` is only usable in workspaces, so a workaround is to enter to the sub crate
# and then exit from it.
cd $SUB_CRATE
cargo fmt --all -- --check
cd ..
# Lints check
cargo clippy -- -D warnings
cargo clippy -p $SUB_CRATE -- -D warnings
# Regular Tests
cargo test
cd ..
cargo test -p $SUB_CRATE
# Run tests in the main crate
# -------------------------------------------------------------------------------------------------
@ -33,36 +43,7 @@ cargo test test_aggregate -- --ignored --test-threads=1
cargo test test_parallel -- --ignored --nocapture --test-threads=1
# Device-changed Tests
cargo test test_switch_device -- --ignored --nocapture
cargo test test_plug_and_unplug_device -- --ignored --nocapture
# cargo test test_register_device_changed_callback -- --ignored --nocapture --test-threads=1
cargo test test_register_device_changed_callback_to_check_default_device_changed_input -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_default_device_changed_output -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_default_device_changed_duplex -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_input_alive_changed_input -- --ignored --nocapture
cargo test test_register_device_changed_callback_to_check_input_alive_changed_duplex -- --ignored --nocapture
cargo test test_destroy_input_stream_after_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_destroy_input_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_destroy_output_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_output_stream_after_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_reinit_input_stream_by_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_reinit_input_stream_by_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_reinit_output_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_reinit_output_stream_by_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_default_input_device -- --ignored --nocapture
# FIXIT: The following test will hang since we don't monitor the alive status of the output device
# cargo test test_reinit_duplex_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_default_output_device -- --ignored --nocapture
sh run_device_tests.sh
# Manual Tests
# cargo test test_switch_output_device -- --ignored --nocapture

Просмотреть файл

@ -1597,8 +1597,8 @@ fn is_aggregate_device(device_info: &ffi::cubeb_device_info) -> bool {
}
}
fn audiounit_device_destroy(device: &mut ffi::cubeb_device_info) {
// This should be mapped to the memory allocation in audiounit_create_device_from_hwdev.
fn destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info) {
// This should be mapped to the memory allocation in create_cubeb_device_info.
// Set the pointers to null in case it points to some released memory.
unsafe {
if !device.device_id.is_null() {
@ -1696,12 +1696,12 @@ extern "C" fn audiounit_collection_changed_callback(
) -> OSStatus {
let context = unsafe { &mut *(in_client_data as *mut AudioUnitContext) };
let queue = context.serial_queue;
let queue = context.serial_queue.clone();
let mutexed_context = Arc::new(Mutex::new(context));
let also_mutexed_context = Arc::clone(&mutexed_context);
// This can be called from inside an AudioUnit function, dispatch to another queue.
async_dispatch(queue, move || {
queue.run_async(move || {
let ctx_guard = also_mutexed_context.lock().unwrap();
let ctx_ptr = *ctx_guard as *const AudioUnitContext;
@ -1849,10 +1849,7 @@ pub const OPS: Ops = capi_new!(AudioUnitContext, AudioUnitStream);
#[derive(Debug)]
pub struct AudioUnitContext {
_ops: *const Ops,
// serial_queue will be created by dispatch_queue_create(create_dispatch_queue)
// without ARC(Automatic Reference Counting) support, so it should be released
// by dispatch_release(release_dispatch_queue).
serial_queue: dispatch_queue_t,
serial_queue: Queue,
latency_controller: Mutex<LatencyController>,
devices: Mutex<SharedDevices>,
}
@ -1861,7 +1858,7 @@ impl AudioUnitContext {
fn new() -> Self {
Self {
_ops: &OPS as *const _,
serial_queue: create_dispatch_queue(DISPATCH_QUEUE_LABEL, DISPATCH_QUEUE_SERIAL),
serial_queue: Queue::new(DISPATCH_QUEUE_LABEL),
latency_controller: Mutex::new(LatencyController::default()),
devices: Mutex::new(SharedDevices::default()),
}
@ -2098,7 +2095,7 @@ impl ContextOps for AudioUnitContext {
let mut devices = retake_forgotten_vec(coll.device, coll.count);
for device in &mut devices {
audiounit_device_destroy(device);
destroy_cubeb_device_info(device);
}
drop(devices); // Release the memory.
coll.device = ptr::null_mut();
@ -2168,6 +2165,10 @@ impl ContextOps for AudioUnitContext {
global_latency_frames,
));
// Rename the task queue to be an unique label.
let queue_label = format!("{}.{:p}", DISPATCH_QUEUE_LABEL, boxed_stream.as_ref());
boxed_stream.queue = Queue::new(queue_label.as_str());
boxed_stream.core_stream_data =
CoreStreamData::new(boxed_stream.as_ref(), in_stm_settings, out_stm_settings);
@ -2218,11 +2219,14 @@ impl Drop for AudioUnitContext {
}
}
// Unregister the callback if necessary.
self.remove_devices_changed_listener(DeviceType::INPUT);
self.remove_devices_changed_listener(DeviceType::OUTPUT);
release_dispatch_queue(self.serial_queue);
// Make sure all the pending (device-collection-changed-callback) tasks
// in queue are done, and cancel all the tasks appended after `drop` is executed.
let queue = self.serial_queue.clone();
queue.run_final(|| {
// Unregister the callback if necessary.
self.remove_devices_changed_listener(DeviceType::INPUT);
self.remove_devices_changed_listener(DeviceType::OUTPUT);
});
}
}
@ -3071,6 +3075,8 @@ impl<'ctx> Drop for CoreStreamData<'ctx> {
struct AudioUnitStream<'ctx> {
context: &'ctx mut AudioUnitContext,
user_ptr: *mut c_void,
// Task queue for the stream.
queue: Queue,
data_callback: ffi::cubeb_data_callback,
state_callback: ffi::cubeb_state_callback,
@ -3107,6 +3113,7 @@ impl<'ctx> AudioUnitStream<'ctx> {
AudioUnitStream {
context,
user_ptr,
queue: Queue::new(DISPATCH_QUEUE_LABEL),
data_callback,
state_callback,
device_changed_callback: Mutex::new(None),
@ -3266,12 +3273,12 @@ impl<'ctx> AudioUnitStream<'ctx> {
return;
}
let queue = self.context.serial_queue;
let queue = self.queue.clone();
let mutexed_stm = Arc::new(Mutex::new(self));
let also_mutexed_stm = Arc::clone(&mutexed_stm);
// Use a new thread, through the queue, to avoid deadlock when calling
// Get/SetProperties method from inside notify callback
async_dispatch(queue, move || {
queue.run_async(move || {
let mut stm_guard = also_mutexed_stm.lock().unwrap();
let stm_ptr = *stm_guard as *const AudioUnitStream;
if stm_guard.destroy_pending.load(Ordering::SeqCst) {
@ -3327,12 +3334,12 @@ impl<'ctx> AudioUnitStream<'ctx> {
// Execute the stream destroy work.
self.destroy_pending.store(true, Ordering::SeqCst);
let queue = self.context.serial_queue;
let queue = self.queue.clone();
let stream_ptr = self as *const AudioUnitStream;
// Execute close in serial queue to avoid collision
// with reinit when un/plug devices
sync_dispatch(queue, move || {
queue.run_final(move || {
// Call stop_audiounits to avoid potential data race. If there is a running data callback,
// which locks a mutex inside CoreAudio framework, then this call will block the current
// thread until the callback is finished since this call asks to lock a mutex inside
@ -3361,11 +3368,10 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
self.draining.store(false, Ordering::SeqCst);
// Execute start in serial queue to avoid racing with destroy or reinit.
let queue = self.context.serial_queue;
let mut result = Err(Error::error());
let started = &mut result;
let stream = &self;
sync_dispatch(queue, move || {
self.queue.run_sync(move || {
*started = stream.core_stream_data.start_audiounits();
});
@ -3385,9 +3391,8 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
self.shutdown.store(true, Ordering::SeqCst);
// Execute stop in serial queue to avoid racing with destroy or reinit.
let queue = self.context.serial_queue;
let stream = &self;
sync_dispatch(queue, move || {
self.queue.run_sync(move || {
stream.core_stream_data.stop_audiounits();
});

Просмотреть файл

@ -1355,24 +1355,22 @@ fn test_create_cubeb_device_info() {
let mut results = test_create_device_infos_by_device(device);
assert_eq!(results.len(), 2);
// Input device type:
let input_result = results.pop_front().unwrap();
if is_input {
check_device_info_by_device(
results.pop_front().unwrap().unwrap(),
device,
Scope::Input,
);
let mut input_device_info = input_result.unwrap();
check_device_info_by_device(&input_device_info, device, Scope::Input);
destroy_cubeb_device_info(&mut input_device_info);
} else {
assert_eq!(results.pop_front().unwrap().unwrap_err(), Error::error());
assert_eq!(input_result.unwrap_err(), Error::error());
}
// Output device type:
let output_result = results.pop_front().unwrap();
if is_output {
check_device_info_by_device(
results.pop_front().unwrap().unwrap(),
device,
Scope::Output,
);
let mut output_device_info = output_result.unwrap();
check_device_info_by_device(&output_device_info, device, Scope::Output);
destroy_cubeb_device_info(&mut output_device_info);
} else {
assert_eq!(results.pop_front().unwrap().unwrap_err(), Error::error());
assert_eq!(output_result.unwrap_err(), Error::error());
}
} else {
println!("No device for {:?}.", scope);
@ -1390,7 +1388,7 @@ fn test_create_cubeb_device_info() {
results
}
fn check_device_info_by_device(info: ffi::cubeb_device_info, id: AudioObjectID, scope: Scope) {
fn check_device_info_by_device(info: &ffi::cubeb_device_info, id: AudioObjectID, scope: Scope) {
assert!(!info.devid.is_null());
assert!(mem::size_of_val(&info.devid) >= mem::size_of::<AudioObjectID>());
assert_eq!(info.devid as AudioObjectID, id);
@ -1486,7 +1484,7 @@ fn test_is_aggregate_device() {
assert!(!is_aggregate_device(&info));
}
// device_destroy
// destroy_cubeb_device_info
// ------------------------------------
#[test]
fn test_device_destroy() {
@ -1502,7 +1500,7 @@ fn test_device_destroy() {
device.friendly_name = friendly_name.into_raw();
device.vendor_name = vendor_name.into_raw();
audiounit_device_destroy(&mut device);
destroy_cubeb_device_info(&mut device);
assert!(device.device_id.is_null());
assert!(device.group_id.is_null());
@ -1514,24 +1512,9 @@ fn test_device_destroy() {
#[should_panic]
fn test_device_destroy_with_different_device_id_and_group_id() {
let mut device = ffi::cubeb_device_info::default();
let device_id = CString::new("test: device id").unwrap();
let group_id = CString::new("test: group id").unwrap();
let friendly_name = CString::new("test: friendly name").unwrap();
let vendor_name = CString::new("test: vendor name").unwrap();
device.device_id = device_id.into_raw();
device.group_id = group_id.into_raw();
device.friendly_name = friendly_name.into_raw();
device.vendor_name = vendor_name.into_raw();
audiounit_device_destroy(&mut device);
// Hit the assertion above, so we will leak some memory allocated for the above cstring.
assert!(device.device_id.is_null());
assert!(device.group_id.is_null());
assert!(device.friendly_name.is_null());
assert!(device.vendor_name.is_null());
device.device_id = 0xdeaddead as *const _;
device.group_id = 0xdeadbeef as *const _;
destroy_cubeb_device_info(&mut device);
}
#[test]
@ -1543,7 +1526,7 @@ fn test_device_destroy_empty_device() {
assert!(device.friendly_name.is_null());
assert!(device.vendor_name.is_null());
audiounit_device_destroy(&mut device);
destroy_cubeb_device_info(&mut device);
assert!(device.device_id.is_null());
assert!(device.group_id.is_null());

Просмотреть файл

@ -32,18 +32,18 @@ fn test_switch_device() {
}
fn test_switch_device_in_scope(scope: Scope) {
// Do nothing if there is no 2 available devices at least.
let devices = test_get_devices_in_scope(scope.clone());
if devices.len() < 2 {
println!("Need 2 devices for {:?} at least.", scope);
return;
}
println!(
"Switch default device for {:?} while the stream is working.",
scope
);
// Do nothing if there is no 2 available devices at least.
let devices = test_get_devices_in_scope(scope.clone());
if devices.len() < 2 {
println!("Need 2 devices for {:?} at least. Skip.", scope);
return;
}
let mut device_switcher = TestDeviceSwitcher::new(scope.clone());
let count = Arc::new(Mutex::new(0));

2
third_party/rust/nom/.cargo-checksum.json поставляемый

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

101
third_party/rust/nom/.travis.yml поставляемый Normal file
Просмотреть файл

@ -0,0 +1,101 @@
language: rust
# sudo is required to enable kcov to use the personality syscall
sudo: required
dist: trusty
cache: cargo
rust:
- nightly
- beta
- stable
- 1.31.0
env:
matrix:
- FEATURES='--features "regexp regexp_macros"'
before_script:
- eval git pull --rebase https://github.com/Geal/nom master
- eval git log --pretty=oneline HEAD~5..HEAD
matrix:
include:
- rust: nightly
env: FEATURES='--no-default-features'
- rust: nightly
env: FEATURES='--no-default-features --features "alloc"'
- rust: stable
env: FEATURES=''
- rust: nightly
env: DOC_FEATURES='--features "std lexical regexp regexp_macros" --no-default-features'
before_script:
- export PATH=$HOME/.cargo/bin:$PATH
script:
- eval cargo doc --verbose $DOC_FEATURES
- rust: nightly
env: FEATURES=''
before_script:
- export PATH=$HOME/.cargo/bin:$PATH
- cargo install cargo-update || echo "cargo-update already installed"
- cargo install cargo-travis || echo "cargo-travis already installed"
- cargo install-update -a
- mkdir -p target/kcov-master
script:
cargo coveralls --verbose --all-features
allow_failures:
- rust: stable
env: FEATURES=''
before_script:
- export PATH=$HOME/.cargo/bin:$PATH
- rustup component add rustfmt-preview
script:
- eval cargo fmt -- --write-mode=diff
notifications:
webhooks:
urls:
- https://webhooks.gitter.im/e/9c035a194ac4fd4cc061
on_success: change
on_failure: always
on_start: false
addons:
apt:
packages:
- libcurl4-openssl-dev
- libelf-dev
- libdw-dev
- binutils-dev
- cmake
sources:
- kalakris-cmake
cache:
directories:
- /home/travis/.cargo
before_cache:
- rm -rf /home/travis/.cargo/registry
script:
- eval cargo build --verbose $FEATURES
- eval cargo test --verbose $FEATURES
after_success: |
case "$TRAVIS_RUST_VERSION" in
nightly)
if [ "${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}" != "master" ]; then
git fetch &&
git checkout master &&
cargo bench --verbose
fi
if [ "$FEATURES" == '--features "regexp regexp_macros"' ]; then
cargo bench --verbose
fi
;;
*)
;;
esac

Просмотреть файл

@ -19,7 +19,7 @@ static_prefs = { path = "../../../../modules/libpref/init/static_prefs" }
profiler_helper = { path = "../../../../tools/profiler/rust-helper", optional = true }
mozurl = { path = "../../../../netwerk/base/mozurl" }
webrender_bindings = { path = "../../../../gfx/webrender_bindings", optional = true }
cubeb-coreaudio = { git = "https://github.com/ChunMinChang/cubeb-coreaudio-rs", rev = "4acd80233efa645ac79769f37b07d495c1b42070", optional = true }
cubeb-coreaudio = { git = "https://github.com/ChunMinChang/cubeb-coreaudio-rs", rev = "799518a033a0c780cfdb82a4eaabfd9681cb7f3b", optional = true }
cubeb-pulse = { git = "https://github.com/djg/cubeb-pulse-rs", rev="8069f8f4189982e0b38fa6dc8993dd4fab41f728", optional = true, features=["pulse-dlopen"] }
cubeb-sys = { version = "0.6", optional = true, features=["gecko-in-tree"] }
encoding_glue = { path = "../../../../intl/encoding_glue" }