QmpCommandList qmp_commands, qmp_cap_negotiation_commands;
-Monitor *cur_mon;
+__thread Monitor *cur_mon;
static void monitor_command_cb(void *opaque, const char *cmdline,
void *readline_opaque);
* applying any rate limiting if required.
*/
static void
-monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
+monitor_qapi_event_queue_no_reenter(QAPIEvent event, QDict *qdict)
{
MonitorQAPIEventConf *evconf;
MonitorQAPIEventState *evstate;
qemu_mutex_unlock(&monitor_lock);
}
+static void
+monitor_qapi_event_queue(QAPIEvent event, QDict *qdict, Error **errp)
+{
+ /*
+ * monitor_qapi_event_queue_no_reenter() is not reentrant: it
+ * would deadlock on monitor_lock. Work around by queueing
+ * events in thread-local storage.
+ * TODO: remove this, make it re-enter safe.
+ */
+ typedef struct MonitorQapiEvent {
+ QAPIEvent event;
+ QDict *qdict;
+ QSIMPLEQ_ENTRY(MonitorQapiEvent) entry;
+ } MonitorQapiEvent;
+ static __thread QSIMPLEQ_HEAD(, MonitorQapiEvent) event_queue;
+ static __thread bool reentered;
+ MonitorQapiEvent *ev;
+
+ if (!reentered) {
+ QSIMPLEQ_INIT(&event_queue);
+ }
+
+ ev = g_new(MonitorQapiEvent, 1);
+ ev->qdict = qobject_ref(qdict);
+ ev->event = event;
+ QSIMPLEQ_INSERT_TAIL(&event_queue, ev, entry);
+ if (reentered) {
+ return;
+ }
+
+ reentered = true;
+
+ while ((ev = QSIMPLEQ_FIRST(&event_queue)) != NULL) {
+ QSIMPLEQ_REMOVE_HEAD(&event_queue, entry);
+ monitor_qapi_event_queue_no_reenter(ev->event, ev->qdict);
+ qobject_unref(ev->qdict);
+ g_free(ev);
+ }
+
+ reentered = false;
+}
+
/*
* This function runs evconf->rate ns after sending a throttled
* event.
} else {
assert(req_obj->err);
rsp = qmp_error_response(req_obj->err);
+ req_obj->err = NULL;
monitor_qmp_respond(req_obj->mon, rsp, NULL);
qobject_unref(rsp);
}
qdict_del(qdict, "id");
} /* else will fail qmp_dispatch() */
- if (trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
+ if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) {
QString *req_json = qobject_to_json(req);
trace_handle_qmp_command(mon, qstring_get_str(req_json));
qobject_unref(req_json);
trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id)
?: "");
monitor_qmp_dispatch(mon, req, id);
+ qobject_unref(req);
+ qobject_unref(id);
return;
}