@@ -40,17 +40,137 @@ typedef struct AwdState {
char *awd_node;
char *notification_node;
char *opt_script;
+ char *opt_script_data;
uint32_t pulse_interval;
uint32_t timeout;
CharBackend chr_awd_node;
CharBackend chr_notification_node;
+ SocketReadState awd_rs;
+
+ QEMUTimer *pulse_timer;
+ QEMUTimer *timeout_timer;
IOThread *iothread;
+ GMainContext *worker_context;
} AwdState;
typedef struct AwdClass {
ObjectClass parent_class;
} AwdClass;
+static int awd_chr_send(AwdState *s,
+ const uint8_t *buf,
+ uint32_t size)
+{
+ int ret = 0;
+ uint32_t len = htonl(size);
+
+ if (!size) {
+ return 0;
+ }
+
+ ret = qemu_chr_fe_write_all(&s->chr_awd_node, (uint8_t *)&len,
+ sizeof(len));
+ if (ret != sizeof(len)) {
+ goto err;
+ }
+
+ ret = qemu_chr_fe_write_all(&s->chr_awd_node, (uint8_t *)buf,
+ size);
+ if (ret != size) {
+ goto err;
+ }
+
+ return 0;
+
+err:
+ return ret < 0 ? ret : -EIO;
+}
+
+static int awd_chr_can_read(void *opaque)
+{
+ return AWD_READ_LEN_MAX;
+}
+
+static void awd_node_in(void *opaque, const uint8_t *buf, int size)
+{
+ AwdState *s = AWD(opaque);
+ int ret;
+
+ ret = net_fill_rstate(&s->awd_rs, buf, size);
+ if (ret == -1) {
+ qemu_chr_fe_set_handlers(&s->chr_awd_node, NULL, NULL, NULL, NULL,
+ NULL, NULL, true);
+ error_report("advanced-watchdog get pulse error");
+ }
+}
+
+static void awd_send_pulse(void *opaque)
+{
+ AwdState *s = opaque;
+ char buf[] = "advanced-watchdog pulse";
+
+ awd_chr_send(s, (uint8_t *)buf, sizeof(buf));
+}
+
+static void awd_regular_pulse(void *opaque)
+{
+ AwdState *s = opaque;
+
+ awd_send_pulse(s);
+ timer_mod(s->pulse_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->pulse_interval);
+}
+
+static void awd_timeout(void *opaque)
+{
+ AwdState *s = opaque;
+ int ret = 0;
+
+ ret = qemu_chr_fe_write_all(&s->chr_notification_node,
+ (uint8_t *)s->opt_script_data,
+ strlen(s->opt_script_data));
+ if (ret) {
+ error_report("advanced-watchdog notification failure");
+ }
+}
+
+static void awd_timer_init(AwdState *s)
+{
+ AioContext *ctx = iothread_get_aio_context(s->iothread);
+
+ s->timeout_timer = aio_timer_new(ctx, QEMU_CLOCK_VIRTUAL, SCALE_MS,
+ awd_timeout, s);
+
+ s->pulse_timer = aio_timer_new(ctx, QEMU_CLOCK_VIRTUAL, SCALE_MS,
+ awd_regular_pulse, s);
+
+ if (!s->pulse_interval) {
+ s->pulse_interval = AWD_PULSE_INTERVAL_DEFAULT;
+ }
+
+ if (!s->timeout) {
+ s->timeout = AWD_TIMEOUT_DEFAULT;
+ }
+
+ timer_mod(s->pulse_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->pulse_interval);
+}
+
+static void awd_timer_del(AwdState *s)
+{
+ if (s->pulse_timer) {
+ timer_del(s->pulse_timer);
+ timer_free(s->pulse_timer);
+ s->pulse_timer = NULL;
+ }
+
+ if (s->timeout_timer) {
+ timer_del(s->timeout_timer);
+ timer_free(s->timeout_timer);
+ s->timeout_timer = NULL;
+ }
+ }
+
static char *awd_get_node(Object *obj, Error **errp)
{
AwdState *s = AWD(obj);
@@ -177,6 +297,22 @@ out:
error_propagate(errp, local_err);
}
+static void awd_rs_finalize(SocketReadState *awd_rs)
+{
+ AwdState *s = container_of(awd_rs, AwdState, awd_rs);
+
+ if (!s->server) {
+ char buf[] = "advanced-watchdog reply pulse";
+
+ awd_chr_send(s, (uint8_t *)buf, sizeof(buf));
+ }
+
+ timer_mod(s->timeout_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) +
+ s->timeout);
+
+ error_report("advanced-watchdog got message : %s", awd_rs->buf);
+}
+
static int find_and_check_chardev(Chardev **chr,
char *chr_name,
Error **errp)
@@ -197,6 +333,46 @@ static int find_and_check_chardev(Chardev **chr,
return 0;
}
+static void awd_iothread(AwdState *s)
+{
+ object_ref(OBJECT(s->iothread));
+ s->worker_context = iothread_get_g_main_context(s->iothread);
+
+ qemu_chr_fe_set_handlers(&s->chr_awd_node, awd_chr_can_read,
+ awd_node_in, NULL, NULL,
+ s, s->worker_context, true);
+
+ awd_timer_init(s);
+}
+
+static int get_opt_script_data(AwdState *s)
+{
+ FILE *opt_fd;
+ long fsize;
+
+ opt_fd = fopen(s->opt_script, "r");
+ if (opt_fd == NULL) {
+ error_report("advanced-watchdog can't open "
+ "opt_script: %s", s->opt_script);
+ return -1;
+ }
+
+ fseek(opt_fd, 0, SEEK_END);
+ fsize = ftell(opt_fd);
+ fseek(opt_fd, 0, SEEK_SET);
+ s->opt_script_data = malloc(fsize + 1);
+
+ if (!fread(s->opt_script_data, 1, fsize, opt_fd)) {
+ error_report("advanced-watchdog can't read "
+ "opt_script: %s", s->opt_script);
+ return -1;
+ }
+
+ fclose(opt_fd);
+
+ return 0;
+}
+
static void awd_complete(UserCreatable *uc, Error **errp)
{
AwdState *s = AWD(uc);
@@ -224,6 +400,16 @@ static void awd_complete(UserCreatable *uc, Error **errp)
return;
}
+ if (get_opt_script_data(s)) {
+ error_setg(errp, "advanced-watchdog can't get "
+ "opt script data: %s", s->opt_script);
+ return;
+ }
+
+ net_socket_rs_init(&s->awd_rs, awd_rs_finalize, false);
+
+ awd_iothread(s);
+
return;
}
@@ -272,6 +458,13 @@ static void awd_finalize(Object *obj)
{
AwdState *s = AWD(obj);
+ qemu_chr_fe_deinit(&s->chr_awd_node, false);
+ qemu_chr_fe_deinit(&s->chr_notification_node, false);
+
+ if (s->iothread) {
+ awd_timer_del(s);
+ }
+
g_free(s->awd_node);
g_free(s->notification_node);
}