diff options
-rw-r--r-- | include/qemu/main-loop.h | 8 | ||||
-rw-r--r-- | rust/qemu-api/meson.build | 2 | ||||
-rw-r--r-- | rust/qemu-api/src/cell.rs | 26 | ||||
-rw-r--r-- | stubs/iothread-lock.c | 8 | ||||
-rw-r--r-- | system/cpus.c | 6 |
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. |