ia64/xen-unstable

changeset 16235:b34ba3bcab0b

pv-qemu 8/10: Add pv console to QEMU paravirt machine

This patch adds a paravirt console driver to qemu-dm. This is used
when the QEMU machine type is 'xenpv', connecting to the ring buffer
provided by the guest kernel. The '-serial' command line flag controls
how the guest console is exposed.

For parity with xenconsoled the '-serial pty' arg can be used. For
guests which are running a qemu-dm device model, the xenconsoled
daemon is no longer needed for guest consoles. The code for the
xen_console.c is based on the original code in
tools/console/daemon/io.c, but simplified; since its only dealing with
a single guest there's no state tracking to worry about.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Thu Oct 25 14:42:40 2007 +0100 (2007-10-25)
parents 695871933840
children e8905caa47b5
files tools/ioemu/Makefile.target tools/ioemu/hw/xen_console.c tools/ioemu/hw/xen_console.h tools/ioemu/hw/xen_machine_pv.c tools/ioemu/xenstore.c tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/tools/ioemu/Makefile.target	Thu Oct 25 14:41:35 2007 +0100
     1.2 +++ b/tools/ioemu/Makefile.target	Thu Oct 25 14:42:40 2007 +0100
     1.3 @@ -412,6 +412,7 @@ VL_OBJS+= xen_platform.o
     1.4  VL_OBJS+= xen_machine_fv.o
     1.5  VL_OBJS+= xen_machine_pv.o
     1.6  VL_OBJS+= xenfb.o
     1.7 +VL_OBJS+= xen_console.o
     1.8  VL_OBJS+= tpm_tis.o
     1.9  CPPFLAGS += -DHAS_AUDIO
    1.10  endif
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/tools/ioemu/hw/xen_console.c	Thu Oct 25 14:42:40 2007 +0100
     2.3 @@ -0,0 +1,432 @@
     2.4 +/*
     2.5 + *  Copyright (C) International Business Machines  Corp., 2005
     2.6 + *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
     2.7 + *
     2.8 + *  Copyright (C) Red Hat 2007
     2.9 + *
    2.10 + *  Xen Console
    2.11 + *
    2.12 + *  This program is free software; you can redistribute it and/or modify
    2.13 + *  it under the terms of the GNU General Public License as published by
    2.14 + *  the Free Software Foundation; under version 2 of the License.
    2.15 + * 
    2.16 + *  This program is distributed in the hope that it will be useful,
    2.17 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.18 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.19 + *  GNU General Public License for more details.
    2.20 + * 
    2.21 + *  You should have received a copy of the GNU General Public License
    2.22 + *  along with this program; if not, write to the Free Software
    2.23 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    2.24 + */
    2.25 +
    2.26 +#include <malloc.h>
    2.27 +#include <stdlib.h>
    2.28 +#include <errno.h>
    2.29 +#include <string.h>
    2.30 +#include <sys/select.h>
    2.31 +#include <fcntl.h>
    2.32 +#include <unistd.h>
    2.33 +#include <termios.h>
    2.34 +#include <stdarg.h>
    2.35 +#include <sys/mman.h>
    2.36 +#include <xs.h>
    2.37 +#include <xen/io/console.h>
    2.38 +#include <xenctrl.h>
    2.39 +
    2.40 +#include "vl.h"
    2.41 +
    2.42 +#include "xen_console.h"
    2.43 +
    2.44 +#define dolog(val, fmt, ...) fprintf(stderr, fmt "\n", ## __VA_ARGS__)
    2.45 +
    2.46 +struct buffer
    2.47 +{
    2.48 +	uint8_t *data;
    2.49 +	size_t consumed;
    2.50 +	size_t size;
    2.51 +	size_t capacity;
    2.52 +	size_t max_capacity;
    2.53 +};
    2.54 +
    2.55 +struct domain
    2.56 +{
    2.57 +	int domid;
    2.58 +	struct buffer buffer;
    2.59 +
    2.60 +	char *conspath;
    2.61 +	char *serialpath;
    2.62 +	int use_consolepath;
    2.63 +	int ring_ref;
    2.64 +	evtchn_port_t local_port;
    2.65 +	evtchn_port_t remote_port;
    2.66 +	int xce_handle;
    2.67 +	struct xs_handle *xsh;
    2.68 +	struct xencons_interface *interface;
    2.69 +	CharDriverState *chr;
    2.70 +};
    2.71 +
    2.72 +
    2.73 +static void buffer_append(struct domain *dom)
    2.74 +{
    2.75 +	struct buffer *buffer = &dom->buffer;
    2.76 +	XENCONS_RING_IDX cons, prod, size;
    2.77 +	struct xencons_interface *intf = dom->interface;
    2.78 +
    2.79 +	cons = intf->out_cons;
    2.80 +	prod = intf->out_prod;
    2.81 +	mb();
    2.82 +
    2.83 +	size = prod - cons;
    2.84 +	if ((size == 0) || (size > sizeof(intf->out)))
    2.85 +		return;
    2.86 +
    2.87 +	if ((buffer->capacity - buffer->size) < size) {
    2.88 +		buffer->capacity += (size + 1024);
    2.89 +		buffer->data = realloc(buffer->data, buffer->capacity);
    2.90 +		if (buffer->data == NULL) {
    2.91 +			dolog(LOG_ERR, "Memory allocation failed");
    2.92 +			exit(ENOMEM);
    2.93 +		}
    2.94 +	}
    2.95 +
    2.96 +	while (cons != prod)
    2.97 +		buffer->data[buffer->size++] = intf->out[
    2.98 +			MASK_XENCONS_IDX(cons++, intf->out)];
    2.99 +
   2.100 +	mb();
   2.101 +	intf->out_cons = cons;
   2.102 +	xc_evtchn_notify(dom->xce_handle, dom->local_port);
   2.103 +
   2.104 +	if (buffer->max_capacity &&
   2.105 +	    buffer->size > buffer->max_capacity) {
   2.106 +		/* Discard the middle of the data. */
   2.107 +
   2.108 +		size_t over = buffer->size - buffer->max_capacity;
   2.109 +		uint8_t *maxpos = buffer->data + buffer->max_capacity;
   2.110 +
   2.111 +		memmove(maxpos - over, maxpos, over);
   2.112 +		buffer->data = realloc(buffer->data, buffer->max_capacity);
   2.113 +		buffer->size = buffer->capacity = buffer->max_capacity;
   2.114 +
   2.115 +		if (buffer->consumed > buffer->max_capacity - over)
   2.116 +			buffer->consumed = buffer->max_capacity - over;
   2.117 +	}
   2.118 +}
   2.119 +
   2.120 +static void buffer_advance(struct buffer *buffer, size_t len)
   2.121 +{
   2.122 +	buffer->consumed += len;
   2.123 +	if (buffer->consumed == buffer->size) {
   2.124 +		buffer->consumed = 0;
   2.125 +		buffer->size = 0;
   2.126 +	}
   2.127 +}
   2.128 +
   2.129 +/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
   2.130 +int xs_gather(struct xs_handle *xs, const char *dir, ...)
   2.131 +{
   2.132 +	va_list ap;
   2.133 +	const char *name;
   2.134 +	char *path;
   2.135 +	int ret = 0;
   2.136 +
   2.137 +	va_start(ap, dir);
   2.138 +	while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
   2.139 +		const char *fmt = va_arg(ap, char *);
   2.140 +		void *result = va_arg(ap, void *);
   2.141 +		char *p;
   2.142 +
   2.143 +		if (asprintf(&path, "%s/%s", dir, name) == -1) {
   2.144 +			ret = ENOMEM;
   2.145 +			break;
   2.146 +		}
   2.147 +		p = xs_read(xs, XBT_NULL, path, NULL);
   2.148 +		free(path);
   2.149 +		if (p == NULL) {
   2.150 +			ret = ENOENT;
   2.151 +			break;
   2.152 +		}
   2.153 +		if (fmt) {
   2.154 +			if (sscanf(p, fmt, result) == 0)
   2.155 +				ret = EINVAL;
   2.156 +			free(p);
   2.157 +		} else
   2.158 +			*(char **)result = p;
   2.159 +	}
   2.160 +	va_end(ap);
   2.161 +	return ret;
   2.162 +}
   2.163 +
   2.164 +static int domain_create_ring(struct domain *dom)
   2.165 +{
   2.166 +	int err, remote_port, ring_ref, rc;
   2.167 +
   2.168 +	err = xs_gather(dom->xsh, dom->serialpath,
   2.169 +			"ring-ref", "%u", &ring_ref,
   2.170 +			"port", "%i", &remote_port,
   2.171 +			NULL);
   2.172 +	if (err) {
   2.173 +		err = xs_gather(dom->xsh, dom->conspath,
   2.174 +				"ring-ref", "%u", &ring_ref,
   2.175 +				"port", "%i", &remote_port,
   2.176 +				NULL);
   2.177 +		if (err) {
   2.178 +			fprintf(stderr, "Console: failed to find ring-ref/port yet\n");
   2.179 +			goto out;
   2.180 +		}
   2.181 +		dom->use_consolepath = 1;
   2.182 +	} else
   2.183 +		dom->use_consolepath = 0;
   2.184 +	fprintf(stderr, "Console: got ring-ref %d port %d\n", ring_ref, remote_port);
   2.185 +
   2.186 +	if ((ring_ref == dom->ring_ref) && (remote_port == dom->remote_port))
   2.187 +		goto out;
   2.188 +
   2.189 +	if (ring_ref != dom->ring_ref) {
   2.190 +		if (dom->interface != NULL)
   2.191 +			munmap(dom->interface, getpagesize());
   2.192 +		dom->interface = xc_map_foreign_range(
   2.193 +			xc_handle, dom->domid, getpagesize(),
   2.194 +			PROT_READ|PROT_WRITE,
   2.195 +			(unsigned long)ring_ref);
   2.196 +		if (dom->interface == NULL) {
   2.197 +			err = errno;
   2.198 +			goto out;
   2.199 +		}
   2.200 +		dom->ring_ref = ring_ref;
   2.201 +	}
   2.202 +
   2.203 +	dom->local_port = -1;
   2.204 +	dom->remote_port = -1;
   2.205 +
   2.206 +	dom->xce_handle = xc_evtchn_open();
   2.207 +	if (dom->xce_handle == -1) {
   2.208 +		err = errno;
   2.209 +		goto out;
   2.210 +	}
   2.211 +
   2.212 +	rc = xc_evtchn_bind_interdomain(dom->xce_handle,
   2.213 +		dom->domid, remote_port);
   2.214 +
   2.215 +	if (rc == -1) {
   2.216 +		err = errno;
   2.217 +		xc_evtchn_close(dom->xce_handle);
   2.218 +		dom->xce_handle = -1;
   2.219 +		goto out;
   2.220 +	}
   2.221 +	dom->local_port = rc;
   2.222 +	dom->remote_port = remote_port;
   2.223 +
   2.224 + out:
   2.225 +	return err;
   2.226 +}
   2.227 +
   2.228 +
   2.229 +static struct domain *create_domain(int domid, CharDriverState *chr)
   2.230 +{
   2.231 +	struct domain *dom;
   2.232 +	char *s;
   2.233 +
   2.234 +	dom = (struct domain *)malloc(sizeof(struct domain));
   2.235 +	if (dom == NULL) {
   2.236 +		dolog(LOG_ERR, "Out of memory %s:%s():L%d",
   2.237 +		      __FILE__, __FUNCTION__, __LINE__);
   2.238 +		exit(ENOMEM);
   2.239 +	}
   2.240 +
   2.241 +	dom->domid = domid;
   2.242 +	dom->chr = chr;
   2.243 +
   2.244 +	dom->xsh = xs_daemon_open();
   2.245 +	if (dom->xsh == NULL) {
   2.246 +		fprintf(logfile, "Could not contact xenstore for console watch\n");
   2.247 +		goto out;
   2.248 +	}
   2.249 +
   2.250 +	dom->serialpath = xs_get_domain_path(dom->xsh, dom->domid);
   2.251 +	s = realloc(dom->serialpath, strlen(dom->serialpath) +
   2.252 +		    strlen("/serial/0") + 1);
   2.253 +	if (s == NULL)
   2.254 +		goto out;
   2.255 +	dom->serialpath = s;
   2.256 +	strcat(dom->serialpath, "/serial/0");
   2.257 +
   2.258 +	dom->conspath = xs_get_domain_path(dom->xsh, dom->domid);
   2.259 +	s = realloc(dom->conspath, strlen(dom->conspath) +
   2.260 +		    strlen("/console") + 1);
   2.261 +	if (s == NULL)
   2.262 +		goto out;
   2.263 +	dom->conspath = s;
   2.264 +	strcat(dom->conspath, "/console");
   2.265 +
   2.266 +	dom->buffer.data = 0;
   2.267 +	dom->buffer.consumed = 0;
   2.268 +	dom->buffer.size = 0;
   2.269 +	dom->buffer.capacity = 0;
   2.270 +	dom->buffer.max_capacity = 0;
   2.271 +
   2.272 +	dom->ring_ref = -1;
   2.273 +	dom->local_port = -1;
   2.274 +	dom->remote_port = -1;
   2.275 +	dom->interface = NULL;
   2.276 +	dom->xce_handle = -1;
   2.277 +
   2.278 +
   2.279 +	return dom;
   2.280 + out:
   2.281 +	free(dom->serialpath);
   2.282 +	free(dom->conspath);
   2.283 +	free(dom);
   2.284 +	return NULL;
   2.285 +}
   2.286 +
   2.287 +
   2.288 +static int ring_free_bytes(struct domain *dom)
   2.289 +{
   2.290 +	struct xencons_interface *intf = dom->interface;
   2.291 +	XENCONS_RING_IDX cons, prod, space;
   2.292 +
   2.293 +	cons = intf->in_cons;
   2.294 +	prod = intf->in_prod;
   2.295 +	mb();
   2.296 +
   2.297 +	space = prod - cons;
   2.298 +	if (space > sizeof(intf->in))
   2.299 +		return 0; /* ring is screwed: ignore it */
   2.300 +
   2.301 +	return (sizeof(intf->in) - space);
   2.302 +}
   2.303 +
   2.304 +static int xencons_can_receive(void *opaque)
   2.305 +{
   2.306 +	struct domain *dom = (struct domain *)opaque;
   2.307 +
   2.308 +	return ring_free_bytes(dom);
   2.309 +}
   2.310 +
   2.311 +static void xencons_receive(void *opaque, const uint8_t *buf, int len)
   2.312 +{
   2.313 +	struct domain *dom = (struct domain *)opaque;
   2.314 +	int i, max;
   2.315 +	struct xencons_interface *intf = dom->interface;
   2.316 +	XENCONS_RING_IDX prod;
   2.317 +
   2.318 +	max = ring_free_bytes(dom);
   2.319 +	/* The can_receive() func limits this, but check again anyway */
   2.320 +	if (max < len)
   2.321 +		len = max;
   2.322 +
   2.323 +	prod = intf->in_prod;
   2.324 +	for (i = 0; i < len; i++) {
   2.325 +		intf->in[MASK_XENCONS_IDX(prod++, intf->in)] =
   2.326 +			buf[i];
   2.327 +	}
   2.328 +	wmb();
   2.329 +	intf->in_prod = prod;
   2.330 +	xc_evtchn_notify(dom->xce_handle, dom->local_port);
   2.331 +}
   2.332 +
   2.333 +static void xencons_send(struct domain *dom)
   2.334 +{
   2.335 +	ssize_t len;
   2.336 +	len = qemu_chr_write(dom->chr, dom->buffer.data + dom->buffer.consumed,
   2.337 +			     dom->buffer.size - dom->buffer.consumed);
   2.338 + 	if (len < 1) {
   2.339 +		/*
   2.340 +		 * Disable log because if we're redirecting to /dev/pts/N we
   2.341 +		 * don't want to flood logs when no client has the PTY open
   2.342 +		 */
   2.343 +		/*
   2.344 +		dolog(LOG_DEBUG, "Write failed on domain %d: %zd, %d\n",
   2.345 +		      dom->domid, len, errno);
   2.346 +		*/
   2.347 +	} else {
   2.348 +		buffer_advance(&dom->buffer, len);
   2.349 +	}
   2.350 +}
   2.351 +
   2.352 +static void xencons_ring_read(void *opaque)
   2.353 +{
   2.354 +	evtchn_port_t port;
   2.355 +	struct domain *dom = (struct domain *)opaque;
   2.356 +
   2.357 +	if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
   2.358 +		return;
   2.359 +
   2.360 +	buffer_append(dom);
   2.361 +
   2.362 +	(void)xc_evtchn_unmask(dom->xce_handle, port);
   2.363 +
   2.364 +	if (dom->buffer.size - dom->buffer.consumed)
   2.365 +		xencons_send(dom);
   2.366 +}
   2.367 +
   2.368 +static void xencons_startup(void *opaque)
   2.369 +{
   2.370 +	struct domain *dom = (struct domain *)opaque;
   2.371 +	unsigned dummy;
   2.372 +	char **vec;
   2.373 +	int err;
   2.374 +	vec = xs_read_watch(dom->xsh, &dummy);
   2.375 +	if (vec)
   2.376 +		free(vec);
   2.377 +	fprintf(stderr, "Console: got watch\n");
   2.378 +	err = domain_create_ring(dom);
   2.379 +	if (err)
   2.380 +		return;
   2.381 +
   2.382 +	xs_unwatch(dom->xsh, dom->conspath, "");
   2.383 +	xs_unwatch(dom->xsh, dom->serialpath, "");
   2.384 +	qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, NULL, NULL, NULL);
   2.385 +
   2.386 +	fprintf(stderr, "Console: connected to guest frontend\n");
   2.387 +	if (qemu_set_fd_handler2(dom->xce_handle, NULL, xencons_ring_read, NULL, dom) < 0)
   2.388 +		return;
   2.389 +
   2.390 +	qemu_chr_add_handlers(dom->chr, xencons_can_receive, xencons_receive,
   2.391 +			      NULL, dom);
   2.392 +}
   2.393 +
   2.394 +
   2.395 +int xencons_init(int domid, CharDriverState *chr)
   2.396 +{
   2.397 +	struct domain *dom = create_domain(domid, chr);
   2.398 +
   2.399 +	if (!dom)
   2.400 +		return -1;
   2.401 +
   2.402 +	/* Setup watches so we asynchronously connect to serial console */
   2.403 +	if (!(xs_watch(dom->xsh, dom->conspath, ""))) {
   2.404 +		fprintf(stderr, "Unable to watch console %s\n", dom->conspath);
   2.405 +		goto fail;
   2.406 +	}
   2.407 +	if (!(xs_watch(dom->xsh, dom->serialpath, ""))) {
   2.408 +		fprintf(stderr, "Unable to watch console %s\n", dom->conspath);
   2.409 +		xs_unwatch(dom->xsh, dom->conspath, "");
   2.410 +		goto fail;
   2.411 +	}
   2.412 +	qemu_set_fd_handler2(xs_fileno(dom->xsh), NULL, xencons_startup, NULL, dom);
   2.413 +	fprintf(stderr, "Console: prepared domain, waiting for ringref at %s or %s\n",
   2.414 +		dom->conspath, dom->serialpath);
   2.415 +
   2.416 +	return 0;
   2.417 +
   2.418 +fail:
   2.419 +	xs_daemon_close(dom->xsh);
   2.420 +	free(dom->serialpath);
   2.421 +	free(dom->conspath);
   2.422 +	free(dom);
   2.423 +	return -1;
   2.424 +}
   2.425 +
   2.426 +
   2.427 +/*
   2.428 + * Local variables:
   2.429 + *  c-file-style: "linux"
   2.430 + *  indent-tabs-mode: t
   2.431 + *  c-indent-level: 8
   2.432 + *  c-basic-offset: 8
   2.433 + *  tab-width: 8
   2.434 + * End:
   2.435 + */
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/ioemu/hw/xen_console.h	Thu Oct 25 14:42:40 2007 +0100
     3.3 @@ -0,0 +1,25 @@
     3.4 +/*
     3.5 + *  Copyright (C) International Business Machines  Corp., 2005
     3.6 + *  Author(s): Anthony Liguori <aliguori@us.ibm.com>
     3.7 + *
     3.8 + *  Copyright (C) Red Hat 2007
     3.9 + *
    3.10 + *  Xen Console
    3.11 + *
    3.12 + *  This program is free software; you can redistribute it and/or modify
    3.13 + *  it under the terms of the GNU General Public License as published by
    3.14 + *  the Free Software Foundation; under version 2 of the License.
    3.15 + * 
    3.16 + *  This program is distributed in the hope that it will be useful,
    3.17 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.18 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.19 + *  GNU General Public License for more details.
    3.20 + * 
    3.21 + *  You should have received a copy of the GNU General Public License
    3.22 + *  along with this program; if not, write to the Free Software
    3.23 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    3.24 + */
    3.25 +
    3.26 +#include "vl.h"
    3.27 +
    3.28 +extern int xencons_init(int domid, CharDriverState *chr);
     4.1 --- a/tools/ioemu/hw/xen_machine_pv.c	Thu Oct 25 14:41:35 2007 +0100
     4.2 +++ b/tools/ioemu/hw/xen_machine_pv.c	Thu Oct 25 14:42:40 2007 +0100
     4.3 @@ -23,6 +23,7 @@
     4.4   */
     4.5  
     4.6  #include "vl.h"
     4.7 +#include "xen_console.h"
     4.8  #include "xenfb.h"
     4.9  
    4.10  /* The Xen PV machine currently provides
    4.11 @@ -39,6 +40,14 @@ static void xen_init_pv(uint64_t ram_siz
    4.12      struct xenfb *xenfb;
    4.13      extern int domid;
    4.14  
    4.15 +    /* Connect to text console */
    4.16 +    if (serial_hds[0]) {
    4.17 +        if (xencons_init(domid, serial_hds[0]) < 0) {
    4.18 +            fprintf(stderr, "Could not connect to domain console\n");
    4.19 +            exit(1);
    4.20 +        }
    4.21 +    }
    4.22 +
    4.23      /* Prepare PVFB state */
    4.24      xenfb = xenfb_new(domid, ds);
    4.25      if (xenfb == NULL) {
     5.1 --- a/tools/ioemu/xenstore.c	Thu Oct 25 14:41:35 2007 +0100
     5.2 +++ b/tools/ioemu/xenstore.c	Thu Oct 25 14:42:40 2007 +0100
     5.3 @@ -17,7 +17,7 @@
     5.4  #include <sys/stat.h>
     5.5  #include <fcntl.h>
     5.6  
     5.7 -static struct xs_handle *xsh = NULL;
     5.8 +struct xs_handle *xsh = NULL;
     5.9  static char *media_filename[MAX_DISKS + MAX_SCSI_DISKS];
    5.10  static QEMUTimer *insert_timer = NULL;
    5.11  
     6.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Oct 25 14:41:35 2007 +0100
     6.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Oct 25 14:42:40 2007 +0100
     6.3 @@ -1761,10 +1761,9 @@ class XendDomainInfo:
     6.4          self.console_mfn = console_mfn
     6.5  
     6.6          self._introduceDomain()
     6.7 -        if self.info.is_hvm():
     6.8 -            self.image = image.create(self, self.info)
     6.9 -            if self.image:
    6.10 -                self.image.createDeviceModel(True)
    6.11 +        self.image = image.create(self, self.info)
    6.12 +        if self.image:
    6.13 +            self.image.createDeviceModel(True)
    6.14          self._storeDomDetails()
    6.15          self._registerWatches()
    6.16          self.refreshShutdown()