diff --git a/devicemodel/core/cmd_monitor/cmd_monitor.c b/devicemodel/core/cmd_monitor/cmd_monitor.c index 44c8c87d2..1db13e67a 100644 --- a/devicemodel/core/cmd_monitor/cmd_monitor.c +++ b/devicemodel/core/cmd_monitor/cmd_monitor.c @@ -99,6 +99,7 @@ static void register_socket_message_handlers(struct vmctx *ctx) arg.ctx_arg = ctx; register_command_handler(user_vm_destroy_handler, &arg, DESTROY); register_command_handler(user_vm_blkrescan_handler, &arg, BLKRESCAN); + register_command_handler(user_vm_register_vm_event_client_handler, &arg, REGISTER_VM_EVENT_CLIENT); } int init_cmd_monitor(struct vmctx *ctx) diff --git a/devicemodel/core/cmd_monitor/command.c b/devicemodel/core/cmd_monitor/command.c index 979ec852c..ae6b17064 100644 --- a/devicemodel/core/cmd_monitor/command.c +++ b/devicemodel/core/cmd_monitor/command.c @@ -26,6 +26,7 @@ #define CMD_OBJS \ GEN_CMD_OBJ(DESTROY), \ GEN_CMD_OBJ(BLKRESCAN), \ + GEN_CMD_OBJ(REGISTER_VM_EVENT_CLIENT), \ struct command dm_command_list[CMDS_NUM] = {CMD_OBJS}; diff --git a/devicemodel/core/cmd_monitor/command.h b/devicemodel/core/cmd_monitor/command.h index 12e4a9145..a8145df89 100644 --- a/devicemodel/core/cmd_monitor/command.h +++ b/devicemodel/core/cmd_monitor/command.h @@ -10,8 +10,9 @@ #define DESTROY "destroy" #define BLKRESCAN "blkrescan" +#define REGISTER_VM_EVENT_CLIENT "register_vm_event_client" -#define CMDS_NUM 2U +#define CMDS_NUM 3U #define CMD_NAME_MAX 32U #define CMD_ARG_MAX 320U diff --git a/devicemodel/core/cmd_monitor/command_handler.c b/devicemodel/core/cmd_monitor/command_handler.c index d85d070c1..a87aa7b8b 100644 --- a/devicemodel/core/cmd_monitor/command_handler.c +++ b/devicemodel/core/cmd_monitor/command_handler.c @@ -67,6 +67,78 @@ static int send_socket_ack(struct socket_dev *sock, int fd, bool normal) return ret; } +static struct socket_client *vm_event_client = NULL; +static pthread_mutex_t vm_event_client_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void vm_event_free_cb(struct socket_client *self) +{ + vm_event_client = NULL; +} + +static int set_vm_event_client(struct socket_client *client) +{ + if (vm_event_client != NULL) { + pr_err("vm event client already registerred.\n"); + return -1; + } else { + vm_event_client = client; + client->per_client_mutex = &vm_event_client_mutex; + client->free_client_cb = vm_event_free_cb; + return 0; + } +} + +int vm_monitor_send_vm_event(const char *msg) +{ + int ret = -1; + struct socket_client *client; + pthread_mutex_t *per_client_mutex = &vm_event_client_mutex; + + pthread_mutex_lock(per_client_mutex); + client = vm_event_client; + if (msg == NULL || client == NULL) { + pthread_mutex_unlock(per_client_mutex); + return -1; + } + memset(client->buf, 0, CLIENT_BUF_LEN); + memcpy(client->buf, msg, strlen(msg)); + client->len = strlen(msg); + ret = write_socket_char(client); + pthread_mutex_unlock(per_client_mutex); + return ret; +} + +/* When a client issues the REGISTER_VM_EVENT_CLIENT command, + * this handler will register that client as this VM's only vm_event receiver, + * and keeps the socket connection. Then vm events will be sent to + * the client through this connection. + */ +int user_vm_register_vm_event_client_handler(void *arg, void *command_para) +{ + int ret; + struct command_parameters *cmd_para = (struct command_parameters *)command_para; + struct handler_args *hdl_arg = (struct handler_args *)arg; + struct socket_dev *sock = (struct socket_dev *)hdl_arg->channel_arg; + struct socket_client *client = NULL; + bool cmd_completed = false; + + client = find_socket_client(sock, cmd_para->fd); + if (client == NULL) + return -1; + + if (set_vm_event_client(client) == 0) { + cmd_completed = true; + } + + pr_dbg("%s: client with fd %d registerred\n", __func__, client->fd); + + ret = send_socket_ack(sock, cmd_para->fd, cmd_completed); + if (ret < 0) { + pr_err("%s: Failed to send ACK message by socket.\n", __func__); + } + return ret; +} + int user_vm_destroy_handler(void *arg, void *command_para) { int ret; diff --git a/devicemodel/core/cmd_monitor/command_handler.h b/devicemodel/core/cmd_monitor/command_handler.h index dcca658a3..2917207fb 100644 --- a/devicemodel/core/cmd_monitor/command_handler.h +++ b/devicemodel/core/cmd_monitor/command_handler.h @@ -9,4 +9,6 @@ extern struct socket_dev *sock_server; int user_vm_destroy_handler(void *arg, void *command_para); int user_vm_blkrescan_handler(void *arg, void *command_para); +int user_vm_register_vm_event_client_handler(void *arg, void *command_para); + #endif diff --git a/devicemodel/core/cmd_monitor/socket.c b/devicemodel/core/cmd_monitor/socket.c index b68953ef9..4983e3c20 100644 --- a/devicemodel/core/cmd_monitor/socket.c +++ b/devicemodel/core/cmd_monitor/socket.c @@ -47,13 +47,23 @@ err: } static void free_socket_client(struct socket_dev *sock, struct socket_client *client) { + pthread_mutex_t *per_client_mutex = client->per_client_mutex; pthread_mutex_lock(&sock->client_mtx); LIST_REMOVE(client, list); pthread_mutex_unlock(&sock->client_mtx); + if (per_client_mutex) { + pthread_mutex_lock(per_client_mutex); + } + if (client->free_client_cb) { + client->free_client_cb(client); + } close(client->fd); client->fd = -1; free(client); + if (per_client_mutex) { + pthread_mutex_unlock(per_client_mutex); + } } int write_socket_char(struct socket_client *client) @@ -142,7 +152,8 @@ static struct socket_client *new_socket_client(struct socket_dev *sock) __func__); goto alloc_client; } - + /* If per client mutex is needed, init in callback */ + client->per_client_mutex = NULL; client->addr_len = sizeof(client->addr); client->fd = accept(sock->sock_fd, (struct sockaddr *)&client->addr, @@ -153,7 +164,6 @@ static struct socket_client *new_socket_client(struct socket_dev *sock) __func__, sock->sock_fd, strerror(errno)); goto accept_con; } - pthread_mutex_lock(&sock->client_mtx); LIST_INSERT_HEAD(&sock->client_head, client, list); pthread_mutex_unlock(&sock->client_mtx); diff --git a/devicemodel/core/cmd_monitor/socket.h b/devicemodel/core/cmd_monitor/socket.h index b86b1f7d8..2dd92a371 100644 --- a/devicemodel/core/cmd_monitor/socket.h +++ b/devicemodel/core/cmd_monitor/socket.h @@ -21,7 +21,11 @@ struct socket_client { socklen_t addr_len; char buf[CLIENT_BUF_LEN]; int len; /* buf len */ - + /* When a client is registered as vm_event receiver, we need this per_client_mutex + * to make sure it is safe to free the client when client disconnects. + */ + pthread_mutex_t *per_client_mutex; + void (*free_client_cb)(struct socket_client *self); LIST_ENTRY(socket_client) list; }; diff --git a/devicemodel/include/monitor.h b/devicemodel/include/monitor.h index e6284f68c..0a390cee4 100644 --- a/devicemodel/include/monitor.h +++ b/devicemodel/include/monitor.h @@ -36,4 +36,7 @@ unsigned get_wakeup_reason(void); int set_wakeup_timer(time_t t); int acrn_parse_intr_monitor(const char *opt); int vm_monitor_blkrescan(void *arg, char *devargs); + +int vm_monitor_send_vm_event(const char *msg); + #endif