@@ -111,9 +111,12 @@ void qemu_chr_be_event(CharDriverState *s, int event)
/* Keep track if the char device is open */
switch (event) {
case CHR_EVENT_OPENED:
+ /*
+ * See the comment in qemu_chr_generic_open_bh() for why
+ * 's->opened = 1' is not here.
+ */
if (s->recon_timer)
qemu_del_timer(s->recon_timer);
- s->opened = 1;
break;
case CHR_EVENT_CLOSED:
if (s->recon_timer)
@@ -132,13 +135,23 @@ void qemu_chr_be_event(CharDriverState *s, int event)
static void qemu_chr_generic_open_bh(void *opaque)
{
CharDriverState *s = opaque;
- qemu_chr_be_event(s, CHR_EVENT_OPENED);
+ /*
+ * Since the "close" event doesn't go through a bh, there is a
+ * possible race condition if a close comes in after an open, but
+ * the open is in the bh queue. So we double-check here, and we
+ * set opened in qemu_chr_generic_open() instead of
+ * qemu_chr_be_event().
+ */
+ if (s->opened)
+ qemu_chr_be_event(s, CHR_EVENT_OPENED);
qemu_bh_delete(s->bh);
s->bh = NULL;
}
void qemu_chr_generic_open(CharDriverState *s)
{
+ /* See the comment in qemu_chr_generic_open_bh() for why this is here */
+ s->opened = 1;
if (s->bh == NULL) {
s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
qemu_bh_schedule(s->bh);
@@ -93,8 +93,10 @@ static void vmc_state(SpiceCharDeviceInstance *sin, int connected)
return;
}
- qemu_chr_be_event(scd->chr,
- connected ? CHR_EVENT_OPENED : CHR_EVENT_CLOSED);
+ if (connected)
+ qemu_chr_generic_open(scd->chr);
+ else
+ qemu_chr_be_event(scd->chr, CHR_EVENT_CLOSED);
}
static SpiceCharDeviceInterface vmc_interface = {