Revision 940cc30d

b/monitor.c
76 76
 *
77 77
 */
78 78

  
79
typedef struct MonitorCompletionData MonitorCompletionData;
80
struct MonitorCompletionData {
81
    Monitor *mon;
82
    void (*user_print)(Monitor *mon, const QObject *data);
83
};
84

  
79 85
typedef struct mon_cmd_t {
80 86
    const char *name;
81 87
    const char *args_type;
......
85 91
    union {
86 92
        void (*info)(Monitor *mon);
87 93
        void (*info_new)(Monitor *mon, QObject **ret_data);
94
        int  (*info_async)(Monitor *mon, MonitorCompletion *cb, void *opaque);
88 95
        void (*cmd)(Monitor *mon, const QDict *qdict);
89 96
        void (*cmd_new)(Monitor *mon, const QDict *params, QObject **ret_data);
97
        int  (*cmd_async)(Monitor *mon, const QDict *params,
98
                          MonitorCompletion *cb, void *opaque);
90 99
    } mhandler;
100
    int async;
91 101
} mon_cmd_t;
92 102

  
93 103
/* file descriptors passed via SCM_RIGHTS */
......
255 265
    return cmd->user_print != NULL;
256 266
}
257 267

  
268
static inline bool monitor_handler_is_async(const mon_cmd_t *cmd)
269
{
270
    return cmd->async != 0;
271
}
272

  
258 273
static inline int monitor_has_error(const Monitor *mon)
259 274
{
260 275
    return mon->error != NULL;
......
453 468
    }
454 469
}
455 470

  
471
static void user_monitor_complete(void *opaque, QObject *ret_data)
472
{
473
    MonitorCompletionData *data = (MonitorCompletionData *)opaque; 
474

  
475
    if (ret_data) {
476
        data->user_print(data->mon, ret_data);
477
    }
478
    monitor_resume(data->mon);
479
    qemu_free(data);
480
}
481

  
482
static void qmp_monitor_complete(void *opaque, QObject *ret_data)
483
{
484
    monitor_protocol_emitter(opaque, ret_data);
485
}
486

  
487
static void qmp_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
488
                                  const QDict *params)
489
{
490
    cmd->mhandler.cmd_async(mon, params, qmp_monitor_complete, mon);
491
}
492

  
493
static void qmp_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
494
{
495
    cmd->mhandler.info_async(mon, qmp_monitor_complete, mon);
496
}
497

  
498
static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
499
                                   const QDict *params)
500
{
501
    int ret;
502

  
503
    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
504
    cb_data->mon = mon;
505
    cb_data->user_print = cmd->user_print;
506
    monitor_suspend(mon);
507
    ret = cmd->mhandler.cmd_async(mon, params,
508
                                  user_monitor_complete, cb_data);
509
    if (ret < 0) {
510
        monitor_resume(mon);
511
        qemu_free(cb_data);
512
    }
513
}
514

  
515
static void user_async_info_handler(Monitor *mon, const mon_cmd_t *cmd)
516
{
517
    int ret;
518

  
519
    MonitorCompletionData *cb_data = qemu_malloc(sizeof(*cb_data));
520
    cb_data->mon = mon;
521
    cb_data->user_print = cmd->user_print;
522
    monitor_suspend(mon);
523
    ret = cmd->mhandler.info_async(mon, user_monitor_complete, cb_data);
524
    if (ret < 0) {
525
        monitor_resume(mon);
526
        qemu_free(cb_data);
527
    }
528
}
529

  
456 530
static void do_info(Monitor *mon, const QDict *qdict, QObject **ret_data)
457 531
{
458 532
    const mon_cmd_t *cmd;
......
476 550
        goto help;
477 551
    }
478 552

  
479
    if (monitor_handler_ported(cmd)) {
553
    if (monitor_handler_is_async(cmd)) {
554
        if (monitor_ctrl_mode(mon)) {
555
            qmp_async_info_handler(mon, cmd);
556
        } else {
557
            user_async_info_handler(mon, cmd);
558
        }
559
        /*
560
         * Indicate that this command is asynchronous and will not return any
561
         * data (not even empty).  Instead, the data will be returned via a
562
         * completion callback.
563
         */
564
        *ret_data = qobject_from_jsonf("{ '__mon_async': 'return' }");
565
    } else if (monitor_handler_ported(cmd)) {
480 566
        cmd->mhandler.info_new(mon, ret_data);
481 567

  
482 568
        if (!monitor_ctrl_mode(mon)) {
......
3588 3674
    mon->error = NULL;
3589 3675
}
3590 3676

  
3677
static int is_async_return(const QObject *data)
3678
{
3679
    return data && qdict_haskey(qobject_to_qdict(data), "__mon_async");
3680
}
3681

  
3591 3682
static void monitor_call_handler(Monitor *mon, const mon_cmd_t *cmd,
3592 3683
                                 const QDict *params)
3593 3684
{
......
3595 3686

  
3596 3687
    cmd->mhandler.cmd_new(mon, params, &data);
3597 3688

  
3598
    if (monitor_ctrl_mode(mon)) {
3689
    if (is_async_return(data)) {
3690
        /*
3691
         * Asynchronous commands have no initial return data but they can
3692
         * generate errors.  Data is returned via the async completion handler.
3693
         */
3694
        if (monitor_ctrl_mode(mon) && monitor_has_error(mon)) {
3695
            monitor_protocol_emitter(mon, NULL);
3696
        }
3697
    } else if (monitor_ctrl_mode(mon)) {
3599 3698
        /* Monitor Protocol */
3600 3699
        monitor_protocol_emitter(mon, data);
3601 3700
    } else {
......
3620 3719

  
3621 3720
    qemu_errors_to_mon(mon);
3622 3721

  
3623
    if (monitor_handler_ported(cmd)) {
3722
    if (monitor_handler_is_async(cmd)) {
3723
        user_async_cmd_handler(mon, cmd, qdict);
3724
    } else if (monitor_handler_ported(cmd)) {
3624 3725
        monitor_call_handler(mon, cmd, qdict);
3625 3726
    } else {
3626 3727
        cmd->mhandler.cmd(mon, qdict);
......
4082 4183
        goto err_out;
4083 4184
    }
4084 4185

  
4085
    monitor_call_handler(mon, cmd, args);
4186
    if (monitor_handler_is_async(cmd)) {
4187
        qmp_async_cmd_handler(mon, cmd, args);
4188
    } else {
4189
        monitor_call_handler(mon, cmd, args);
4190
    }
4086 4191
    goto out;
4087 4192

  
4088 4193
err_input:
b/monitor.h
44 44
void monitor_print_filename(Monitor *mon, const char *filename);
45 45
void monitor_flush(Monitor *mon);
46 46

  
47
typedef void (MonitorCompletion)(void *opaque, QObject *ret_data);
48

  
47 49
#endif /* !MONITOR_H */

Also available in: Unified diff