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>
This commit is contained in:
Stefan Hajnoczi 2021-04-14 21:02:46 +01:00
parent 711c0418c8
commit 0f08586c71
5 changed files with 43 additions and 11 deletions

View File

@ -292,19 +292,44 @@ void aio_context_acquire(AioContext *ctx);
void aio_context_release(AioContext *ctx); void aio_context_release(AioContext *ctx);
/** /**
* aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run * aio_bh_schedule_oneshot_full: Allocate a new bottom half structure that will
* only once and as soon as possible. * run only once and as soon as possible.
*
* @name: A human-readable identifier for debugging purposes.
*/ */
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);
/** /**
* aio_bh_new: Allocate a new bottom half structure. * aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run
* only once and as soon as possible.
*
* A convenience wrapper for aio_bh_schedule_oneshot_full() that uses cb as the
* name string.
*/
#define aio_bh_schedule_oneshot(ctx, cb, opaque) \
aio_bh_schedule_oneshot_full((ctx), (cb), (opaque), (stringify(cb)))
/**
* 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(AioContext *ctx, QEMUBHFunc *cb, void *opaque); 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.
*/
#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.

View File

@ -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 {

View File

@ -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);

View File

@ -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;
} }

View File

@ -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);
} }
/* /*