Message ID | 1498117132-27139-14-git-send-email-bhupinder.thakur@linaro.org |
---|---|
State | New |
Headers | show |
Series | SBSA UART emulation support in Xen | expand |
On Thu, 22 Jun 2017, Bhupinder Thakur wrote: > This patch adds the support for multiple consoles and introduces the iterator > functions to operate on multiple consoles. > > This patch is in preparation to support a new vuart console. > > Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org> > --- > CC: Ian Jackson <ian.jackson@eu.citrix.com> > CC: Wei Liu <wei.liu2@citrix.com> > CC: Stefano Stabellini <sstabellini@kernel.org> > CC: Julien Grall <julien.grall@arm.com> > > Changes since v4: > - Changes to make event channel handling per console rather than per domain. > > Changes since v3: > - The changes in xenconsole have been split into four patches. This is the third patch. > > tools/console/daemon/io.c | 435 ++++++++++++++++++++++++++++++++-------------- > 1 file changed, 302 insertions(+), 133 deletions(-) > > diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c > index a2a3496..baf0e2e 100644 > --- a/tools/console/daemon/io.c > +++ b/tools/console/daemon/io.c > @@ -90,12 +90,14 @@ struct buffer { > }; > > struct console { > + char *ttyname; > int master_fd; > int master_pollfd_idx; > int slave_fd; > int log_fd; > struct buffer buffer; > char *xspath; > + char *log_suffix; > int ring_ref; > xenevtchn_handle *xce_handle; > int xce_pollfd_idx; > @@ -107,16 +109,112 @@ struct console { > struct domain *d; > }; > > +struct console_data { > + char *xsname; > + char *ttyname; > + char *log_suffix; > +}; > + > +static struct console_data console_data[] = { > + > + { > + .xsname = "/console", > + .ttyname = "tty", > + .log_suffix = "", > + }, > +}; > + > +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data)) > + > struct domain { > int domid; > bool is_dead; > unsigned last_seen; > struct domain *next; > - struct console console; > + struct console console[MAX_CONSOLE]; > }; > > static struct domain *dom_head; > > +typedef void (*VOID_ITER_FUNC_ARG1)(struct console *); > +typedef bool (*BOOL_ITER_FUNC_ARG1)(struct console *); > +typedef int (*INT_ITER_FUNC_ARG1)(struct console *); > +typedef void (*VOID_ITER_FUNC_ARG2)(struct console *, void *); > +typedef int (*INT_ITER_FUNC_ARG3)(struct console *, > + struct domain *dom, void **); > + > +static inline bool console_enabled(struct console *con) > +{ > + return con->local_port != -1; > +} > + > +static inline void console_iter_void_arg1(struct domain *d, > + VOID_ITER_FUNC_ARG1 iter_func) > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + > + for (i = 0; i < MAX_CONSOLE; i++, con++) > + { > + iter_func(con); > + } > +} > + > +static inline void console_iter_void_arg2(struct domain *d, > + VOID_ITER_FUNC_ARG2 iter_func, > + void *iter_data) > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + > + for (i = 0; i < MAX_CONSOLE; i++, con++) > + { > + iter_func(con, iter_data); > + } > +} > + > +static inline bool console_iter_bool_arg1(struct domain *d, > + BOOL_ITER_FUNC_ARG1 iter_func) > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + > + for (i = 0; i < MAX_CONSOLE; i++, con++) > + { > + if (iter_func(con)) > + return true; > + } > + return false; > +} > + > +static inline int console_iter_int_arg1(struct domain *d, > + INT_ITER_FUNC_ARG1 iter_func) > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + > + for (i = 0; i < MAX_CONSOLE; i++, con++) > + { > + if (iter_func(con)) > + return 1; > + } > + return 0; > +} > + > +static inline int console_iter_int_arg3(struct domain *d, > + INT_ITER_FUNC_ARG3 iter_func, > + void **iter_data) > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + > + for (i = 0; i < MAX_CONSOLE; i++, con++) > + { > + if (iter_func(con, d, iter_data)) > + return 1; > + } > + return 0; > +} > static int write_all(int fd, const char* buf, size_t len) > { > while (len) { > @@ -163,12 +261,22 @@ static int write_with_timestamp(int fd, const char *data, size_t sz, > return 0; > } > > -static void buffer_append(struct console *con) > +static inline bool buffer_available(struct console *con) > +{ > + if (discard_overflowed_data || > + !con->buffer.max_capacity || > + con->buffer.size < con->buffer.max_capacity) > + return true; > + else > + return false; > +} > + > +static void buffer_append(struct console *con, xenevtchn_port_or_error_t port) > { it doesn't look like port is used anywhere here > struct buffer *buffer = &con->buffer; > + struct xencons_interface *intf = con->interface; > struct domain *dom = con->d; > XENCONS_RING_IDX cons, prod, size; > - struct xencons_interface *intf = con->interface; Spurious change? > cons = intf->out_cons; > prod = intf->out_prod; > @@ -321,7 +429,7 @@ static int create_console_log(struct console *con) > return -1; > } > > - snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data); > + snprintf(logfile, PATH_MAX-1, "%s/guest-%s%s.log", log_dir, data, con->log_suffix); > free(data); > logfile[PATH_MAX-1] = '\0'; > > @@ -473,7 +581,7 @@ static int console_create_tty(struct console *con) > } > free(path); > > - success = (asprintf(&path, "%s/tty", con->xspath) != -1); > + success = (asprintf(&path, "%s/%s", con->xspath, con->ttyname) != -1); > if (!success) > goto out; > success = xs_write(xs, XBT_NULL, path, slave, strlen(slave)); > @@ -594,6 +702,7 @@ static int console_create_ring(struct console *con) > > con->local_port = -1; > con->remote_port = -1; > + > if (con->xce_handle != NULL) > xenevtchn_close(con->xce_handle); Spurious change > @@ -639,13 +748,13 @@ static bool watch_domain(struct domain *dom, bool watch) > { > char domid_str[3 + MAX_STRLEN(dom->domid)]; > bool success; > - struct console *con = &dom->console; > + struct console *con = &dom->console[0]; > > snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid); > if (watch) { > success = xs_watch(xs, con->xspath, domid_str); > if (success) > - console_create_ring(con); > + console_iter_int_arg1(dom, console_create_ring); > else > xs_unwatch(xs, con->xspath, domid_str); > } else { > @@ -655,20 +764,59 @@ static bool watch_domain(struct domain *dom, bool watch) > return success; > } > > - > -static struct domain *create_domain(int domid) > +static int console_init(struct console *con, struct domain *dom, void **data) > { > - struct domain *dom; > char *s; > + int err = -1; > struct timespec ts; > - struct console *con; > + struct console_data **con_data = (struct console_data **)data; > + char *xsname; > > if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { > dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", > __FILE__, __FUNCTION__, __LINE__); > - return NULL; > + return err; > + } > + > + con->master_fd = -1; > + con->master_pollfd_idx = -1; > + con->slave_fd = -1; > + con->log_fd = -1; > + con->ring_ref = -1; > + con->local_port = -1; > + con->remote_port = -1; > + con->xce_pollfd_idx = -1; > + con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; > + con->d = dom; > + con->ttyname = (*con_data)->ttyname; > + con->log_suffix = (*con_data)->log_suffix; > + xsname = (*con_data)->xsname; > + con->xspath = xs_get_domain_path(xs, dom->domid); > + s = realloc(con->xspath, strlen(con->xspath) + > + strlen(xsname) + 1); > + if (s) > + { > + con->xspath = s; > + strcat(con->xspath, xsname); > + err = 0; > } > > + (*con_data)++; > + > + return err; > +} > + > +static void console_free(struct console *con) > +{ > + if (con->xspath) > + free(con->xspath); > +} > + > +static struct domain *create_domain(int domid) > +{ > + struct domain *dom; > + struct console_data *con_data = &console_data[0]; > + > dom = calloc(1, sizeof *dom); > if (dom == NULL) { > dolog(LOG_ERR, "Out of memory %s:%s():L%d", > @@ -678,27 +826,8 @@ static struct domain *create_domain(int domid) > > dom->domid = domid; > > - con = &dom->console; > - con->xspath = xs_get_domain_path(xs, dom->domid); > - s = realloc(con->xspath, strlen(con->xspath) + > - strlen("/console") + 1); > - if (s == NULL) > + if (console_iter_int_arg3(dom, console_init, (void **)&con_data)) > goto out; > - con->xspath = s; > - strcat(con->xspath, "/console"); > - > - con->master_fd = -1; > - con->master_pollfd_idx = -1; > - con->slave_fd = -1; > - con->log_fd = -1; > - con->xce_pollfd_idx = -1; > - con->d = dom; > - > - con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; > - > - con->ring_ref = -1; > - con->local_port = -1; > - con->remote_port = -1; > > if (!watch_domain(dom, true)) > goto out; > @@ -710,7 +839,7 @@ static struct domain *create_domain(int domid) > > return dom; > out: > - free(con->xspath); > + console_iter_void_arg1(dom, console_free); > free(dom); > return NULL; > } > @@ -740,38 +869,51 @@ static void remove_domain(struct domain *dom) > } > } > > -static void cleanup_domain(struct domain *d) > +static void console_cleanup(struct console *con) > { > - struct console *con = &d->console; > - > - console_close_tty(con); > - > if (con->log_fd != -1) { > close(con->log_fd); > con->log_fd = -1; > } > > - free(con->buffer.data); > - con->buffer.data = NULL; > + if (con->buffer.data) > + { > + free(con->buffer.data); > + con->buffer.data = NULL; > + } > + > + if (con->xspath) > + { > + free(con->xspath); > + con->xspath = NULL; > + } > +} > + > +static void cleanup_domain(struct domain *d) > +{ > + console_iter_void_arg1(d, console_close_tty); > > - free(con->xspath); > - con->xspath = NULL; > + console_iter_void_arg1(d, console_cleanup); > > remove_domain(d); > } > > -static void shutdown_domain(struct domain *d) > +static void console_close_evtchn(struct console *con) > { > - struct console *con = &d->console; > - > - d->is_dead = true; > - watch_domain(d, false); > - console_unmap_interface(con); > if (con->xce_handle != NULL) > xenevtchn_close(con->xce_handle); > + > con->xce_handle = NULL; > } > > +static void shutdown_domain(struct domain *d) > +{ > + d->is_dead = true; > + watch_domain(d, false); > + console_iter_void_arg1(d, console_unmap_interface); > + console_iter_void_arg1(d, console_close_evtchn); > +} > + > static unsigned enum_pass = 0; > > static void enum_domains(void) > @@ -885,12 +1027,32 @@ static void handle_tty_write(struct console *con) > } > } > > -static void handle_ring_read(struct domain *dom) > +static void console_evtchn_unmask(struct console *con, void *data) > +{ > + long long now = (long long)data; > + > + if (!console_enabled(con)) > + return; > + > + /* CS 16257:955ee4fa1345 introduces a 5ms fuzz > + * for select(), it is not clear poll() has > + * similar behavior (returning a couple of ms > + * sooner than requested) as well. Just leave > + * the fuzz here. Remove it with a separate > + * patch if necessary */ > + if ((now+5) > con->next_period) { > + con->next_period = now + RATE_LIMIT_PERIOD; > + if (con->event_count >= RATE_LIMIT_ALLOWANCE) > + (void)xenevtchn_unmask(con->xce_handle, con->local_port); > + con->event_count = 0; > + } > +} > + > +static void handle_ring_read(struct console *con) > { > xenevtchn_port_or_error_t port; > - struct console *con = &dom->console; > > - if (dom->is_dead) > + if (con->d->is_dead) > return; > > if ((port = xenevtchn_pending(con->xce_handle)) == -1) > @@ -898,10 +1060,23 @@ static void handle_ring_read(struct domain *dom) > > con->event_count++; > > - buffer_append(con); > + buffer_append(con, port); > > if (con->event_count < RATE_LIMIT_ALLOWANCE) > - (void)xenevtchn_unmask(con->xce_handle, port); > + (void)xenevtchn_unmask(con->xce_handle, con->local_port); > +} > + > +static void handle_console_ring(struct console *con) > +{ > + if (con->event_count < RATE_LIMIT_ALLOWANCE) { > + if (con->xce_handle != NULL && > + con->xce_pollfd_idx != -1 && > + !(fds[con->xce_pollfd_idx].revents & > + ~(POLLIN|POLLOUT|POLLPRI)) && > + (fds[con->xce_pollfd_idx].revents & > + POLLIN)) > + handle_ring_read(con); > + } > } > > static void handle_xs(void) > @@ -922,7 +1097,7 @@ static void handle_xs(void) > /* We may get watches firing for domains that have recently > been removed, so dom may be NULL here. */ > if (dom && dom->is_dead == false) > - console_create_ring(&dom->console); > + console_iter_int_arg1(dom, console_create_ring); > } > > free(vec); > @@ -963,16 +1138,22 @@ static void handle_hv_logs(xenevtchn_handle *xce_handle, bool force) > (void)xenevtchn_unmask(xce_handle, port); > } > > +static void console_open_log(struct console *con) > +{ > + if (console_enabled(con)) > + { > + if (con->log_fd != -1) > + close(con->log_fd); > + con->log_fd = create_console_log(con); > + } > +} > + > static void handle_log_reload(void) > { > if (log_guest) { > struct domain *d; > for (d = dom_head; d; d = d->next) { > - struct console *con = &d->console; > - > - if (con->log_fd != -1) > - close(con->log_fd); > - con->log_fd = create_console_log(con); > + console_iter_void_arg1(d, console_open_log); > } > } > > @@ -1024,6 +1205,62 @@ static void reset_fds(void) > memset(fds, 0, sizeof(struct pollfd) * current_array_size); > } > > +static void add_console_evtchn_fd(struct console *con, void *data) > +{ > + long long next_timeout = *((long long *)data); > + > + if (con->event_count >= RATE_LIMIT_ALLOWANCE) { > + /* Determine if we're going to be the next time slice to expire */ > + if (!next_timeout || > + con->next_period < next_timeout) > + next_timeout = con->next_period; > + } else if (con->xce_handle != NULL) { > + if (buffer_available(con)) > + { > + int evtchn_fd = xenevtchn_fd(con->xce_handle); > + con->xce_pollfd_idx = set_fds(evtchn_fd, > + POLLIN|POLLPRI); > + } > + } > + > + *((long long *)data) = next_timeout; > +} > + > +static void add_console_tty_fd(struct console *con) > +{ > + if (con->master_fd != -1) { > + short events = 0; > + if (!con->d->is_dead && ring_free_bytes(con)) > + events |= POLLIN; > + > + if (!buffer_empty(&con->buffer)) > + events |= POLLOUT; > + > + if (events) > + con->master_pollfd_idx = > + set_fds(con->master_fd, events|POLLPRI); > + } > +} > + > +static void handle_console_tty(struct console *con) > +{ > + if (con->master_fd != -1 && con->master_pollfd_idx != -1) { > + if (fds[con->master_pollfd_idx].revents & > + ~(POLLIN|POLLOUT|POLLPRI)) > + console_handle_broken_tty(con, domain_is_valid(con->d->domid)); > + else { > + if (fds[con->master_pollfd_idx].revents & > + POLLIN) > + handle_tty_read(con); > + if (fds[con->master_pollfd_idx].revents & > + POLLOUT) > + handle_tty_write(con); > + } > + } > + con->master_pollfd_idx = -1; > + con->xce_pollfd_idx = -1; > +} > + > void handle_io(void) > { > int ret; > @@ -1081,55 +1318,11 @@ void handle_io(void) > /* Re-calculate any event counter allowances & unblock > domains with new allowance */ > for (d = dom_head; d; d = d->next) { > - struct console *con = &d->console; > - > - /* CS 16257:955ee4fa1345 introduces a 5ms fuzz > - * for select(), it is not clear poll() has > - * similar behavior (returning a couple of ms > - * sooner than requested) as well. Just leave > - * the fuzz here. Remove it with a separate > - * patch if necessary */ > - if ((now+5) > con->next_period) { > - con->next_period = now + RATE_LIMIT_PERIOD; > - if (con->event_count >= RATE_LIMIT_ALLOWANCE) { > - (void)xenevtchn_unmask(con->xce_handle, con->local_port); > - } > - con->event_count = 0; > - } > - } > > - for (d = dom_head; d; d = d->next) { > - struct console *con = &d->console; > - > - if (con->event_count >= RATE_LIMIT_ALLOWANCE) { > - /* Determine if we're going to be the next time slice to expire */ > - if (!next_timeout || > - con->next_period < next_timeout) > - next_timeout = con->next_period; > - } else if (con->xce_handle != NULL) { > - if (discard_overflowed_data || > - !con->buffer.max_capacity || > - con->buffer.size < con->buffer.max_capacity) { > - int evtchn_fd = xenevtchn_fd(con->xce_handle); > - con->xce_pollfd_idx = set_fds(evtchn_fd, > - POLLIN|POLLPRI); > - } > - } > - > - if (con->master_fd != -1) { > - short events = 0; > - if (!d->is_dead && ring_free_bytes(con)) > - events |= POLLIN; > - > - if (!buffer_empty(&con->buffer)) > - events |= POLLOUT; > - > - if (events) > - con->master_pollfd_idx = > - set_fds(con->master_fd, > - events|POLLPRI); > - } > - } > + console_iter_void_arg2(d, console_evtchn_unmask, (void *)now); > + console_iter_void_arg2(d, add_console_evtchn_fd, (void *)&next_timeout); > + console_iter_void_arg1(d, add_console_tty_fd); > + } > > /* If any domain has been rate limited, we need to work > out what timeout to supply to poll */ > @@ -1189,35 +1382,11 @@ void handle_io(void) > } > > for (d = dom_head; d; d = n) { > - struct console *con = &d->console; > > n = d->next; > - if (con->event_count < RATE_LIMIT_ALLOWANCE) { > - if (con->xce_handle != NULL && > - con->xce_pollfd_idx != -1 && > - !(fds[con->xce_pollfd_idx].revents & > - ~(POLLIN|POLLOUT|POLLPRI)) && > - (fds[con->xce_pollfd_idx].revents & > - POLLIN)) > - handle_ring_read(d); > - } > - > - if (con->master_fd != -1 && con->master_pollfd_idx != -1) { > - if (fds[con->master_pollfd_idx].revents & > - ~(POLLIN|POLLOUT|POLLPRI)) > - console_handle_broken_tty(con, > - domain_is_valid(d->domid)); > - else { > - if (fds[con->master_pollfd_idx].revents & > - POLLIN) > - handle_tty_read(con); > - if (fds[con->master_pollfd_idx].revents & > - POLLOUT) > - handle_tty_write(con); > - } > - } > > - con->xce_pollfd_idx = con->master_pollfd_idx = -1; > + console_iter_void_arg1(d, handle_console_ring); > + console_iter_void_arg1(d, handle_console_tty); > > if (d->last_seen != enum_pass) > shutdown_domain(d); > -- > 2.7.4 >
On Thu, Jun 22, 2017 at 01:08:48PM +0530, Bhupinder Thakur wrote: > This patch adds the support for multiple consoles and introduces the iterator > functions to operate on multiple consoles. > > This patch is in preparation to support a new vuart console. > > Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org> > --- > CC: Ian Jackson <ian.jackson@eu.citrix.com> > CC: Wei Liu <wei.liu2@citrix.com> > CC: Stefano Stabellini <sstabellini@kernel.org> > CC: Julien Grall <julien.grall@arm.com> > > Changes since v4: > - Changes to make event channel handling per console rather than per domain. > > Changes since v3: > - The changes in xenconsole have been split into four patches. This is the third patch. > > tools/console/daemon/io.c | 435 ++++++++++++++++++++++++++++++++-------------- > 1 file changed, 302 insertions(+), 133 deletions(-) > > diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c > index a2a3496..baf0e2e 100644 > --- a/tools/console/daemon/io.c > +++ b/tools/console/daemon/io.c > @@ -90,12 +90,14 @@ struct buffer { > }; > > struct console { > + char *ttyname; > int master_fd; > int master_pollfd_idx; > int slave_fd; > int log_fd; > struct buffer buffer; > char *xspath; > + char *log_suffix; I suppose both new fields can be const. > int ring_ref; > xenevtchn_handle *xce_handle; > int xce_pollfd_idx; > @@ -107,16 +109,112 @@ struct console { > struct domain *d; > }; > > +struct console_data { > + char *xsname; > + char *ttyname; > + char *log_suffix; const for all three. > +}; > + > +static struct console_data console_data[] = { > + Stray line. > + { > + .xsname = "/console", > + .ttyname = "tty", > + .log_suffix = "", > + }, > +}; > + > +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data)) > + > struct domain { > int domid; > bool is_dead; > unsigned last_seen; > struct domain *next; > - struct console console; > + struct console console[MAX_CONSOLE]; > }; > > static struct domain *dom_head; > > +typedef void (*VOID_ITER_FUNC_ARG1)(struct console *); > +typedef bool (*BOOL_ITER_FUNC_ARG1)(struct console *); > +typedef int (*INT_ITER_FUNC_ARG1)(struct console *); > +typedef void (*VOID_ITER_FUNC_ARG2)(struct console *, void *); > +typedef int (*INT_ITER_FUNC_ARG3)(struct console *, > + struct domain *dom, void **); > + > +static inline bool console_enabled(struct console *con) > +{ > + return con->local_port != -1; > +} > + > +static inline void console_iter_void_arg1(struct domain *d, > + VOID_ITER_FUNC_ARG1 iter_func) Too many tabs here and below? You might want to configure your editor to display tab as 8 spaces. > +{ > + int i = 0; > + struct console *con = &(d->console[0]); > + No need to have the (), I think. > -static struct domain *create_domain(int domid) > +static int console_init(struct console *con, struct domain *dom, void **data) > { > - struct domain *dom; > char *s; > + int err = -1; > struct timespec ts; > - struct console *con; > + struct console_data **con_data = (struct console_data **)data; > + char *xsname; > > if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { > dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", > __FILE__, __FUNCTION__, __LINE__); > - return NULL; > + return err; > + } > + There is a danger that you return at this point, the cleanup path in caller will free garbage. I suggest you at least initialise all pointers to NULL at the beginning. > + con->master_fd = -1; > + con->master_pollfd_idx = -1; > + con->slave_fd = -1; > + con->log_fd = -1; > + con->ring_ref = -1; > + con->local_port = -1; > + con->remote_port = -1; > + con->xce_pollfd_idx = -1; > + con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; > + con->d = dom; > + con->ttyname = (*con_data)->ttyname; > + con->log_suffix = (*con_data)->log_suffix; > + xsname = (*con_data)->xsname; > + con->xspath = xs_get_domain_path(xs, dom->domid); > + s = realloc(con->xspath, strlen(con->xspath) + > + strlen(xsname) + 1); > + if (s) > + { > + con->xspath = s; > + strcat(con->xspath, xsname); > + err = 0; > } > > + (*con_data)++; > + > + return err; > +} > + > + [...] > +static void handle_console_ring(struct console *con) > +{ > + if (con->event_count < RATE_LIMIT_ALLOWANCE) { > + if (con->xce_handle != NULL && > + con->xce_pollfd_idx != -1 && > + !(fds[con->xce_pollfd_idx].revents & > + ~(POLLIN|POLLOUT|POLLPRI)) && > + (fds[con->xce_pollfd_idx].revents & > + POLLIN)) > + handle_ring_read(con); > + } Refactoring like this should go to its own patch(es). It is currently very hard to review this patch because refactoring is mixed with all the iterator changes. I can't really continue at this point. Sorry. Please split the refactoring of all the buffer_* and handle_console_* functions to separate patches.
Hi Wei, >> >> struct console { >> + char *ttyname; >> int master_fd; >> int master_pollfd_idx; >> int slave_fd; >> int log_fd; >> struct buffer buffer; >> char *xspath; >> + char *log_suffix; > > I suppose both new fields can be const. ok. I will make all the new fields as const char *const. > >> int ring_ref; >> xenevtchn_handle *xce_handle; >> int xce_pollfd_idx; >> @@ -107,16 +109,112 @@ struct console { >> struct domain *d; >> }; >> >> +struct console_data { >> + char *xsname; >> + char *ttyname; >> + char *log_suffix; > > const for all three. ok. > >> +static inline void console_iter_void_arg1(struct domain *d, >> + VOID_ITER_FUNC_ARG1 iter_func) > > Too many tabs here and below? > > You might want to configure your editor to display tab as 8 spaces. I have set my editor to use 8 spaces for a tab. I will fix these misalignments. > >> +{ >> + int i = 0; >> + struct console *con = &(d->console[0]); >> + > > No need to have the (), I think. ok. > >> -static struct domain *create_domain(int domid) >> +static int console_init(struct console *con, struct domain *dom, void **data) >> { >> - struct domain *dom; >> char *s; >> + int err = -1; >> struct timespec ts; >> - struct console *con; >> + struct console_data **con_data = (struct console_data **)data; >> + char *xsname; >> >> if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { >> dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", >> __FILE__, __FUNCTION__, __LINE__); >> - return NULL; >> + return err; >> + } >> + > > There is a danger that you return at this point, the cleanup path in > caller will free garbage. > > I suggest you at least initialise all pointers to NULL at the beginning. > I am checking that the pointer is not null before freeing them. >> + con->master_fd = -1; >> + con->master_pollfd_idx = -1; >> + con->slave_fd = -1; >> + con->log_fd = -1; >> + con->ring_ref = -1; >> + con->local_port = -1; >> + con->remote_port = -1; >> + con->xce_pollfd_idx = -1; >> + con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; >> + con->d = dom; >> + con->ttyname = (*con_data)->ttyname; >> + con->log_suffix = (*con_data)->log_suffix; >> + xsname = (*con_data)->xsname; >> + con->xspath = xs_get_domain_path(xs, dom->domid); >> + s = realloc(con->xspath, strlen(con->xspath) + >> + strlen(xsname) + 1); >> + if (s) >> + { >> + con->xspath = s; >> + strcat(con->xspath, xsname); >> + err = 0; >> } >> >> + (*con_data)++; >> + >> + return err; >> +} >> + >> + > [...] >> +static void handle_console_ring(struct console *con) >> +{ >> + if (con->event_count < RATE_LIMIT_ALLOWANCE) { >> + if (con->xce_handle != NULL && >> + con->xce_pollfd_idx != -1 && >> + !(fds[con->xce_pollfd_idx].revents & >> + ~(POLLIN|POLLOUT|POLLPRI)) && >> + (fds[con->xce_pollfd_idx].revents & >> + POLLIN)) >> + handle_ring_read(con); >> + } > > Refactoring like this should go to its own patch(es). > > It is currently very hard to review this patch because refactoring is > mixed with all the iterator changes. > > I can't really continue at this point. Sorry. Please split the > refactoring of all the buffer_* and handle_console_* functions to > separate patches. I have split the changes such that each new function and the related changes appear in one patch. Regards, Bhupinder
On Fri, Jul 07, 2017 at 07:22:14PM +0530, Bhupinder Thakur wrote: > >> -static struct domain *create_domain(int domid) > >> +static int console_init(struct console *con, struct domain *dom, void **data) > >> { > >> - struct domain *dom; > >> char *s; > >> + int err = -1; > >> struct timespec ts; > >> - struct console *con; > >> + struct console_data **con_data = (struct console_data **)data; > >> + char *xsname; > >> > >> if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { > >> dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", > >> __FILE__, __FUNCTION__, __LINE__); > >> - return NULL; > >> + return err; > >> + } > >> + > > > > There is a danger that you return at this point, the cleanup path in > > caller will free garbage. > > > > I suggest you at least initialise all pointers to NULL at the beginning. > > > I am checking that the pointer is not null before freeing them. > I'm not sure what your reply means. Without initialising the pointers to NULL you can have garbage in your pointer (currently only xspath) -- you end up freeing the garbage pointer. That's why I made the suggestion in the first place. Checking NULL isn't going to help that.
Hi Wei, On 7 July 2017 at 19:30, Wei Liu <wei.liu2@citrix.com> wrote: > On Fri, Jul 07, 2017 at 07:22:14PM +0530, Bhupinder Thakur wrote: >> >> -static struct domain *create_domain(int domid) >> >> +static int console_init(struct console *con, struct domain *dom, void **data) >> >> { >> >> - struct domain *dom; >> >> char *s; >> >> + int err = -1; >> >> struct timespec ts; >> >> - struct console *con; >> >> + struct console_data **con_data = (struct console_data **)data; >> >> + char *xsname; >> >> >> >> if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { >> >> dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", >> >> __FILE__, __FUNCTION__, __LINE__); >> >> - return NULL; >> >> + return err; >> >> + } >> >> + >> > >> > There is a danger that you return at this point, the cleanup path in >> > caller will free garbage. >> > >> > I suggest you at least initialise all pointers to NULL at the beginning. >> > >> I am checking that the pointer is not null before freeing them. >> > > I'm not sure what your reply means. > > Without initialising the pointers to NULL you can have garbage in your > pointer (currently only xspath) -- you end up freeing the garbage > pointer. That's why I made the suggestion in the first place. Checking > NULL isn't going to help that. I believe when domain structure is allocated it is initialized with 0 (as calloc is used for allocation) so all fields in the domain and console structures should be NULL. Regards, Bhupinder
On Fri, Jul 07, 2017 at 07:49:32PM +0530, Bhupinder Thakur wrote: > Hi Wei, > > On 7 July 2017 at 19:30, Wei Liu <wei.liu2@citrix.com> wrote: > > On Fri, Jul 07, 2017 at 07:22:14PM +0530, Bhupinder Thakur wrote: > >> >> -static struct domain *create_domain(int domid) > >> >> +static int console_init(struct console *con, struct domain *dom, void **data) > >> >> { > >> >> - struct domain *dom; > >> >> char *s; > >> >> + int err = -1; > >> >> struct timespec ts; > >> >> - struct console *con; > >> >> + struct console_data **con_data = (struct console_data **)data; > >> >> + char *xsname; > >> >> > >> >> if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { > >> >> dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", > >> >> __FILE__, __FUNCTION__, __LINE__); > >> >> - return NULL; > >> >> + return err; > >> >> + } > >> >> + > >> > > >> > There is a danger that you return at this point, the cleanup path in > >> > caller will free garbage. > >> > > >> > I suggest you at least initialise all pointers to NULL at the beginning. > >> > > >> I am checking that the pointer is not null before freeing them. > >> > > > > I'm not sure what your reply means. > > > > Without initialising the pointers to NULL you can have garbage in your > > pointer (currently only xspath) -- you end up freeing the garbage > > pointer. That's why I made the suggestion in the first place. Checking > > NULL isn't going to help that. > > I believe when domain structure is allocated it is initialized with 0 > (as calloc is used for allocation) so all fields > in the domain and console structures should be NULL. > OK in that case it is fine. Misread part of your patch.
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index a2a3496..baf0e2e 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -90,12 +90,14 @@ struct buffer { }; struct console { + char *ttyname; int master_fd; int master_pollfd_idx; int slave_fd; int log_fd; struct buffer buffer; char *xspath; + char *log_suffix; int ring_ref; xenevtchn_handle *xce_handle; int xce_pollfd_idx; @@ -107,16 +109,112 @@ struct console { struct domain *d; }; +struct console_data { + char *xsname; + char *ttyname; + char *log_suffix; +}; + +static struct console_data console_data[] = { + + { + .xsname = "/console", + .ttyname = "tty", + .log_suffix = "", + }, +}; + +#define MAX_CONSOLE (sizeof(console_data)/sizeof(struct console_data)) + struct domain { int domid; bool is_dead; unsigned last_seen; struct domain *next; - struct console console; + struct console console[MAX_CONSOLE]; }; static struct domain *dom_head; +typedef void (*VOID_ITER_FUNC_ARG1)(struct console *); +typedef bool (*BOOL_ITER_FUNC_ARG1)(struct console *); +typedef int (*INT_ITER_FUNC_ARG1)(struct console *); +typedef void (*VOID_ITER_FUNC_ARG2)(struct console *, void *); +typedef int (*INT_ITER_FUNC_ARG3)(struct console *, + struct domain *dom, void **); + +static inline bool console_enabled(struct console *con) +{ + return con->local_port != -1; +} + +static inline void console_iter_void_arg1(struct domain *d, + VOID_ITER_FUNC_ARG1 iter_func) +{ + int i = 0; + struct console *con = &(d->console[0]); + + for (i = 0; i < MAX_CONSOLE; i++, con++) + { + iter_func(con); + } +} + +static inline void console_iter_void_arg2(struct domain *d, + VOID_ITER_FUNC_ARG2 iter_func, + void *iter_data) +{ + int i = 0; + struct console *con = &(d->console[0]); + + for (i = 0; i < MAX_CONSOLE; i++, con++) + { + iter_func(con, iter_data); + } +} + +static inline bool console_iter_bool_arg1(struct domain *d, + BOOL_ITER_FUNC_ARG1 iter_func) +{ + int i = 0; + struct console *con = &(d->console[0]); + + for (i = 0; i < MAX_CONSOLE; i++, con++) + { + if (iter_func(con)) + return true; + } + return false; +} + +static inline int console_iter_int_arg1(struct domain *d, + INT_ITER_FUNC_ARG1 iter_func) +{ + int i = 0; + struct console *con = &(d->console[0]); + + for (i = 0; i < MAX_CONSOLE; i++, con++) + { + if (iter_func(con)) + return 1; + } + return 0; +} + +static inline int console_iter_int_arg3(struct domain *d, + INT_ITER_FUNC_ARG3 iter_func, + void **iter_data) +{ + int i = 0; + struct console *con = &(d->console[0]); + + for (i = 0; i < MAX_CONSOLE; i++, con++) + { + if (iter_func(con, d, iter_data)) + return 1; + } + return 0; +} static int write_all(int fd, const char* buf, size_t len) { while (len) { @@ -163,12 +261,22 @@ static int write_with_timestamp(int fd, const char *data, size_t sz, return 0; } -static void buffer_append(struct console *con) +static inline bool buffer_available(struct console *con) +{ + if (discard_overflowed_data || + !con->buffer.max_capacity || + con->buffer.size < con->buffer.max_capacity) + return true; + else + return false; +} + +static void buffer_append(struct console *con, xenevtchn_port_or_error_t port) { struct buffer *buffer = &con->buffer; + struct xencons_interface *intf = con->interface; struct domain *dom = con->d; XENCONS_RING_IDX cons, prod, size; - struct xencons_interface *intf = con->interface; cons = intf->out_cons; prod = intf->out_prod; @@ -321,7 +429,7 @@ static int create_console_log(struct console *con) return -1; } - snprintf(logfile, PATH_MAX-1, "%s/guest-%s.log", log_dir, data); + snprintf(logfile, PATH_MAX-1, "%s/guest-%s%s.log", log_dir, data, con->log_suffix); free(data); logfile[PATH_MAX-1] = '\0'; @@ -473,7 +581,7 @@ static int console_create_tty(struct console *con) } free(path); - success = (asprintf(&path, "%s/tty", con->xspath) != -1); + success = (asprintf(&path, "%s/%s", con->xspath, con->ttyname) != -1); if (!success) goto out; success = xs_write(xs, XBT_NULL, path, slave, strlen(slave)); @@ -594,6 +702,7 @@ static int console_create_ring(struct console *con) con->local_port = -1; con->remote_port = -1; + if (con->xce_handle != NULL) xenevtchn_close(con->xce_handle); @@ -639,13 +748,13 @@ static bool watch_domain(struct domain *dom, bool watch) { char domid_str[3 + MAX_STRLEN(dom->domid)]; bool success; - struct console *con = &dom->console; + struct console *con = &dom->console[0]; snprintf(domid_str, sizeof(domid_str), "dom%u", dom->domid); if (watch) { success = xs_watch(xs, con->xspath, domid_str); if (success) - console_create_ring(con); + console_iter_int_arg1(dom, console_create_ring); else xs_unwatch(xs, con->xspath, domid_str); } else { @@ -655,20 +764,59 @@ static bool watch_domain(struct domain *dom, bool watch) return success; } - -static struct domain *create_domain(int domid) +static int console_init(struct console *con, struct domain *dom, void **data) { - struct domain *dom; char *s; + int err = -1; struct timespec ts; - struct console *con; + struct console_data **con_data = (struct console_data **)data; + char *xsname; if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) { dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", __FILE__, __FUNCTION__, __LINE__); - return NULL; + return err; + } + + con->master_fd = -1; + con->master_pollfd_idx = -1; + con->slave_fd = -1; + con->log_fd = -1; + con->ring_ref = -1; + con->local_port = -1; + con->remote_port = -1; + con->xce_pollfd_idx = -1; + con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; + con->d = dom; + con->ttyname = (*con_data)->ttyname; + con->log_suffix = (*con_data)->log_suffix; + xsname = (*con_data)->xsname; + con->xspath = xs_get_domain_path(xs, dom->domid); + s = realloc(con->xspath, strlen(con->xspath) + + strlen(xsname) + 1); + if (s) + { + con->xspath = s; + strcat(con->xspath, xsname); + err = 0; } + (*con_data)++; + + return err; +} + +static void console_free(struct console *con) +{ + if (con->xspath) + free(con->xspath); +} + +static struct domain *create_domain(int domid) +{ + struct domain *dom; + struct console_data *con_data = &console_data[0]; + dom = calloc(1, sizeof *dom); if (dom == NULL) { dolog(LOG_ERR, "Out of memory %s:%s():L%d", @@ -678,27 +826,8 @@ static struct domain *create_domain(int domid) dom->domid = domid; - con = &dom->console; - con->xspath = xs_get_domain_path(xs, dom->domid); - s = realloc(con->xspath, strlen(con->xspath) + - strlen("/console") + 1); - if (s == NULL) + if (console_iter_int_arg3(dom, console_init, (void **)&con_data)) goto out; - con->xspath = s; - strcat(con->xspath, "/console"); - - con->master_fd = -1; - con->master_pollfd_idx = -1; - con->slave_fd = -1; - con->log_fd = -1; - con->xce_pollfd_idx = -1; - con->d = dom; - - con->next_period = ((long long)ts.tv_sec * 1000) + (ts.tv_nsec / 1000000) + RATE_LIMIT_PERIOD; - - con->ring_ref = -1; - con->local_port = -1; - con->remote_port = -1; if (!watch_domain(dom, true)) goto out; @@ -710,7 +839,7 @@ static struct domain *create_domain(int domid) return dom; out: - free(con->xspath); + console_iter_void_arg1(dom, console_free); free(dom); return NULL; } @@ -740,38 +869,51 @@ static void remove_domain(struct domain *dom) } } -static void cleanup_domain(struct domain *d) +static void console_cleanup(struct console *con) { - struct console *con = &d->console; - - console_close_tty(con); - if (con->log_fd != -1) { close(con->log_fd); con->log_fd = -1; } - free(con->buffer.data); - con->buffer.data = NULL; + if (con->buffer.data) + { + free(con->buffer.data); + con->buffer.data = NULL; + } + + if (con->xspath) + { + free(con->xspath); + con->xspath = NULL; + } +} + +static void cleanup_domain(struct domain *d) +{ + console_iter_void_arg1(d, console_close_tty); - free(con->xspath); - con->xspath = NULL; + console_iter_void_arg1(d, console_cleanup); remove_domain(d); } -static void shutdown_domain(struct domain *d) +static void console_close_evtchn(struct console *con) { - struct console *con = &d->console; - - d->is_dead = true; - watch_domain(d, false); - console_unmap_interface(con); if (con->xce_handle != NULL) xenevtchn_close(con->xce_handle); + con->xce_handle = NULL; } +static void shutdown_domain(struct domain *d) +{ + d->is_dead = true; + watch_domain(d, false); + console_iter_void_arg1(d, console_unmap_interface); + console_iter_void_arg1(d, console_close_evtchn); +} + static unsigned enum_pass = 0; static void enum_domains(void) @@ -885,12 +1027,32 @@ static void handle_tty_write(struct console *con) } } -static void handle_ring_read(struct domain *dom) +static void console_evtchn_unmask(struct console *con, void *data) +{ + long long now = (long long)data; + + if (!console_enabled(con)) + return; + + /* CS 16257:955ee4fa1345 introduces a 5ms fuzz + * for select(), it is not clear poll() has + * similar behavior (returning a couple of ms + * sooner than requested) as well. Just leave + * the fuzz here. Remove it with a separate + * patch if necessary */ + if ((now+5) > con->next_period) { + con->next_period = now + RATE_LIMIT_PERIOD; + if (con->event_count >= RATE_LIMIT_ALLOWANCE) + (void)xenevtchn_unmask(con->xce_handle, con->local_port); + con->event_count = 0; + } +} + +static void handle_ring_read(struct console *con) { xenevtchn_port_or_error_t port; - struct console *con = &dom->console; - if (dom->is_dead) + if (con->d->is_dead) return; if ((port = xenevtchn_pending(con->xce_handle)) == -1) @@ -898,10 +1060,23 @@ static void handle_ring_read(struct domain *dom) con->event_count++; - buffer_append(con); + buffer_append(con, port); if (con->event_count < RATE_LIMIT_ALLOWANCE) - (void)xenevtchn_unmask(con->xce_handle, port); + (void)xenevtchn_unmask(con->xce_handle, con->local_port); +} + +static void handle_console_ring(struct console *con) +{ + if (con->event_count < RATE_LIMIT_ALLOWANCE) { + if (con->xce_handle != NULL && + con->xce_pollfd_idx != -1 && + !(fds[con->xce_pollfd_idx].revents & + ~(POLLIN|POLLOUT|POLLPRI)) && + (fds[con->xce_pollfd_idx].revents & + POLLIN)) + handle_ring_read(con); + } } static void handle_xs(void) @@ -922,7 +1097,7 @@ static void handle_xs(void) /* We may get watches firing for domains that have recently been removed, so dom may be NULL here. */ if (dom && dom->is_dead == false) - console_create_ring(&dom->console); + console_iter_int_arg1(dom, console_create_ring); } free(vec); @@ -963,16 +1138,22 @@ static void handle_hv_logs(xenevtchn_handle *xce_handle, bool force) (void)xenevtchn_unmask(xce_handle, port); } +static void console_open_log(struct console *con) +{ + if (console_enabled(con)) + { + if (con->log_fd != -1) + close(con->log_fd); + con->log_fd = create_console_log(con); + } +} + static void handle_log_reload(void) { if (log_guest) { struct domain *d; for (d = dom_head; d; d = d->next) { - struct console *con = &d->console; - - if (con->log_fd != -1) - close(con->log_fd); - con->log_fd = create_console_log(con); + console_iter_void_arg1(d, console_open_log); } } @@ -1024,6 +1205,62 @@ static void reset_fds(void) memset(fds, 0, sizeof(struct pollfd) * current_array_size); } +static void add_console_evtchn_fd(struct console *con, void *data) +{ + long long next_timeout = *((long long *)data); + + if (con->event_count >= RATE_LIMIT_ALLOWANCE) { + /* Determine if we're going to be the next time slice to expire */ + if (!next_timeout || + con->next_period < next_timeout) + next_timeout = con->next_period; + } else if (con->xce_handle != NULL) { + if (buffer_available(con)) + { + int evtchn_fd = xenevtchn_fd(con->xce_handle); + con->xce_pollfd_idx = set_fds(evtchn_fd, + POLLIN|POLLPRI); + } + } + + *((long long *)data) = next_timeout; +} + +static void add_console_tty_fd(struct console *con) +{ + if (con->master_fd != -1) { + short events = 0; + if (!con->d->is_dead && ring_free_bytes(con)) + events |= POLLIN; + + if (!buffer_empty(&con->buffer)) + events |= POLLOUT; + + if (events) + con->master_pollfd_idx = + set_fds(con->master_fd, events|POLLPRI); + } +} + +static void handle_console_tty(struct console *con) +{ + if (con->master_fd != -1 && con->master_pollfd_idx != -1) { + if (fds[con->master_pollfd_idx].revents & + ~(POLLIN|POLLOUT|POLLPRI)) + console_handle_broken_tty(con, domain_is_valid(con->d->domid)); + else { + if (fds[con->master_pollfd_idx].revents & + POLLIN) + handle_tty_read(con); + if (fds[con->master_pollfd_idx].revents & + POLLOUT) + handle_tty_write(con); + } + } + con->master_pollfd_idx = -1; + con->xce_pollfd_idx = -1; +} + void handle_io(void) { int ret; @@ -1081,55 +1318,11 @@ void handle_io(void) /* Re-calculate any event counter allowances & unblock domains with new allowance */ for (d = dom_head; d; d = d->next) { - struct console *con = &d->console; - - /* CS 16257:955ee4fa1345 introduces a 5ms fuzz - * for select(), it is not clear poll() has - * similar behavior (returning a couple of ms - * sooner than requested) as well. Just leave - * the fuzz here. Remove it with a separate - * patch if necessary */ - if ((now+5) > con->next_period) { - con->next_period = now + RATE_LIMIT_PERIOD; - if (con->event_count >= RATE_LIMIT_ALLOWANCE) { - (void)xenevtchn_unmask(con->xce_handle, con->local_port); - } - con->event_count = 0; - } - } - for (d = dom_head; d; d = d->next) { - struct console *con = &d->console; - - if (con->event_count >= RATE_LIMIT_ALLOWANCE) { - /* Determine if we're going to be the next time slice to expire */ - if (!next_timeout || - con->next_period < next_timeout) - next_timeout = con->next_period; - } else if (con->xce_handle != NULL) { - if (discard_overflowed_data || - !con->buffer.max_capacity || - con->buffer.size < con->buffer.max_capacity) { - int evtchn_fd = xenevtchn_fd(con->xce_handle); - con->xce_pollfd_idx = set_fds(evtchn_fd, - POLLIN|POLLPRI); - } - } - - if (con->master_fd != -1) { - short events = 0; - if (!d->is_dead && ring_free_bytes(con)) - events |= POLLIN; - - if (!buffer_empty(&con->buffer)) - events |= POLLOUT; - - if (events) - con->master_pollfd_idx = - set_fds(con->master_fd, - events|POLLPRI); - } - } + console_iter_void_arg2(d, console_evtchn_unmask, (void *)now); + console_iter_void_arg2(d, add_console_evtchn_fd, (void *)&next_timeout); + console_iter_void_arg1(d, add_console_tty_fd); + } /* If any domain has been rate limited, we need to work out what timeout to supply to poll */ @@ -1189,35 +1382,11 @@ void handle_io(void) } for (d = dom_head; d; d = n) { - struct console *con = &d->console; n = d->next; - if (con->event_count < RATE_LIMIT_ALLOWANCE) { - if (con->xce_handle != NULL && - con->xce_pollfd_idx != -1 && - !(fds[con->xce_pollfd_idx].revents & - ~(POLLIN|POLLOUT|POLLPRI)) && - (fds[con->xce_pollfd_idx].revents & - POLLIN)) - handle_ring_read(d); - } - - if (con->master_fd != -1 && con->master_pollfd_idx != -1) { - if (fds[con->master_pollfd_idx].revents & - ~(POLLIN|POLLOUT|POLLPRI)) - console_handle_broken_tty(con, - domain_is_valid(d->domid)); - else { - if (fds[con->master_pollfd_idx].revents & - POLLIN) - handle_tty_read(con); - if (fds[con->master_pollfd_idx].revents & - POLLOUT) - handle_tty_write(con); - } - } - con->xce_pollfd_idx = con->master_pollfd_idx = -1; + console_iter_void_arg1(d, handle_console_ring); + console_iter_void_arg1(d, handle_console_tty); if (d->last_seen != enum_pass) shutdown_domain(d);
This patch adds the support for multiple consoles and introduces the iterator functions to operate on multiple consoles. This patch is in preparation to support a new vuart console. Signed-off-by: Bhupinder Thakur <bhupinder.thakur@linaro.org> --- CC: Ian Jackson <ian.jackson@eu.citrix.com> CC: Wei Liu <wei.liu2@citrix.com> CC: Stefano Stabellini <sstabellini@kernel.org> CC: Julien Grall <julien.grall@arm.com> Changes since v4: - Changes to make event channel handling per console rather than per domain. Changes since v3: - The changes in xenconsole have been split into four patches. This is the third patch. tools/console/daemon/io.c | 435 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 302 insertions(+), 133 deletions(-)