Skip to content

Commit 4197c30

Browse files
committed
CI: Move native-dispatcher tests to Linux
1 parent b620bb4 commit 4197c30

File tree

3 files changed

+67
-39
lines changed

3 files changed

+67
-39
lines changed

.circleci/config.yml

+29-6
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,34 @@ commands:
8383
glean_parser coverage --allow-reserved -c glean_coverage.txt -f codecovio -o codecov.json glean-core/metrics.yaml
8484
bin/codecov.sh -X yaml -f codecov.json
8585
86+
test-rust-native-dispatcher:
87+
steps:
88+
- run:
89+
name: Install required dependencies
90+
command: |
91+
sudo apt update
92+
sudo apt install -y cmake ninja-build clang
93+
- run:
94+
name: Install libdispatch
95+
command: |
96+
cd ~
97+
git clone https://github.com/apple/swift-corelibs-libdispatch
98+
cd swift-corelibs-libdispatch
99+
mkdir build && cd build
100+
cmake -G Ninja \
101+
-DCMAKE_C_COMPILER=clang \
102+
-DCMAKE_CXX_COMPILER=clang++ \
103+
-DCMAKE_BUILD_WITH_INSTALL_RPATH=On \
104+
..
105+
ninja
106+
sudo ninja install
107+
108+
- run:
109+
name: Run Rust tests with native dispatcher
110+
command: |
111+
export LD_LIBRARY_PATH=/usr/local/lib
112+
cargo test --verbose --jobs 6 --features native-dispatcher -- --nocapture
113+
86114
install-rustup:
87115
steps:
88116
- run:
@@ -324,6 +352,7 @@ jobs:
324352
resource_class: "medium+"
325353
steps:
326354
- test-rust
355+
- test-rust-native-dispatcher
327356

328357
Rust tests - beta:
329358
docker:
@@ -529,12 +558,6 @@ jobs:
529558
keys:
530559
- v2-cargo-cache-{{arch}}-{{checksum "buildtype.txt"}}-{{checksum "Cargo.lock"}}
531560

532-
# Experimental - we might move this to Linux with an appropriate libdispatch later
533-
- run:
534-
name: Run Rust tests with native dispatcher
535-
command: |
536-
cargo test --verbose --jobs 6 --features native-dispatcher -- --nocapture
537-
538561
- run:
539562
name: Run iOS build
540563
command: bash bin/run-ios-build.sh

glean-core/src/dispatcher/mod.rs

-3
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ mod test {
120120
fn launch_correctly_adds_tasks_to_preinit_queue() {
121121
enable_test_logging();
122122

123-
let main_thread_id = thread::current().id();
124123
let thread_canary = Arc::new(AtomicU8::new(0));
125124

126125
let dispatcher = Dispatcher::new(100);
@@ -132,8 +131,6 @@ mod test {
132131
dispatcher
133132
.guard()
134133
.launch(move || {
135-
// Make sure the task is flushed off-the-main thread.
136-
assert!(thread::current().id() != main_thread_id);
137134
canary_clone.fetch_add(1, Ordering::SeqCst);
138135
})
139136
.expect("Failed to dispatch the test task");

glean-core/src/dispatcher/native.rs

+38-30
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
use std::sync::atomic::{AtomicU8, Ordering};
5+
use std::sync::atomic::{AtomicU8, AtomicUsize, Ordering};
66
use std::sync::Arc;
77
use std::sync::Mutex;
88

@@ -38,12 +38,13 @@ impl Dispatcher {
3838
pub fn new(max_queue_size: usize) -> Self {
3939
let queue = Queue::create("glean.dispatcher", QueueAttribute::Serial);
4040
let preinit_queue = Mutex::new(Vec::with_capacity(10));
41+
let overflow_count = Arc::new(AtomicUsize::new(0));
4142

4243
let guard = DispatchGuard {
4344
queue: Some(queue),
44-
4545
flushed: AtomicU8::new(QueueStatus::NotFlushed as u8),
4646
max_queue_size,
47+
overflow_count,
4748
preinit_queue,
4849
};
4950

@@ -60,15 +61,11 @@ impl Dispatcher {
6061
///
6162
/// You need to call `shutdown` to initiate a shutdown of the queue.
6263
pub fn join(&mut self) -> Result<(), DispatchError> {
63-
self.guard.shutdown().ok();
64-
if let Some(queue) = self.guard.queue.as_ref() {
65-
queue.exec_sync(|| {
66-
// intentionally left empty
67-
});
68-
}
69-
7064
if let Some(guard) = Arc::get_mut(&mut self.guard) {
7165
if let Some(queue) = guard.queue.take() {
66+
queue.exec_sync(|| {
67+
// intentionally left empty
68+
});
7269
drop(queue);
7370
}
7471
}
@@ -78,9 +75,21 @@ impl Dispatcher {
7875

7976
/// A clonable guard for a dispatch queue.
8077
pub struct DispatchGuard {
78+
/// The queue to run on
8179
queue: Option<Queue>,
80+
81+
/// Status of the queue. One of `QueueStatus`
8282
flushed: AtomicU8,
83+
84+
/// The maximum pre-init queue size
8385
max_queue_size: usize,
86+
87+
/// The number of items that were added to the queue after it filled up
88+
overflow_count: Arc<AtomicUsize>,
89+
90+
/// The pre-init queue
91+
///
92+
/// Collects tasks before `flush_init` is called up until `max_queue_size`.
8493
preinit_queue: Mutex<Vec<Box<dyn FnOnce() + Send + 'static>>>,
8594
}
8695

@@ -95,12 +104,20 @@ impl DispatchGuard {
95104
pub fn launch(&self, task: impl FnOnce() + Send + 'static) -> Result<(), DispatchError> {
96105
if self.flushed.load(Ordering::SeqCst) == QueueStatus::IsFlushed as u8 {
97106
self.queue().exec_async(task);
107+
Ok(())
98108
} else {
99109
let mut queue = self.preinit_queue.lock().unwrap();
100-
queue.push(Box::new(task))
110+
if queue.len() < self.max_queue_size {
111+
queue.push(Box::new(task));
112+
Ok(())
113+
} else {
114+
self.overflow_count.fetch_add(1, Ordering::SeqCst);
115+
// Instead of using a bounded queue, we are handling the bounds
116+
// checking ourselves. If a bounded queue were full, we would return
117+
// a QueueFull DispatchError, so we do the same here.
118+
Err(DispatchError::QueueFull)
119+
}
101120
}
102-
103-
Ok(())
104121
}
105122

106123
/// Shut down the dispatch queue.
@@ -147,32 +164,23 @@ impl DispatchGuard {
147164
return Err(DispatchError::AlreadyFlushed);
148165
}
149166

150-
let over;
151-
let queue_size;
152167
{
153168
let mut queue = self.preinit_queue.lock().unwrap();
154-
queue_size = queue.len();
155-
over = queue_size.saturating_sub(self.max_queue_size);
156-
let end = std::cmp::min(queue_size, self.max_queue_size);
157-
158-
for task in queue.drain(..end) {
169+
for task in queue.drain(..) {
159170
self.queue().exec_sync(task);
160171
}
161172
}
162-
// give others a chance to get the lock
163-
{
164-
let mut queue = self.preinit_queue.lock().unwrap();
165-
if queue.len() > over {
166-
let start = queue.len() - over;
167-
for task in queue.drain(start..) {
168-
self.queue().exec_sync(task);
169-
}
170-
}
171-
}
173+
174+
let overflow_count = self.overflow_count.load(Ordering::SeqCst);
172175

173176
self.flushed
174177
.store(QueueStatus::IsFlushed as u8, Ordering::SeqCst);
175-
Ok(over)
178+
179+
if overflow_count > 0 {
180+
Ok(overflow_count)
181+
} else {
182+
Ok(0)
183+
}
176184
}
177185

178186
pub fn kill(&self) -> Result<(), DispatchError> {

0 commit comments

Comments
 (0)