Revisión | 7e3c0deab1b76f37ac0b3199324db976a6cd1b2c (tree) |
---|---|
Tiempo | 2019-06-18 03:36:56 |
Autor | Kevin Wolf <kwolf@redh...> |
Commiter | Markus Armbruster |
monitor: Split out monitor/qmp.c
Move QMP infrastructure from monitor/misc.c to monitor/qmp.c. This is
code that can be shared for all targets, so compile it only once.
The amount of function and particularly extern variables in
monitor_int.h is probably a bit larger than it needs to be, but this way
no non-trivial code modifications are needed. The interfaces between QMP
and the monitor core can be cleaned up later.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Message-Id: <20190613153405.24769-11-kwolf@redhat.com>
Reviewed-by: Markus Armbruster <armbru@redhat.com>
[monitor_is_qmp() tidied up to make checkpatch.pl happy,
superfluous #include dropped]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
@@ -46,6 +46,7 @@ ifeq ($(CONFIG_SOFTMMU),y) | ||
46 | 46 | common-obj-y = blockdev.o blockdev-nbd.o block/ |
47 | 47 | common-obj-y += bootdevice.o iothread.o |
48 | 48 | common-obj-y += job-qmp.o |
49 | +common-obj-y += monitor/ | |
49 | 50 | common-obj-y += net/ |
50 | 51 | common-obj-y += qdev-monitor.o device-hotplug.o |
51 | 52 | common-obj-$(CONFIG_WIN32) += os-win32.o |
@@ -1,2 +1,3 @@ | ||
1 | 1 | obj-y += misc.o |
2 | +common-obj-y += qmp.o | |
2 | 3 | common-obj-y += qmp-cmds.o hmp-cmds.o |
@@ -36,7 +36,6 @@ | ||
36 | 36 | #include "exec/gdbstub.h" |
37 | 37 | #include "net/net.h" |
38 | 38 | #include "net/slirp.h" |
39 | -#include "chardev/char-io.h" | |
40 | 39 | #include "chardev/char-mux.h" |
41 | 40 | #include "ui/qemu-spice.h" |
42 | 41 | #include "sysemu/numa.h" |
@@ -58,8 +57,6 @@ | ||
58 | 57 | #include "qapi/qmp/qerror.h" |
59 | 58 | #include "qapi/qmp/qnum.h" |
60 | 59 | #include "qapi/qmp/qstring.h" |
61 | -#include "qapi/qmp/qjson.h" | |
62 | -#include "qapi/qmp/qlist.h" | |
63 | 60 | #include "qom/object_interfaces.h" |
64 | 61 | #include "trace.h" |
65 | 62 | #include "trace/control.h" |
@@ -81,7 +78,6 @@ | ||
81 | 78 | #include "qapi/qapi-introspect.h" |
82 | 79 | #include "sysemu/qtest.h" |
83 | 80 | #include "sysemu/cpus.h" |
84 | -#include "sysemu/iothread.h" | |
85 | 81 | #include "qemu/cutils.h" |
86 | 82 | #include "tcg/tcg.h" |
87 | 83 |
@@ -138,52 +134,30 @@ IOThread *mon_iothread; | ||
138 | 134 | /* Bottom half to dispatch the requests received from I/O thread */ |
139 | 135 | QEMUBH *qmp_dispatcher_bh; |
140 | 136 | |
141 | -struct QMPRequest { | |
142 | - /* Owner of the request */ | |
143 | - MonitorQMP *mon; | |
144 | - /* | |
145 | - * Request object to be handled or Error to be reported | |
146 | - * (exactly one of them is non-null) | |
147 | - */ | |
148 | - QObject *req; | |
149 | - Error *err; | |
150 | -}; | |
151 | -typedef struct QMPRequest QMPRequest; | |
152 | - | |
153 | 137 | /* QMP checker flags */ |
154 | 138 | #define QMP_ACCEPT_UNKNOWNS 1 |
155 | 139 | |
156 | 140 | /* Protects mon_list, monitor_qapi_event_state, monitor_destroyed. */ |
157 | -static QemuMutex monitor_lock; | |
141 | +QemuMutex monitor_lock; | |
158 | 142 | static GHashTable *monitor_qapi_event_state; |
159 | -static QTAILQ_HEAD(, Monitor) mon_list; | |
143 | +MonitorList mon_list; | |
160 | 144 | static bool monitor_destroyed; |
161 | 145 | |
162 | 146 | /* Protects mon_fdsets */ |
163 | 147 | static QemuMutex mon_fdsets_lock; |
164 | 148 | static QLIST_HEAD(, MonFdset) mon_fdsets; |
165 | 149 | |
166 | -static int mon_refcount; | |
150 | +int mon_refcount; | |
167 | 151 | |
168 | 152 | static HMPCommand hmp_cmds[]; |
169 | 153 | static HMPCommand hmp_info_cmds[]; |
170 | 154 | |
171 | -QmpCommandList qmp_commands, qmp_cap_negotiation_commands; | |
172 | - | |
173 | 155 | __thread Monitor *cur_mon; |
174 | 156 | |
175 | 157 | static void monitor_command_cb(void *opaque, const char *cmdline, |
176 | 158 | void *readline_opaque); |
177 | 159 | |
178 | 160 | /** |
179 | - * Is @mon a QMP monitor? | |
180 | - */ | |
181 | -static inline bool monitor_is_qmp(const Monitor *mon) | |
182 | -{ | |
183 | - return (mon->flags & MONITOR_USE_CONTROL); | |
184 | -} | |
185 | - | |
186 | -/** | |
187 | 161 | * Is @mon is using readline? |
188 | 162 | * Note: not all HMP monitors use readline, e.g., gdbserver has a |
189 | 163 | * non-interactive HMP monitor, so readline is not used there. |
@@ -241,28 +215,6 @@ int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, | ||
241 | 215 | } |
242 | 216 | } |
243 | 217 | |
244 | -static void qmp_request_free(QMPRequest *req) | |
245 | -{ | |
246 | - qobject_unref(req->req); | |
247 | - error_free(req->err); | |
248 | - g_free(req); | |
249 | -} | |
250 | - | |
251 | -/* Caller must hold mon->qmp.qmp_queue_lock */ | |
252 | -static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon) | |
253 | -{ | |
254 | - while (!g_queue_is_empty(mon->qmp_requests)) { | |
255 | - qmp_request_free(g_queue_pop_head(mon->qmp_requests)); | |
256 | - } | |
257 | -} | |
258 | - | |
259 | -static void monitor_qmp_cleanup_queues(MonitorQMP *mon) | |
260 | -{ | |
261 | - qemu_mutex_lock(&mon->qmp_queue_lock); | |
262 | - monitor_qmp_cleanup_req_queue_locked(mon); | |
263 | - qemu_mutex_unlock(&mon->qmp_queue_lock); | |
264 | -} | |
265 | - | |
266 | 218 | |
267 | 219 | static void monitor_flush_locked(Monitor *mon); |
268 | 220 |
@@ -322,7 +274,7 @@ void monitor_flush(Monitor *mon) | ||
322 | 274 | } |
323 | 275 | |
324 | 276 | /* flush at every end of line */ |
325 | -static int monitor_puts(Monitor *mon, const char *str) | |
277 | +int monitor_puts(Monitor *mon, const char *str) | |
326 | 278 | { |
327 | 279 | int i; |
328 | 280 | char c; |
@@ -372,21 +324,6 @@ int monitor_printf(Monitor *mon, const char *fmt, ...) | ||
372 | 324 | return ret; |
373 | 325 | } |
374 | 326 | |
375 | -static void qmp_send_response(MonitorQMP *mon, const QDict *rsp) | |
376 | -{ | |
377 | - const QObject *data = QOBJECT(rsp); | |
378 | - QString *json; | |
379 | - | |
380 | - json = mon->common.flags & MONITOR_USE_PRETTY ? | |
381 | - qobject_to_json_pretty(data) : qobject_to_json(data); | |
382 | - assert(json != NULL); | |
383 | - | |
384 | - qstring_append_chr(json, '\n'); | |
385 | - monitor_puts(&mon->common, qstring_get_str(json)); | |
386 | - | |
387 | - qobject_unref(json); | |
388 | -} | |
389 | - | |
390 | 327 | static MonitorQAPIEventConf monitor_qapi_event_conf[QAPI_EVENT__MAX] = { |
391 | 328 | /* Limit guest-triggerable events to 1 per second */ |
392 | 329 | [QAPI_EVENT_RTC_CHANGE] = { 1000 * SCALE_MS }, |
@@ -601,8 +538,8 @@ static void handle_hmp_command(MonitorHMP *mon, const char *cmdline); | ||
601 | 538 | |
602 | 539 | static void monitor_iothread_init(void); |
603 | 540 | |
604 | -static void monitor_data_init(Monitor *mon, int flags, bool skip_flush, | |
605 | - bool use_io_thread) | |
541 | +void monitor_data_init(Monitor *mon, int flags, bool skip_flush, | |
542 | + bool use_io_thread) | |
606 | 543 | { |
607 | 544 | if (use_io_thread && !mon_iothread) { |
608 | 545 | monitor_iothread_init(); |
@@ -614,14 +551,6 @@ static void monitor_data_init(Monitor *mon, int flags, bool skip_flush, | ||
614 | 551 | mon->flags = flags; |
615 | 552 | } |
616 | 553 | |
617 | -static void monitor_data_destroy_qmp(MonitorQMP *mon) | |
618 | -{ | |
619 | - json_message_parser_destroy(&mon->parser); | |
620 | - qemu_mutex_destroy(&mon->qmp_queue_lock); | |
621 | - monitor_qmp_cleanup_req_queue_locked(mon); | |
622 | - g_queue_free(mon->qmp_requests); | |
623 | -} | |
624 | - | |
625 | 554 | static void monitor_data_destroy(Monitor *mon) |
626 | 555 | { |
627 | 556 | g_free(mon->mon_cpu_path); |
@@ -1058,18 +987,6 @@ static void monitor_init_qmp_commands(void) | ||
1058 | 987 | qmp_marshal_qmp_capabilities, QCO_ALLOW_PRECONFIG); |
1059 | 988 | } |
1060 | 989 | |
1061 | -static bool qmp_oob_enabled(MonitorQMP *mon) | |
1062 | -{ | |
1063 | - return mon->capab[QMP_CAPABILITY_OOB]; | |
1064 | -} | |
1065 | - | |
1066 | -static void monitor_qmp_caps_reset(MonitorQMP *mon) | |
1067 | -{ | |
1068 | - memset(mon->capab_offered, 0, sizeof(mon->capab_offered)); | |
1069 | - memset(mon->capab, 0, sizeof(mon->capab)); | |
1070 | - mon->capab_offered[QMP_CAPABILITY_OOB] = mon->common.use_io_thread; | |
1071 | -} | |
1072 | - | |
1073 | 990 | /* |
1074 | 991 | * Accept QMP capabilities in @list for @mon. |
1075 | 992 | * On success, set mon->qmp.capab[], and return true. |
@@ -2245,7 +2162,7 @@ static void monitor_fdset_cleanup(MonFdset *mon_fdset) | ||
2245 | 2162 | } |
2246 | 2163 | } |
2247 | 2164 | |
2248 | -static void monitor_fdsets_cleanup(void) | |
2165 | +void monitor_fdsets_cleanup(void) | |
2249 | 2166 | { |
2250 | 2167 | MonFdset *mon_fdset; |
2251 | 2168 | MonFdset *mon_fdset_next; |
@@ -4023,209 +3940,13 @@ cleanup: | ||
4023 | 3940 | free_cmdline_args(args, nb_args); |
4024 | 3941 | } |
4025 | 3942 | |
4026 | -static int monitor_can_read(void *opaque) | |
3943 | +int monitor_can_read(void *opaque) | |
4027 | 3944 | { |
4028 | 3945 | Monitor *mon = opaque; |
4029 | 3946 | |
4030 | 3947 | return !atomic_mb_read(&mon->suspend_cnt); |
4031 | 3948 | } |
4032 | 3949 | |
4033 | -/* | |
4034 | - * Emit QMP response @rsp with ID @id to @mon. | |
4035 | - * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. | |
4036 | - * Nothing is emitted then. | |
4037 | - */ | |
4038 | -static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) | |
4039 | -{ | |
4040 | - if (rsp) { | |
4041 | - qmp_send_response(mon, rsp); | |
4042 | - } | |
4043 | -} | |
4044 | - | |
4045 | -static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) | |
4046 | -{ | |
4047 | - Monitor *old_mon; | |
4048 | - QDict *rsp; | |
4049 | - QDict *error; | |
4050 | - | |
4051 | - old_mon = cur_mon; | |
4052 | - cur_mon = &mon->common; | |
4053 | - | |
4054 | - rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); | |
4055 | - | |
4056 | - cur_mon = old_mon; | |
4057 | - | |
4058 | - if (mon->commands == &qmp_cap_negotiation_commands) { | |
4059 | - error = qdict_get_qdict(rsp, "error"); | |
4060 | - if (error | |
4061 | - && !g_strcmp0(qdict_get_try_str(error, "class"), | |
4062 | - QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { | |
4063 | - /* Provide a more useful error message */ | |
4064 | - qdict_del(error, "desc"); | |
4065 | - qdict_put_str(error, "desc", "Expecting capabilities negotiation" | |
4066 | - " with 'qmp_capabilities'"); | |
4067 | - } | |
4068 | - } | |
4069 | - | |
4070 | - monitor_qmp_respond(mon, rsp); | |
4071 | - qobject_unref(rsp); | |
4072 | -} | |
4073 | - | |
4074 | -/* | |
4075 | - * Pop a QMP request from a monitor request queue. | |
4076 | - * Return the request, or NULL all request queues are empty. | |
4077 | - * We are using round-robin fashion to pop the request, to avoid | |
4078 | - * processing commands only on a very busy monitor. To achieve that, | |
4079 | - * when we process one request on a specific monitor, we put that | |
4080 | - * monitor to the end of mon_list queue. | |
4081 | - * | |
4082 | - * Note: if the function returned with non-NULL, then the caller will | |
4083 | - * be with qmp_mon->qmp_queue_lock held, and the caller is responsible | |
4084 | - * to release it. | |
4085 | - */ | |
4086 | -static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) | |
4087 | -{ | |
4088 | - QMPRequest *req_obj = NULL; | |
4089 | - Monitor *mon; | |
4090 | - MonitorQMP *qmp_mon; | |
4091 | - | |
4092 | - qemu_mutex_lock(&monitor_lock); | |
4093 | - | |
4094 | - QTAILQ_FOREACH(mon, &mon_list, entry) { | |
4095 | - if (!monitor_is_qmp(mon)) { | |
4096 | - continue; | |
4097 | - } | |
4098 | - | |
4099 | - qmp_mon = container_of(mon, MonitorQMP, common); | |
4100 | - qemu_mutex_lock(&qmp_mon->qmp_queue_lock); | |
4101 | - req_obj = g_queue_pop_head(qmp_mon->qmp_requests); | |
4102 | - if (req_obj) { | |
4103 | - /* With the lock of corresponding queue held */ | |
4104 | - break; | |
4105 | - } | |
4106 | - qemu_mutex_unlock(&qmp_mon->qmp_queue_lock); | |
4107 | - } | |
4108 | - | |
4109 | - if (req_obj) { | |
4110 | - /* | |
4111 | - * We found one request on the monitor. Degrade this monitor's | |
4112 | - * priority to lowest by re-inserting it to end of queue. | |
4113 | - */ | |
4114 | - QTAILQ_REMOVE(&mon_list, mon, entry); | |
4115 | - QTAILQ_INSERT_TAIL(&mon_list, mon, entry); | |
4116 | - } | |
4117 | - | |
4118 | - qemu_mutex_unlock(&monitor_lock); | |
4119 | - | |
4120 | - return req_obj; | |
4121 | -} | |
4122 | - | |
4123 | -static void monitor_qmp_bh_dispatcher(void *data) | |
4124 | -{ | |
4125 | - QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock(); | |
4126 | - QDict *rsp; | |
4127 | - bool need_resume; | |
4128 | - MonitorQMP *mon; | |
4129 | - | |
4130 | - if (!req_obj) { | |
4131 | - return; | |
4132 | - } | |
4133 | - | |
4134 | - mon = req_obj->mon; | |
4135 | - /* qmp_oob_enabled() might change after "qmp_capabilities" */ | |
4136 | - need_resume = !qmp_oob_enabled(mon) || | |
4137 | - mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1; | |
4138 | - qemu_mutex_unlock(&mon->qmp_queue_lock); | |
4139 | - if (req_obj->req) { | |
4140 | - QDict *qdict = qobject_to(QDict, req_obj->req); | |
4141 | - QObject *id = qdict ? qdict_get(qdict, "id") : NULL; | |
4142 | - trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); | |
4143 | - monitor_qmp_dispatch(mon, req_obj->req); | |
4144 | - } else { | |
4145 | - assert(req_obj->err); | |
4146 | - rsp = qmp_error_response(req_obj->err); | |
4147 | - req_obj->err = NULL; | |
4148 | - monitor_qmp_respond(mon, rsp); | |
4149 | - qobject_unref(rsp); | |
4150 | - } | |
4151 | - | |
4152 | - if (need_resume) { | |
4153 | - /* Pairs with the monitor_suspend() in handle_qmp_command() */ | |
4154 | - monitor_resume(&mon->common); | |
4155 | - } | |
4156 | - qmp_request_free(req_obj); | |
4157 | - | |
4158 | - /* Reschedule instead of looping so the main loop stays responsive */ | |
4159 | - qemu_bh_schedule(qmp_dispatcher_bh); | |
4160 | -} | |
4161 | - | |
4162 | -static void handle_qmp_command(void *opaque, QObject *req, Error *err) | |
4163 | -{ | |
4164 | - MonitorQMP *mon = opaque; | |
4165 | - QObject *id = NULL; | |
4166 | - QDict *qdict; | |
4167 | - QMPRequest *req_obj; | |
4168 | - | |
4169 | - assert(!req != !err); | |
4170 | - | |
4171 | - qdict = qobject_to(QDict, req); | |
4172 | - if (qdict) { | |
4173 | - id = qdict_get(qdict, "id"); | |
4174 | - } /* else will fail qmp_dispatch() */ | |
4175 | - | |
4176 | - if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { | |
4177 | - QString *req_json = qobject_to_json(req); | |
4178 | - trace_handle_qmp_command(mon, qstring_get_str(req_json)); | |
4179 | - qobject_unref(req_json); | |
4180 | - } | |
4181 | - | |
4182 | - if (qdict && qmp_is_oob(qdict)) { | |
4183 | - /* OOB commands are executed immediately */ | |
4184 | - trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: ""); | |
4185 | - monitor_qmp_dispatch(mon, req); | |
4186 | - qobject_unref(req); | |
4187 | - return; | |
4188 | - } | |
4189 | - | |
4190 | - req_obj = g_new0(QMPRequest, 1); | |
4191 | - req_obj->mon = mon; | |
4192 | - req_obj->req = req; | |
4193 | - req_obj->err = err; | |
4194 | - | |
4195 | - /* Protect qmp_requests and fetching its length. */ | |
4196 | - qemu_mutex_lock(&mon->qmp_queue_lock); | |
4197 | - | |
4198 | - /* | |
4199 | - * Suspend the monitor when we can't queue more requests after | |
4200 | - * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume | |
4201 | - * it. Note that when OOB is disabled, we queue at most one | |
4202 | - * command, for backward compatibility. | |
4203 | - */ | |
4204 | - if (!qmp_oob_enabled(mon) || | |
4205 | - mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) { | |
4206 | - monitor_suspend(&mon->common); | |
4207 | - } | |
4208 | - | |
4209 | - /* | |
4210 | - * Put the request to the end of queue so that requests will be | |
4211 | - * handled in time order. Ownership for req_obj, req, | |
4212 | - * etc. will be delivered to the handler side. | |
4213 | - */ | |
4214 | - assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); | |
4215 | - g_queue_push_tail(mon->qmp_requests, req_obj); | |
4216 | - qemu_mutex_unlock(&mon->qmp_queue_lock); | |
4217 | - | |
4218 | - /* Kick the dispatcher routine */ | |
4219 | - qemu_bh_schedule(qmp_dispatcher_bh); | |
4220 | -} | |
4221 | - | |
4222 | -static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) | |
4223 | -{ | |
4224 | - MonitorQMP *mon = opaque; | |
4225 | - | |
4226 | - json_message_parser_feed(&mon->parser, (const char *) buf, size); | |
4227 | -} | |
4228 | - | |
4229 | 3950 | static void monitor_read(void *opaque, const uint8_t *buf, int size) |
4230 | 3951 | { |
4231 | 3952 | MonitorHMP *mon; |
@@ -4312,56 +4033,6 @@ void monitor_resume(Monitor *mon) | ||
4312 | 4033 | trace_monitor_suspend(mon, -1); |
4313 | 4034 | } |
4314 | 4035 | |
4315 | -static QDict *qmp_greeting(MonitorQMP *mon) | |
4316 | -{ | |
4317 | - QList *cap_list = qlist_new(); | |
4318 | - QObject *ver = NULL; | |
4319 | - QMPCapability cap; | |
4320 | - | |
4321 | - qmp_marshal_query_version(NULL, &ver, NULL); | |
4322 | - | |
4323 | - for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) { | |
4324 | - if (mon->capab_offered[cap]) { | |
4325 | - qlist_append_str(cap_list, QMPCapability_str(cap)); | |
4326 | - } | |
4327 | - } | |
4328 | - | |
4329 | - return qdict_from_jsonf_nofail( | |
4330 | - "{'QMP': {'version': %p, 'capabilities': %p}}", | |
4331 | - ver, cap_list); | |
4332 | -} | |
4333 | - | |
4334 | -static void monitor_qmp_event(void *opaque, int event) | |
4335 | -{ | |
4336 | - QDict *data; | |
4337 | - MonitorQMP *mon = opaque; | |
4338 | - | |
4339 | - switch (event) { | |
4340 | - case CHR_EVENT_OPENED: | |
4341 | - mon->commands = &qmp_cap_negotiation_commands; | |
4342 | - monitor_qmp_caps_reset(mon); | |
4343 | - data = qmp_greeting(mon); | |
4344 | - qmp_send_response(mon, data); | |
4345 | - qobject_unref(data); | |
4346 | - mon_refcount++; | |
4347 | - break; | |
4348 | - case CHR_EVENT_CLOSED: | |
4349 | - /* | |
4350 | - * Note: this is only useful when the output of the chardev | |
4351 | - * backend is still open. For example, when the backend is | |
4352 | - * stdio, it's possible that stdout is still open when stdin | |
4353 | - * is closed. | |
4354 | - */ | |
4355 | - monitor_qmp_cleanup_queues(mon); | |
4356 | - json_message_parser_destroy(&mon->parser); | |
4357 | - json_message_parser_init(&mon->parser, handle_qmp_command, | |
4358 | - mon, NULL); | |
4359 | - mon_refcount--; | |
4360 | - monitor_fdsets_cleanup(); | |
4361 | - break; | |
4362 | - } | |
4363 | -} | |
4364 | - | |
4365 | 4036 | static void monitor_event(void *opaque, int event) |
4366 | 4037 | { |
4367 | 4038 | Monitor *mon = opaque; |
@@ -4495,7 +4166,7 @@ int error_vprintf_unless_qmp(const char *fmt, va_list ap) | ||
4495 | 4166 | return -1; |
4496 | 4167 | } |
4497 | 4168 | |
4498 | -static void monitor_list_append(Monitor *mon) | |
4169 | +void monitor_list_append(Monitor *mon) | |
4499 | 4170 | { |
4500 | 4171 | qemu_mutex_lock(&monitor_lock); |
4501 | 4172 | /* |
@@ -4515,60 +4186,6 @@ static void monitor_list_append(Monitor *mon) | ||
4515 | 4186 | } |
4516 | 4187 | } |
4517 | 4188 | |
4518 | -static void monitor_qmp_setup_handlers_bh(void *opaque) | |
4519 | -{ | |
4520 | - MonitorQMP *mon = opaque; | |
4521 | - GMainContext *context; | |
4522 | - | |
4523 | - assert(mon->common.use_io_thread); | |
4524 | - context = iothread_get_g_main_context(mon_iothread); | |
4525 | - assert(context); | |
4526 | - qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, | |
4527 | - monitor_qmp_read, monitor_qmp_event, | |
4528 | - NULL, &mon->common, context, true); | |
4529 | - monitor_list_append(&mon->common); | |
4530 | -} | |
4531 | - | |
4532 | -static void monitor_init_qmp(Chardev *chr, int flags) | |
4533 | -{ | |
4534 | - MonitorQMP *mon = g_new0(MonitorQMP, 1); | |
4535 | - | |
4536 | - /* Only HMP supports readline */ | |
4537 | - assert(!(flags & MONITOR_USE_READLINE)); | |
4538 | - | |
4539 | - /* Note: we run QMP monitor in I/O thread when @chr supports that */ | |
4540 | - monitor_data_init(&mon->common, flags, false, | |
4541 | - qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); | |
4542 | - | |
4543 | - qemu_mutex_init(&mon->qmp_queue_lock); | |
4544 | - mon->qmp_requests = g_queue_new(); | |
4545 | - | |
4546 | - qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); | |
4547 | - qemu_chr_fe_set_echo(&mon->common.chr, true); | |
4548 | - | |
4549 | - json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); | |
4550 | - if (mon->common.use_io_thread) { | |
4551 | - /* | |
4552 | - * Make sure the old iowatch is gone. It's possible when | |
4553 | - * e.g. the chardev is in client mode, with wait=on. | |
4554 | - */ | |
4555 | - remove_fd_in_watch(chr); | |
4556 | - /* | |
4557 | - * We can't call qemu_chr_fe_set_handlers() directly here | |
4558 | - * since chardev might be running in the monitor I/O | |
4559 | - * thread. Schedule a bottom half. | |
4560 | - */ | |
4561 | - aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), | |
4562 | - monitor_qmp_setup_handlers_bh, mon); | |
4563 | - /* The bottom half will add @mon to @mon_list */ | |
4564 | - } else { | |
4565 | - qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, | |
4566 | - monitor_qmp_read, monitor_qmp_event, | |
4567 | - NULL, &mon->common, NULL, true); | |
4568 | - monitor_list_append(&mon->common); | |
4569 | - } | |
4570 | -} | |
4571 | - | |
4572 | 4189 | static void monitor_init_hmp(Chardev *chr, int flags) |
4573 | 4190 | { |
4574 | 4191 | MonitorHMP *mon = g_new0(MonitorHMP, 1); |
@@ -31,6 +31,7 @@ | ||
31 | 31 | #include "qapi/qmp/dispatch.h" |
32 | 32 | #include "qapi/qmp/json-parser.h" |
33 | 33 | #include "qemu/readline.h" |
34 | +#include "sysemu/iothread.h" | |
34 | 35 | |
35 | 36 | /* |
36 | 37 | * Supported types: |
@@ -142,4 +143,33 @@ typedef struct { | ||
142 | 143 | GQueue *qmp_requests; |
143 | 144 | } MonitorQMP; |
144 | 145 | |
146 | +/** | |
147 | + * Is @mon a QMP monitor? | |
148 | + */ | |
149 | +static inline bool monitor_is_qmp(const Monitor *mon) | |
150 | +{ | |
151 | + return mon->flags & MONITOR_USE_CONTROL; | |
152 | +} | |
153 | + | |
154 | +typedef QTAILQ_HEAD(MonitorList, Monitor) MonitorList; | |
155 | +extern IOThread *mon_iothread; | |
156 | +extern QEMUBH *qmp_dispatcher_bh; | |
157 | +extern QmpCommandList qmp_commands, qmp_cap_negotiation_commands; | |
158 | +extern QemuMutex monitor_lock; | |
159 | +extern MonitorList mon_list; | |
160 | +extern int mon_refcount; | |
161 | + | |
162 | +void monitor_init_qmp(Chardev *chr, int flags); | |
163 | + | |
164 | +int monitor_puts(Monitor *mon, const char *str); | |
165 | +void monitor_data_init(Monitor *mon, int flags, bool skip_flush, | |
166 | + bool use_io_thread); | |
167 | +int monitor_can_read(void *opaque); | |
168 | +void monitor_list_append(Monitor *mon); | |
169 | +void monitor_fdsets_cleanup(void); | |
170 | + | |
171 | +void qmp_send_response(MonitorQMP *mon, const QDict *rsp); | |
172 | +void monitor_data_destroy_qmp(MonitorQMP *mon); | |
173 | +void monitor_qmp_bh_dispatcher(void *data); | |
174 | + | |
145 | 175 | #endif |
@@ -0,0 +1,406 @@ | ||
1 | +/* | |
2 | + * QEMU monitor | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 Fabrice Bellard | |
5 | + * | |
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
7 | + * of this software and associated documentation files (the "Software"), to deal | |
8 | + * in the Software without restriction, including without limitation the rights | |
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
10 | + * copies of the Software, and to permit persons to whom the Software is | |
11 | + * furnished to do so, subject to the following conditions: | |
12 | + * | |
13 | + * The above copyright notice and this permission notice shall be included in | |
14 | + * all copies or substantial portions of the Software. | |
15 | + * | |
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
22 | + * THE SOFTWARE. | |
23 | + */ | |
24 | + | |
25 | +#include "qemu/osdep.h" | |
26 | + | |
27 | +#include "chardev/char-io.h" | |
28 | +#include "monitor-internal.h" | |
29 | +#include "qapi/error.h" | |
30 | +#include "qapi/qapi-commands-misc.h" | |
31 | +#include "qapi/qmp/qdict.h" | |
32 | +#include "qapi/qmp/qjson.h" | |
33 | +#include "qapi/qmp/qlist.h" | |
34 | +#include "qapi/qmp/qstring.h" | |
35 | +#include "trace.h" | |
36 | + | |
37 | +struct QMPRequest { | |
38 | + /* Owner of the request */ | |
39 | + MonitorQMP *mon; | |
40 | + /* | |
41 | + * Request object to be handled or Error to be reported | |
42 | + * (exactly one of them is non-null) | |
43 | + */ | |
44 | + QObject *req; | |
45 | + Error *err; | |
46 | +}; | |
47 | +typedef struct QMPRequest QMPRequest; | |
48 | + | |
49 | +QmpCommandList qmp_commands, qmp_cap_negotiation_commands; | |
50 | + | |
51 | +static bool qmp_oob_enabled(MonitorQMP *mon) | |
52 | +{ | |
53 | + return mon->capab[QMP_CAPABILITY_OOB]; | |
54 | +} | |
55 | + | |
56 | +static void monitor_qmp_caps_reset(MonitorQMP *mon) | |
57 | +{ | |
58 | + memset(mon->capab_offered, 0, sizeof(mon->capab_offered)); | |
59 | + memset(mon->capab, 0, sizeof(mon->capab)); | |
60 | + mon->capab_offered[QMP_CAPABILITY_OOB] = mon->common.use_io_thread; | |
61 | +} | |
62 | + | |
63 | +static void qmp_request_free(QMPRequest *req) | |
64 | +{ | |
65 | + qobject_unref(req->req); | |
66 | + error_free(req->err); | |
67 | + g_free(req); | |
68 | +} | |
69 | + | |
70 | +/* Caller must hold mon->qmp.qmp_queue_lock */ | |
71 | +static void monitor_qmp_cleanup_req_queue_locked(MonitorQMP *mon) | |
72 | +{ | |
73 | + while (!g_queue_is_empty(mon->qmp_requests)) { | |
74 | + qmp_request_free(g_queue_pop_head(mon->qmp_requests)); | |
75 | + } | |
76 | +} | |
77 | + | |
78 | +static void monitor_qmp_cleanup_queues(MonitorQMP *mon) | |
79 | +{ | |
80 | + qemu_mutex_lock(&mon->qmp_queue_lock); | |
81 | + monitor_qmp_cleanup_req_queue_locked(mon); | |
82 | + qemu_mutex_unlock(&mon->qmp_queue_lock); | |
83 | +} | |
84 | + | |
85 | +void qmp_send_response(MonitorQMP *mon, const QDict *rsp) | |
86 | +{ | |
87 | + const QObject *data = QOBJECT(rsp); | |
88 | + QString *json; | |
89 | + | |
90 | + json = mon->common.flags & MONITOR_USE_PRETTY ? | |
91 | + qobject_to_json_pretty(data) : qobject_to_json(data); | |
92 | + assert(json != NULL); | |
93 | + | |
94 | + qstring_append_chr(json, '\n'); | |
95 | + monitor_puts(&mon->common, qstring_get_str(json)); | |
96 | + | |
97 | + qobject_unref(json); | |
98 | +} | |
99 | + | |
100 | +/* | |
101 | + * Emit QMP response @rsp with ID @id to @mon. | |
102 | + * Null @rsp can only happen for commands with QCO_NO_SUCCESS_RESP. | |
103 | + * Nothing is emitted then. | |
104 | + */ | |
105 | +static void monitor_qmp_respond(MonitorQMP *mon, QDict *rsp) | |
106 | +{ | |
107 | + if (rsp) { | |
108 | + qmp_send_response(mon, rsp); | |
109 | + } | |
110 | +} | |
111 | + | |
112 | +static void monitor_qmp_dispatch(MonitorQMP *mon, QObject *req) | |
113 | +{ | |
114 | + Monitor *old_mon; | |
115 | + QDict *rsp; | |
116 | + QDict *error; | |
117 | + | |
118 | + old_mon = cur_mon; | |
119 | + cur_mon = &mon->common; | |
120 | + | |
121 | + rsp = qmp_dispatch(mon->commands, req, qmp_oob_enabled(mon)); | |
122 | + | |
123 | + cur_mon = old_mon; | |
124 | + | |
125 | + if (mon->commands == &qmp_cap_negotiation_commands) { | |
126 | + error = qdict_get_qdict(rsp, "error"); | |
127 | + if (error | |
128 | + && !g_strcmp0(qdict_get_try_str(error, "class"), | |
129 | + QapiErrorClass_str(ERROR_CLASS_COMMAND_NOT_FOUND))) { | |
130 | + /* Provide a more useful error message */ | |
131 | + qdict_del(error, "desc"); | |
132 | + qdict_put_str(error, "desc", "Expecting capabilities negotiation" | |
133 | + " with 'qmp_capabilities'"); | |
134 | + } | |
135 | + } | |
136 | + | |
137 | + monitor_qmp_respond(mon, rsp); | |
138 | + qobject_unref(rsp); | |
139 | +} | |
140 | + | |
141 | +/* | |
142 | + * Pop a QMP request from a monitor request queue. | |
143 | + * Return the request, or NULL all request queues are empty. | |
144 | + * We are using round-robin fashion to pop the request, to avoid | |
145 | + * processing commands only on a very busy monitor. To achieve that, | |
146 | + * when we process one request on a specific monitor, we put that | |
147 | + * monitor to the end of mon_list queue. | |
148 | + * | |
149 | + * Note: if the function returned with non-NULL, then the caller will | |
150 | + * be with qmp_mon->qmp_queue_lock held, and the caller is responsible | |
151 | + * to release it. | |
152 | + */ | |
153 | +static QMPRequest *monitor_qmp_requests_pop_any_with_lock(void) | |
154 | +{ | |
155 | + QMPRequest *req_obj = NULL; | |
156 | + Monitor *mon; | |
157 | + MonitorQMP *qmp_mon; | |
158 | + | |
159 | + qemu_mutex_lock(&monitor_lock); | |
160 | + | |
161 | + QTAILQ_FOREACH(mon, &mon_list, entry) { | |
162 | + if (!monitor_is_qmp(mon)) { | |
163 | + continue; | |
164 | + } | |
165 | + | |
166 | + qmp_mon = container_of(mon, MonitorQMP, common); | |
167 | + qemu_mutex_lock(&qmp_mon->qmp_queue_lock); | |
168 | + req_obj = g_queue_pop_head(qmp_mon->qmp_requests); | |
169 | + if (req_obj) { | |
170 | + /* With the lock of corresponding queue held */ | |
171 | + break; | |
172 | + } | |
173 | + qemu_mutex_unlock(&qmp_mon->qmp_queue_lock); | |
174 | + } | |
175 | + | |
176 | + if (req_obj) { | |
177 | + /* | |
178 | + * We found one request on the monitor. Degrade this monitor's | |
179 | + * priority to lowest by re-inserting it to end of queue. | |
180 | + */ | |
181 | + QTAILQ_REMOVE(&mon_list, mon, entry); | |
182 | + QTAILQ_INSERT_TAIL(&mon_list, mon, entry); | |
183 | + } | |
184 | + | |
185 | + qemu_mutex_unlock(&monitor_lock); | |
186 | + | |
187 | + return req_obj; | |
188 | +} | |
189 | + | |
190 | +void monitor_qmp_bh_dispatcher(void *data) | |
191 | +{ | |
192 | + QMPRequest *req_obj = monitor_qmp_requests_pop_any_with_lock(); | |
193 | + QDict *rsp; | |
194 | + bool need_resume; | |
195 | + MonitorQMP *mon; | |
196 | + | |
197 | + if (!req_obj) { | |
198 | + return; | |
199 | + } | |
200 | + | |
201 | + mon = req_obj->mon; | |
202 | + /* qmp_oob_enabled() might change after "qmp_capabilities" */ | |
203 | + need_resume = !qmp_oob_enabled(mon) || | |
204 | + mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1; | |
205 | + qemu_mutex_unlock(&mon->qmp_queue_lock); | |
206 | + if (req_obj->req) { | |
207 | + QDict *qdict = qobject_to(QDict, req_obj->req); | |
208 | + QObject *id = qdict ? qdict_get(qdict, "id") : NULL; | |
209 | + trace_monitor_qmp_cmd_in_band(qobject_get_try_str(id) ?: ""); | |
210 | + monitor_qmp_dispatch(mon, req_obj->req); | |
211 | + } else { | |
212 | + assert(req_obj->err); | |
213 | + rsp = qmp_error_response(req_obj->err); | |
214 | + req_obj->err = NULL; | |
215 | + monitor_qmp_respond(mon, rsp); | |
216 | + qobject_unref(rsp); | |
217 | + } | |
218 | + | |
219 | + if (need_resume) { | |
220 | + /* Pairs with the monitor_suspend() in handle_qmp_command() */ | |
221 | + monitor_resume(&mon->common); | |
222 | + } | |
223 | + qmp_request_free(req_obj); | |
224 | + | |
225 | + /* Reschedule instead of looping so the main loop stays responsive */ | |
226 | + qemu_bh_schedule(qmp_dispatcher_bh); | |
227 | +} | |
228 | + | |
229 | +static void handle_qmp_command(void *opaque, QObject *req, Error *err) | |
230 | +{ | |
231 | + MonitorQMP *mon = opaque; | |
232 | + QObject *id = NULL; | |
233 | + QDict *qdict; | |
234 | + QMPRequest *req_obj; | |
235 | + | |
236 | + assert(!req != !err); | |
237 | + | |
238 | + qdict = qobject_to(QDict, req); | |
239 | + if (qdict) { | |
240 | + id = qdict_get(qdict, "id"); | |
241 | + } /* else will fail qmp_dispatch() */ | |
242 | + | |
243 | + if (req && trace_event_get_state_backends(TRACE_HANDLE_QMP_COMMAND)) { | |
244 | + QString *req_json = qobject_to_json(req); | |
245 | + trace_handle_qmp_command(mon, qstring_get_str(req_json)); | |
246 | + qobject_unref(req_json); | |
247 | + } | |
248 | + | |
249 | + if (qdict && qmp_is_oob(qdict)) { | |
250 | + /* OOB commands are executed immediately */ | |
251 | + trace_monitor_qmp_cmd_out_of_band(qobject_get_try_str(id) ?: ""); | |
252 | + monitor_qmp_dispatch(mon, req); | |
253 | + qobject_unref(req); | |
254 | + return; | |
255 | + } | |
256 | + | |
257 | + req_obj = g_new0(QMPRequest, 1); | |
258 | + req_obj->mon = mon; | |
259 | + req_obj->req = req; | |
260 | + req_obj->err = err; | |
261 | + | |
262 | + /* Protect qmp_requests and fetching its length. */ | |
263 | + qemu_mutex_lock(&mon->qmp_queue_lock); | |
264 | + | |
265 | + /* | |
266 | + * Suspend the monitor when we can't queue more requests after | |
267 | + * this one. Dequeuing in monitor_qmp_bh_dispatcher() will resume | |
268 | + * it. Note that when OOB is disabled, we queue at most one | |
269 | + * command, for backward compatibility. | |
270 | + */ | |
271 | + if (!qmp_oob_enabled(mon) || | |
272 | + mon->qmp_requests->length == QMP_REQ_QUEUE_LEN_MAX - 1) { | |
273 | + monitor_suspend(&mon->common); | |
274 | + } | |
275 | + | |
276 | + /* | |
277 | + * Put the request to the end of queue so that requests will be | |
278 | + * handled in time order. Ownership for req_obj, req, | |
279 | + * etc. will be delivered to the handler side. | |
280 | + */ | |
281 | + assert(mon->qmp_requests->length < QMP_REQ_QUEUE_LEN_MAX); | |
282 | + g_queue_push_tail(mon->qmp_requests, req_obj); | |
283 | + qemu_mutex_unlock(&mon->qmp_queue_lock); | |
284 | + | |
285 | + /* Kick the dispatcher routine */ | |
286 | + qemu_bh_schedule(qmp_dispatcher_bh); | |
287 | +} | |
288 | + | |
289 | +static void monitor_qmp_read(void *opaque, const uint8_t *buf, int size) | |
290 | +{ | |
291 | + MonitorQMP *mon = opaque; | |
292 | + | |
293 | + json_message_parser_feed(&mon->parser, (const char *) buf, size); | |
294 | +} | |
295 | + | |
296 | +static QDict *qmp_greeting(MonitorQMP *mon) | |
297 | +{ | |
298 | + QList *cap_list = qlist_new(); | |
299 | + QObject *ver = NULL; | |
300 | + QMPCapability cap; | |
301 | + | |
302 | + qmp_marshal_query_version(NULL, &ver, NULL); | |
303 | + | |
304 | + for (cap = 0; cap < QMP_CAPABILITY__MAX; cap++) { | |
305 | + if (mon->capab_offered[cap]) { | |
306 | + qlist_append_str(cap_list, QMPCapability_str(cap)); | |
307 | + } | |
308 | + } | |
309 | + | |
310 | + return qdict_from_jsonf_nofail( | |
311 | + "{'QMP': {'version': %p, 'capabilities': %p}}", | |
312 | + ver, cap_list); | |
313 | +} | |
314 | + | |
315 | +static void monitor_qmp_event(void *opaque, int event) | |
316 | +{ | |
317 | + QDict *data; | |
318 | + MonitorQMP *mon = opaque; | |
319 | + | |
320 | + switch (event) { | |
321 | + case CHR_EVENT_OPENED: | |
322 | + mon->commands = &qmp_cap_negotiation_commands; | |
323 | + monitor_qmp_caps_reset(mon); | |
324 | + data = qmp_greeting(mon); | |
325 | + qmp_send_response(mon, data); | |
326 | + qobject_unref(data); | |
327 | + mon_refcount++; | |
328 | + break; | |
329 | + case CHR_EVENT_CLOSED: | |
330 | + /* | |
331 | + * Note: this is only useful when the output of the chardev | |
332 | + * backend is still open. For example, when the backend is | |
333 | + * stdio, it's possible that stdout is still open when stdin | |
334 | + * is closed. | |
335 | + */ | |
336 | + monitor_qmp_cleanup_queues(mon); | |
337 | + json_message_parser_destroy(&mon->parser); | |
338 | + json_message_parser_init(&mon->parser, handle_qmp_command, | |
339 | + mon, NULL); | |
340 | + mon_refcount--; | |
341 | + monitor_fdsets_cleanup(); | |
342 | + break; | |
343 | + } | |
344 | +} | |
345 | + | |
346 | +void monitor_data_destroy_qmp(MonitorQMP *mon) | |
347 | +{ | |
348 | + json_message_parser_destroy(&mon->parser); | |
349 | + qemu_mutex_destroy(&mon->qmp_queue_lock); | |
350 | + monitor_qmp_cleanup_req_queue_locked(mon); | |
351 | + g_queue_free(mon->qmp_requests); | |
352 | +} | |
353 | + | |
354 | +static void monitor_qmp_setup_handlers_bh(void *opaque) | |
355 | +{ | |
356 | + MonitorQMP *mon = opaque; | |
357 | + GMainContext *context; | |
358 | + | |
359 | + assert(mon->common.use_io_thread); | |
360 | + context = iothread_get_g_main_context(mon_iothread); | |
361 | + assert(context); | |
362 | + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, | |
363 | + monitor_qmp_read, monitor_qmp_event, | |
364 | + NULL, &mon->common, context, true); | |
365 | + monitor_list_append(&mon->common); | |
366 | +} | |
367 | + | |
368 | +void monitor_init_qmp(Chardev *chr, int flags) | |
369 | +{ | |
370 | + MonitorQMP *mon = g_new0(MonitorQMP, 1); | |
371 | + | |
372 | + /* Only HMP supports readline */ | |
373 | + assert(!(flags & MONITOR_USE_READLINE)); | |
374 | + | |
375 | + /* Note: we run QMP monitor in I/O thread when @chr supports that */ | |
376 | + monitor_data_init(&mon->common, flags, false, | |
377 | + qemu_chr_has_feature(chr, QEMU_CHAR_FEATURE_GCONTEXT)); | |
378 | + | |
379 | + qemu_mutex_init(&mon->qmp_queue_lock); | |
380 | + mon->qmp_requests = g_queue_new(); | |
381 | + | |
382 | + qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); | |
383 | + qemu_chr_fe_set_echo(&mon->common.chr, true); | |
384 | + | |
385 | + json_message_parser_init(&mon->parser, handle_qmp_command, mon, NULL); | |
386 | + if (mon->common.use_io_thread) { | |
387 | + /* | |
388 | + * Make sure the old iowatch is gone. It's possible when | |
389 | + * e.g. the chardev is in client mode, with wait=on. | |
390 | + */ | |
391 | + remove_fd_in_watch(chr); | |
392 | + /* | |
393 | + * We can't call qemu_chr_fe_set_handlers() directly here | |
394 | + * since chardev might be running in the monitor I/O | |
395 | + * thread. Schedule a bottom half. | |
396 | + */ | |
397 | + aio_bh_schedule_oneshot(iothread_get_aio_context(mon_iothread), | |
398 | + monitor_qmp_setup_handlers_bh, mon); | |
399 | + /* The bottom half will add @mon to @mon_list */ | |
400 | + } else { | |
401 | + qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, | |
402 | + monitor_qmp_read, monitor_qmp_event, | |
403 | + NULL, &mon->common, NULL, true); | |
404 | + monitor_list_append(&mon->common); | |
405 | + } | |
406 | +} |
@@ -5,7 +5,9 @@ monitor_protocol_event_handler(uint32_t event, void *qdict) "event=%d data=%p" | ||
5 | 5 | monitor_protocol_event_emit(uint32_t event, void *data) "event=%d data=%p" |
6 | 6 | monitor_protocol_event_queue(uint32_t event, void *qdict, uint64_t rate) "event=%d data=%p rate=%" PRId64 |
7 | 7 | handle_hmp_command(void *mon, const char *cmdline) "mon %p cmdline: %s" |
8 | -handle_qmp_command(void *mon, const char *req) "mon %p req: %s" | |
9 | 8 | monitor_suspend(void *ptr, int cnt) "mon %p: %d" |
9 | + | |
10 | +# qmp.c | |
10 | 11 | monitor_qmp_cmd_in_band(const char *id) "%s" |
11 | 12 | monitor_qmp_cmd_out_of_band(const char *id) "%s" |
13 | +handle_qmp_command(void *mon, const char *req) "mon %p req: %s" |