Skip to content

Commit 2e68088

Browse files
committed
add tests for QueueSync
For tests that do not use iter(), we can simply replace direct access to the QueueState with lock() in order to retrieve the guard. However, "q.lock().a = q.lock().b" is illegal, because it has two mutable borrows at the same time. For tests that use iter(), the result of q.lock() must survive until the test is done with the iterator. Suggested-by: Laura Loghin <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 1116b24 commit 2e68088

File tree

1 file changed

+97
-15
lines changed

1 file changed

+97
-15
lines changed

crates/virtio-queue/src/lib.rs

Lines changed: 97 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,12 +1211,10 @@ mod tests {
12111211
}
12121212
}
12131213

1214-
#[test]
1215-
fn test_queue_and_iterator() {
1216-
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1214+
fn do_test_queue_and_iterator<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
12171215
let vq = MockSplitQueue::new(m, 16);
12181216

1219-
let mut q: Queue<_> = vq.as_queue(m);
1217+
let mut q: Q = vq.as_queue(m);
12201218

12211219
// q is currently valid
12221220
assert!(q.is_valid());
@@ -1326,11 +1324,21 @@ mod tests {
13261324
}
13271325

13281326
#[test]
1329-
fn test_descriptor_and_iterator() {
1327+
fn test_queue_and_iterator() {
1328+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1329+
do_test_queue_and_iterator::<Queue<&AddrSpace>>(m);
1330+
}
1331+
1332+
#[test]
1333+
fn test_queue_and_iterator_sync() {
13301334
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1335+
do_test_queue_and_iterator::<QueueSync<&AddrSpace>>(m);
1336+
}
1337+
1338+
fn do_test_descriptor_and_iterator<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
13311339
let vq = MockSplitQueue::new(m, 16);
13321340

1333-
let mut q: Queue<_> = vq.as_queue(m);
1341+
let mut q: Q = vq.as_queue(m);
13341342

13351343
// q is currently valid
13361344
assert!(q.is_valid());
@@ -1390,11 +1398,21 @@ mod tests {
13901398
}
13911399

13921400
#[test]
1393-
fn test_add_used() {
1401+
fn test_descriptor_and_iterator() {
1402+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1403+
do_test_descriptor_and_iterator::<Queue<&AddrSpace>>(m);
1404+
}
1405+
1406+
#[test]
1407+
fn test_descriptor_and_iterator_sync() {
13941408
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1409+
do_test_descriptor_and_iterator::<QueueSync<&AddrSpace>>(m);
1410+
}
1411+
1412+
fn do_test_add_used<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
13951413
let vq = MockSplitQueue::new(m, 16);
13961414

1397-
let mut q: Queue<_> = vq.as_queue(m);
1415+
let mut q: Q = vq.as_queue(m);
13981416

13991417
assert_eq!(vq.used().idx().load(), 0);
14001418

@@ -1412,6 +1430,18 @@ mod tests {
14121430
assert_eq!(x.len, 0x1000);
14131431
}
14141432

1433+
#[test]
1434+
fn test_add_used() {
1435+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1436+
do_test_add_used::<Queue<&AddrSpace>>(m);
1437+
}
1438+
1439+
#[test]
1440+
fn test_add_used_sync() {
1441+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1442+
do_test_add_used::<QueueSync<&AddrSpace>>(m);
1443+
}
1444+
14151445
#[test]
14161446
fn test_queue_guard() {
14171447
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
@@ -1427,11 +1457,31 @@ mod tests {
14271457
}
14281458

14291459
#[test]
1430-
fn test_reset_queue() {
1431-
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1460+
fn test_queue_guard_sync() {
1461+
let m = &GuestMemoryMmap::<()>::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
14321462
let vq = MockSplitQueue::new(m, 16);
14331463

1434-
let mut q: Queue<_> = vq.as_queue(m);
1464+
// Note how the test_queue_guard above has "let mut" here. A singlethreaded
1465+
// queue can only be accessed by one thread, and that one needs to have an
1466+
// exclusive reference; a multithreaded queue can be accessed by many thread
1467+
// and therefore it has to support interior mutability (via Mutex). On the
1468+
// other hand, a multithreaded queue is reference counted and therefore it
1469+
// cannot be accessed via an exclusive reference *at all*. This is the
1470+
// the reason why only Queue has the acquire() method, and only QueueSync
1471+
// has a lock() method.
1472+
let q: QueueSync<_> = vq.as_queue(m);
1473+
let mut qstate = q.lock();
1474+
qstate.ready = true;
1475+
qstate.reset();
1476+
assert_eq!(qstate.ready, false);
1477+
let mut iter = qstate.iter().unwrap();
1478+
assert!(iter.next().is_none());
1479+
}
1480+
1481+
fn do_test_reset_queue<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
1482+
let vq = MockSplitQueue::new(m, 16);
1483+
1484+
let mut q: Q = vq.as_queue(m);
14351485
q.with(|mut qstate| {
14361486
qstate.size = 8;
14371487
qstate.ready = true;
@@ -1442,12 +1492,22 @@ mod tests {
14421492
}
14431493

14441494
#[test]
1445-
fn test_needs_notification() {
1495+
fn test_reset_queue() {
1496+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1497+
do_test_reset_queue::<Queue<&AddrSpace>>(m);
1498+
}
1499+
1500+
#[test]
1501+
fn test_reset_queue_sync() {
14461502
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1503+
do_test_reset_queue::<QueueSync<&AddrSpace>>(m);
1504+
}
1505+
1506+
fn do_test_needs_notification<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
14471507
let qsize = 16;
14481508
let vq = MockSplitQueue::new(m, qsize);
14491509

1450-
let mut q: Queue<_> = vq.as_queue(m);
1510+
let mut q: Q = vq.as_queue(m);
14511511
let avail_addr = vq.avail_addr();
14521512

14531513
// It should always return true when EVENT_IDX isn't enabled.
@@ -1491,11 +1551,21 @@ mod tests {
14911551
}
14921552

14931553
#[test]
1494-
fn test_enable_disable_notification() {
1554+
fn test_needs_notification() {
1555+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1556+
do_test_needs_notification::<Queue<&AddrSpace>>(m);
1557+
}
1558+
1559+
#[test]
1560+
fn test_needs_notification_sync() {
14951561
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1562+
do_test_needs_notification::<QueueSync<&AddrSpace>>(m);
1563+
}
1564+
1565+
fn do_test_enable_disable_notification<'a, Q: QueueT<&'a AddrSpace>>(m: &'a AddrSpace) {
14961566
let vq = MockSplitQueue::new(m, 16);
14971567

1498-
let mut q: Queue<_> = vq.as_queue(m);
1568+
let mut q: Q = vq.as_queue(m);
14991569
let used_addr = vq.used_addr();
15001570

15011571
q.with(|qstate| assert_eq!(qstate.event_idx_enabled, false));
@@ -1526,4 +1596,16 @@ mod tests {
15261596
q.with(|mut qstate| qstate.next_avail = Wrapping(8));
15271597
assert_eq!(q.enable_notification().unwrap(), false);
15281598
}
1599+
1600+
#[test]
1601+
fn test_enable_disable_notification() {
1602+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1603+
do_test_enable_disable_notification::<Queue<&AddrSpace>>(m);
1604+
}
1605+
1606+
#[test]
1607+
fn test_enable_disable_notification_sync() {
1608+
let m = &AddrSpace::from_ranges(&[(GuestAddress(0), 0x10000)]).unwrap();
1609+
do_test_enable_disable_notification::<QueueSync<&AddrSpace>>(m);
1610+
}
15291611
}

0 commit comments

Comments
 (0)