Forráskód Böngészése

util/async: add a human-readable name to BHs for debugging

It can be difficult to debug issues with BHs in production environments.
Although BHs can usually be identified by looking up their ->cb()
function pointer, this requires debug information for the program. It is
also not possible to print human-readable diagnostics about BHs because
they have no identifier.

This patch adds a name to each BH. The name is not unique per instance
but differentiates between cb() functions, which is usually enough. It's
done by changing aio_bh_new() and friends to macros that stringify cb.

The next patch will use the name field when reporting leaked BHs.

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20210414200247.917496-2-stefanha@redhat.com>
Stefan Hajnoczi 4 éve
szülő
commit
0f08586c71

+ 28 - 3
include/block/aio.h

@@ -291,20 +291,45 @@ void aio_context_acquire(AioContext *ctx);
 /* Relinquish ownership of the AioContext. */
 /* Relinquish ownership of the AioContext. */
 void aio_context_release(AioContext *ctx);
 void aio_context_release(AioContext *ctx);
 
 
+/**
+ * aio_bh_schedule_oneshot_full: Allocate a new bottom half structure that will
+ * run only once and as soon as possible.
+ *
+ * @name: A human-readable identifier for debugging purposes.
+ */
+void aio_bh_schedule_oneshot_full(AioContext *ctx, QEMUBHFunc *cb, void *opaque,
+                                  const char *name);
+
 /**
 /**
  * aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run
  * aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run
  * only once and as soon as possible.
  * only once and as soon as possible.
+ *
+ * A convenience wrapper for aio_bh_schedule_oneshot_full() that uses cb as the
+ * name string.
  */
  */
-void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
+#define aio_bh_schedule_oneshot(ctx, cb, opaque) \
+    aio_bh_schedule_oneshot_full((ctx), (cb), (opaque), (stringify(cb)))
 
 
 /**
 /**
- * aio_bh_new: Allocate a new bottom half structure.
+ * aio_bh_new_full: Allocate a new bottom half structure.
  *
  *
  * Bottom halves are lightweight callbacks whose invocation is guaranteed
  * Bottom halves are lightweight callbacks whose invocation is guaranteed
  * to be wait-free, thread-safe and signal-safe.  The #QEMUBH structure
  * to be wait-free, thread-safe and signal-safe.  The #QEMUBH structure
  * is opaque and must be allocated prior to its use.
  * is opaque and must be allocated prior to its use.
+ *
+ * @name: A human-readable identifier for debugging purposes.
+ */
+QEMUBH *aio_bh_new_full(AioContext *ctx, QEMUBHFunc *cb, void *opaque,
+                        const char *name);
+
+/**
+ * aio_bh_new: Allocate a new bottom half structure
+ *
+ * A convenience wrapper for aio_bh_new_full() that uses the cb as the name
+ * string.
  */
  */
-QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
+#define aio_bh_new(ctx, cb, opaque) \
+    aio_bh_new_full((ctx), (cb), (opaque), (stringify(cb)))
 
 
 /**
 /**
  * aio_notify: Force processing of pending events.
  * aio_notify: Force processing of pending events.

+ 3 - 1
include/qemu/main-loop.h

@@ -294,7 +294,9 @@ void qemu_cond_timedwait_iothread(QemuCond *cond, int ms);
 
 
 void qemu_fd_register(int fd);
 void qemu_fd_register(int fd);
 
 
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
+#define qemu_bh_new(cb, opaque) \
+    qemu_bh_new_full((cb), (opaque), (stringify(cb)))
+QEMUBH *qemu_bh_new_full(QEMUBHFunc *cb, void *opaque, const char *name);
 void qemu_bh_schedule_idle(QEMUBH *bh);
 void qemu_bh_schedule_idle(QEMUBH *bh);
 
 
 enum {
 enum {

+ 1 - 1
tests/unit/ptimer-test-stubs.c

@@ -108,7 +108,7 @@ int64_t qemu_clock_deadline_ns_all(QEMUClockType type, int attr_mask)
     return deadline;
     return deadline;
 }
 }
 
 
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+QEMUBH *qemu_bh_new_full(QEMUBHFunc *cb, void *opaque, const char *name)
 {
 {
     QEMUBH *bh = g_new(QEMUBH, 1);
     QEMUBH *bh = g_new(QEMUBH, 1);
 
 

+ 7 - 2
util/async.c

@@ -57,6 +57,7 @@ enum {
 
 
 struct QEMUBH {
 struct QEMUBH {
     AioContext *ctx;
     AioContext *ctx;
+    const char *name;
     QEMUBHFunc *cb;
     QEMUBHFunc *cb;
     void *opaque;
     void *opaque;
     QSLIST_ENTRY(QEMUBH) next;
     QSLIST_ENTRY(QEMUBH) next;
@@ -107,7 +108,8 @@ static QEMUBH *aio_bh_dequeue(BHList *head, unsigned *flags)
     return bh;
     return bh;
 }
 }
 
 
-void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
+void aio_bh_schedule_oneshot_full(AioContext *ctx, QEMUBHFunc *cb,
+                                  void *opaque, const char *name)
 {
 {
     QEMUBH *bh;
     QEMUBH *bh;
     bh = g_new(QEMUBH, 1);
     bh = g_new(QEMUBH, 1);
@@ -115,11 +117,13 @@ void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
         .ctx = ctx,
         .ctx = ctx,
         .cb = cb,
         .cb = cb,
         .opaque = opaque,
         .opaque = opaque,
+        .name = name,
     };
     };
     aio_bh_enqueue(bh, BH_SCHEDULED | BH_ONESHOT);
     aio_bh_enqueue(bh, BH_SCHEDULED | BH_ONESHOT);
 }
 }
 
 
-QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
+QEMUBH *aio_bh_new_full(AioContext *ctx, QEMUBHFunc *cb, void *opaque,
+                        const char *name)
 {
 {
     QEMUBH *bh;
     QEMUBH *bh;
     bh = g_new(QEMUBH, 1);
     bh = g_new(QEMUBH, 1);
@@ -127,6 +131,7 @@ QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
         .ctx = ctx,
         .ctx = ctx,
         .cb = cb,
         .cb = cb,
         .opaque = opaque,
         .opaque = opaque,
+        .name = name,
     };
     };
     return bh;
     return bh;
 }
 }

+ 2 - 2
util/main-loop.c

@@ -544,9 +544,9 @@ void main_loop_wait(int nonblocking)
 
 
 /* Functions to operate on the main QEMU AioContext.  */
 /* Functions to operate on the main QEMU AioContext.  */
 
 
-QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+QEMUBH *qemu_bh_new_full(QEMUBHFunc *cb, void *opaque, const char *name)
 {
 {
-    return aio_bh_new(qemu_aio_context, cb, opaque);
+    return aio_bh_new_full(qemu_aio_context, cb, opaque, name);
 }
 }
 
 
 /*
 /*