aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/qemu/main-loop.h8
-rw-r--r--rust/qemu-api/meson.build2
-rw-r--r--rust/qemu-api/src/cell.rs26
-rw-r--r--stubs/iothread-lock.c8
-rw-r--r--system/cpus.c6
5 files changed, 45 insertions, 5 deletions
diff --git a/include/qemu/main-loop.h b/include/qemu/main-loop.h
index 646306c..3935a57 100644
--- a/include/qemu/main-loop.h
+++ b/include/qemu/main-loop.h
@@ -248,6 +248,14 @@ GSource *iohandler_get_g_source(void);
AioContext *iohandler_get_aio_context(void);
/**
+ * rust_bql_mock_lock:
+ *
+ * Called from Rust doctests to make bql_lock() return true.
+ * Do not touch.
+ */
+void rust_bql_mock_lock(void);
+
+/**
* bql_locked: Return lock status of the Big QEMU Lock (BQL)
*
* The Big QEMU Lock (BQL) is the coarsest lock in QEMU, and as such it
diff --git a/rust/qemu-api/meson.build b/rust/qemu-api/meson.build
index 7ff408a..50ec00e 100644
--- a/rust/qemu-api/meson.build
+++ b/rust/qemu-api/meson.build
@@ -60,7 +60,7 @@ test('rust-qemu-api-integration',
dependencies: [qemu_api, qemu_api_macros],
link_whole: [rust_qemu_api_objs, libqemuutil]),
args: [
- '--test',
+ '--test', '--test-threads', '1',
'--format', 'pretty',
],
protocol: 'rust',
diff --git a/rust/qemu-api/src/cell.rs b/rust/qemu-api/src/cell.rs
index 28349de..eae4e2c 100644
--- a/rust/qemu-api/src/cell.rs
+++ b/rust/qemu-api/src/cell.rs
@@ -124,9 +124,18 @@ use std::{
use crate::bindings;
-// TODO: When building doctests do not include the actual BQL, because cargo
-// does not know how to link them to libqemuutil. This can be fixed by
-// running rustdoc from "meson test" instead of relying on cargo.
+/// An internal function that is used by doctests.
+pub fn bql_start_test() {
+ if cfg!(MESON) {
+ // SAFETY: integration tests are run with --test-threads=1, while
+ // unit tests and doctests are not multithreaded and do not have
+ // any BQL-protected data. Just set bql_locked to true.
+ unsafe {
+ bindings::rust_bql_mock_lock();
+ }
+ }
+}
+
pub fn bql_locked() -> bool {
// SAFETY: the function does nothing but return a thread-local bool
!cfg!(MESON) || unsafe { bindings::bql_locked() }
@@ -220,6 +229,7 @@ impl<T> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
/// ```
@@ -236,6 +246,7 @@ impl<T> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
///
@@ -253,6 +264,7 @@ impl<T> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let cell = BqlCell::new(5);
/// assert_eq!(cell.get(), 5);
@@ -274,6 +286,7 @@ impl<T> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
/// let five = c.into_inner();
@@ -293,6 +306,7 @@ impl<T: Copy> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
///
@@ -315,6 +329,7 @@ impl<T> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
///
@@ -333,6 +348,7 @@ impl<T: Default> BqlCell<T> {
///
/// ```
/// use qemu_api::cell::BqlCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlCell::new(5);
/// let five = c.take();
@@ -461,6 +477,7 @@ impl<T> BqlRefCell<T> {
///
/// ```
/// use qemu_api::cell::BqlRefCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlRefCell::new(5);
///
@@ -472,6 +489,7 @@ impl<T> BqlRefCell<T> {
///
/// ```should_panic
/// use qemu_api::cell::BqlRefCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlRefCell::new(5);
///
@@ -513,6 +531,7 @@ impl<T> BqlRefCell<T> {
///
/// ```
/// use qemu_api::cell::BqlRefCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlRefCell::new("hello".to_owned());
///
@@ -525,6 +544,7 @@ impl<T> BqlRefCell<T> {
///
/// ```should_panic
/// use qemu_api::cell::BqlRefCell;
+ /// # qemu_api::cell::bql_start_test();
///
/// let c = BqlRefCell::new(5);
/// let m = c.borrow();
diff --git a/stubs/iothread-lock.c b/stubs/iothread-lock.c
index 5467659..6050c08 100644
--- a/stubs/iothread-lock.c
+++ b/stubs/iothread-lock.c
@@ -1,11 +1,17 @@
#include "qemu/osdep.h"
#include "qemu/main-loop.h"
+static bool bql_is_locked = false;
static uint32_t bql_unlock_blocked;
bool bql_locked(void)
{
- return false;
+ return bql_is_locked;
+}
+
+void rust_bql_mock_lock(void)
+{
+ bql_is_locked = true;
}
void bql_lock_impl(const char *file, int line)
diff --git a/system/cpus.c b/system/cpus.c
index ba633c7..4b43ceb 100644
--- a/system/cpus.c
+++ b/system/cpus.c
@@ -538,6 +538,12 @@ bool qemu_in_main_thread(void)
return bql_locked();
}
+void rust_bql_mock_lock(void)
+{
+ error_report("This function should be used only from tests");
+ abort();
+}
+
/*
* The BQL is taken from so many places that it is worth profiling the
* callers directly, instead of funneling them all through a single function.