]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
bql: add a "mock" BQL for Rust unit tests
authorPaolo Bonzini <pbonzini@redhat.com>
Fri, 15 Nov 2024 11:08:43 +0000 (12:08 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 19 Dec 2024 18:36:37 +0000 (19:36 +0100)
Right now, the stub BQL in stubs/iothread-lock.c always reports itself as
unlocked.  However, Rust would like to run its tests in an environment where
the BQL *is* locked.  Provide an extremely dirty function that flips the
return value of bql_is_locked() to true.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
include/qemu/main-loop.h
rust/qemu-api/meson.build
rust/qemu-api/src/cell.rs
stubs/iothread-lock.c
system/cpus.c

index 646306c272f7a883fa902794ce4ae59eb5875d7d..3935a573391eed4f8efb4c157f5ddb20722eb0ab 100644 (file)
@@ -247,6 +247,14 @@ void event_notifier_set_handler(EventNotifier *e,
 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)
  *
index 7ff408ad68eb73a722fcccf4daec92f7b295e0ee..50ec00e128dde387ba4aafe12f339f0a4cc25f07 100644 (file)
@@ -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',
index 28349de291a059144cc7767fdb23408643813163..eae4e2ce786b20736cb4a967d3cf2273f941f475 100644 (file)
@@ -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();
index 54676598950f6c7a8d8bbfb2588eeae57e9fb5e2..6050c081f533dd6ea2de81c46ef05a7e4e3f696c 100644 (file)
@@ -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)
index ba633c7688b2bb3d10dae57fd0f3f165b7abd086..4b43ceb5435d14383dfca1f9111ab338866c2487 100644 (file)
@@ -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.