@@ -98,10 +98,13 @@ 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->be_open = 1;
break;
case CHR_EVENT_CLOSED:
if (s->recon_timer) {
@@ -126,13 +129,24 @@ void qemu_chr_be_event(CharDriverState *s, int event)
static gboolean qemu_chr_be_generic_open_bh(gpointer 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->be_open) {
+ qemu_chr_be_event(s, CHR_EVENT_OPENED);
+ }
s->idle_tag = 0;
return FALSE;
}
void qemu_chr_be_generic_open(CharDriverState *s)
{
+ /* See the comment in qemu_chr_generic_open_bh() for why this is here */
+ s->be_open = 1;
if (s->idle_tag == 0) {
s->idle_tag = g_idle_add(qemu_chr_be_generic_open_bh, s);
}
@@ -97,8 +97,11 @@ 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 = {