From: Paul Durrant Date: Thu, 1 Dec 2016 13:17:28 +0000 (+0000) Subject: Initial commit X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=HEAD;p=people%2Fpauldu%2Fstats.git Initial commit Signed-off-by: Paul Durrant --- 1fe63c9c50c79fe4cf71958d6ddbcb6647c744f1 diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1ac294d --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +TARGET = xen-stats + +OBJS := stats.o + +CFLAGS = -I$(shell pwd)/include + +# _GNU_SOURCE for asprintf. +CFLAGS += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_GNU_SOURCE +CFLAGS += -Wall -Werror -g -O1 + +ifeq ($(shell uname),Linux) +LDLIBS := -lutil -lrt +endif + +LDLIBS += -lxenstore -lxenctrl -lxenevtchn -lxengnttab + +# Get gcc to generate the dependencies for us. +CFLAGS += -Wp,-MD,$(@D)/.$(@F).d + +SUBDIRS = $(filter-out ./,$(dir $(OBJS) $(LIBS))) +DEPS = .*.d + +LDFLAGS := -g + +all: $(TARGET) + +$(TARGET): $(LIBS) $(OBJS) + gcc -o $@ $(LDFLAGS) $(OBJS) $(LIBS) $(LDLIBS) + +%.o: %.c + gcc -o $@ $(CFLAGS) -c $< + +.PHONY: ALWAYS + +clean: + $(foreach dir,$(SUBDIRS),make -C $(dir) clean) + rm -f $(OBJS) + rm -f $(DEPS) + rm -f $(TARGET) + rm -f TAGS + +.PHONY: TAGS +TAGS: + find . -name \*.[ch] | etags - + +-include $(DEPS) + +print-%: + echo $($*) diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..816d778 --- /dev/null +++ b/debug.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _DEBUG_H +#define _DEBUG_H + +#define DBG(...) \ + do { \ + fprintf(stderr, "%s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fflush(stderr); \ + } while (FALSE) + +#endif /* _DEBUG_H */ + diff --git a/stats.c b/stats.c new file mode 100644 index 0000000..a902570 --- /dev/null +++ b/stats.c @@ -0,0 +1,1175 @@ +/* + * Copyright (c) 2016, Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "xen_stats.h" + +#include "debug.h" + +#define FALSE 0 + +enum { + STATS_OPT_DOMAIN, + STATS_OPT_PROVIDER, + STATS_OPT_SET, + STATS_OPT_INTERVAL, + STATS_NR_OPTS + }; + +static struct option stats_option[] = { + {"domain", 1, NULL, 0}, + {"provider", 1, NULL, 0}, + {"set", 1, NULL, 0}, + {"interval", 1, NULL, 0}, + {NULL, 0, NULL, 0} +}; + +static const char *stats_option_text[] = { + "", + "", + "", + "", + NULL +}; + +static const char *prog; + +static void +usage(void) +{ + int i; + + fprintf(stderr, "Usage: %s \n\n", prog); + + for (i = 0; i < STATS_NR_OPTS; i++) + fprintf(stderr, "\t--%s %s\n", + stats_option[i].name, + stats_option_text[i]); + + fprintf(stderr, "\n"); + + exit(2); +} + +typedef enum { + STATS_SEQ_UNINITIALIZED = 0, + STATS_SEQ_CTRL_OPEN, + STATS_SEQ_STORE_OPEN, + STATS_SEQ_EVTCHN_OPEN, + STATS_SEQ_GNTTAB_OPEN, + STATS_SEQ_SET_FOUND, + STATS_SEQ_SET_NOTIFIED, + STATS_SEQ_WATCH_CREATED, + STATS_SEQ_TIMER_CREATED, + STATS_SEQ_INITIALIZED, + STATS_NR_SEQS +} stats_seq_t; + +typedef struct stats_state { + stats_seq_t seq; + domid_t domid; + xc_interface *xch; + struct xs_handle *xsh; + xenevtchn_handle *xeh; + xengnttab_handle *xgh; + char *path; + char *monitor_id_key; + char *event_channel_key; + char *event_channel_token; + evtchn_port_t local_port; + char **name; + unsigned int *type; + void *values; + unsigned int nr_stats; + unsigned int nr_pages; + bool bound; + timer_t tid; + int tfd; +} stats_state_t; + +static stats_state_t stats_state; + +static void +stats_seq_next(stats_seq_t seq) +{ + assert(stats_state.seq < STATS_SEQ_INITIALIZED); + + stats_state.seq++; + assert(stats_state.seq == seq); + + switch (stats_state.seq) { + case STATS_SEQ_CTRL_OPEN: + DBG(">CTRL_OPEN\n"); + break; + + case STATS_SEQ_STORE_OPEN: + DBG(">STORE_OPEN\n"); + break; + + case STATS_SEQ_EVTCHN_OPEN: + DBG(">EVTCHN_OPEN\n"); + break; + + case STATS_SEQ_GNTTAB_OPEN: + DBG(">GNTTAB_OPEN\n"); + break; + + case STATS_SEQ_SET_FOUND: + DBG(">SET_FOUND\n"); + break; + + case STATS_SEQ_SET_NOTIFIED: + DBG(">SET_NOTIFIED\n"); + break; + + case STATS_SEQ_WATCH_CREATED: + DBG(">WATCH_CREATED\n"); + break; + + case STATS_SEQ_TIMER_CREATED: + DBG(">TIMER_CREATED\n"); + break; + + case STATS_SEQ_INITIALIZED: + DBG(">INITIALIZED\n"); + break; + + default: + assert(FALSE); + break; + } +} + +static int +stats_set_monitor_id(void) +{ + char *domid_str; + domid_t domid; + char *key; + char *value; + int rc; + + domid_str = xs_read(stats_state.xsh, XBT_NULL, + "domid", NULL); + + if (domid_str == NULL) + goto fail1; + + domid = (domid_t)strtol(domid_str, NULL, 0); + + rc = asprintf(&key, "%s/monitor-id", stats_state.path); + if (rc < 0) + goto fail2; + + rc = asprintf(&value, "%u", domid); + if (rc < 0) + goto fail3; + + DBG("%s -> %s\n", key, value); + + if (!xs_write(stats_state.xsh, XBT_NULL, key, value, strlen(value))) + goto fail4; + + free(value); + + stats_state.monitor_id_key = key; + + free(domid_str); + + return 0; + +fail4: + DBG("fail4\n"); + + free(value); + +fail3: + DBG("fail3\n"); + + free(key); + +fail2: + DBG("fail2\n"); + + free(domid_str); + +fail1: + DBG("fail1\n"); + + return -1; +} + +static void +stats_clear_monitor_id(void) +{ + (void) xs_rm(stats_state.xsh, XBT_NULL, stats_state.monitor_id_key); + + free(stats_state.monitor_id_key); +} + +static int +stats_create_watch(void) +{ + char *key; + char *token; + int rc; + + rc = asprintf(&key, "%s/event-channel", stats_state.path); + if (rc < 0) + goto fail1; + + DBG("%s\n", key); + + rc = asprintf(&token, "%u:event-channel", getpid()); + if (rc < 0) + goto fail2; + + if (!xs_watch(stats_state.xsh, key, token)) + goto fail3; + + stats_state.event_channel_key = key; + stats_state.event_channel_token = token; + + return 0; + +fail3: + DBG("fail3\n"); + + free(token); + +fail2: + DBG("fail2\n"); + + free(key); + +fail1: + DBG("fail1\n"); + + return -1; +} + +static void +stats_destroy_watch(void) +{ + (void) xs_unwatch(stats_state.xsh, stats_state.event_channel_key, + stats_state.event_channel_token); + + free(stats_state.event_channel_key); + free(stats_state.event_channel_token); +} + +static int +stats_parse_name_types(void *name_types, unsigned int nr_pages) +{ + struct xen_stats_name_type *name_type = name_types; + unsigned int max_nr_stats; + unsigned int i, nr_stats; + + max_nr_stats = (nr_pages * XC_PAGE_SIZE) / + sizeof(struct xen_stats_name_type); + + i = 0; + while (i < max_nr_stats) { + if (name_type[i].type == XEN_STATS_TYPE_INVALID) + break; + + i++; + } + nr_stats = i; + + if (nr_stats == 0) + goto fail1; + + stats_state.name = calloc(nr_stats, sizeof (char *)); + if (stats_state.name == NULL) + goto fail2; + + stats_state.type = calloc(nr_stats, sizeof (unsigned int)); + if (stats_state.type == NULL) + goto fail3; + + for (i = 0; i < nr_stats; i++) { + int rc; + + rc = asprintf(&stats_state.name[i], "%s", name_type[i].name); + if (rc < 0) + goto fail4; + + stats_state.type[i] = name_type[i].type; + } + + stats_state.nr_stats = nr_stats; + + return 0; + +fail4: + DBG("fail4\n"); + + while (i-- != 0) + free(stats_state.name[i]); + + free(stats_state.type); + +fail3: + DBG("fail3\n"); + + free(stats_state.name); + +fail2: + DBG("fail2\n"); + +fail1: + DBG("fail1\n"); + + return -1; +} + +static void +stats_free_name_types(void) +{ + unsigned int i = stats_state.nr_stats; + + while (i-- != 0) + free(stats_state.name[i]); + + free(stats_state.type); + free(stats_state.name); +} + +#define MAX_NR_PAGES 8 + +static int +stats_bind(unsigned int port) +{ + uint32_t name_ref[MAX_NR_PAGES]; + uint32_t val_ref[MAX_NR_PAGES]; + void *name_types; + unsigned int i, nr_pages; + int rc; + + rc = xenevtchn_bind_interdomain(stats_state.xeh, stats_state.domid, + port); + if (rc < 0) + goto fail1; + + stats_state.local_port = rc; + + DBG("(%u:%u) -> %u\n", stats_state.domid, port, stats_state.local_port); + + i = 0; + while (i < MAX_NR_PAGES) { + char *key; + char *ref_str; + uint32_t ref; + + rc = asprintf(&key, "%s/name-ref%u", stats_state.path, i); + if (rc < 0) + goto fail2; + + ref_str = xs_read(stats_state.xsh, XBT_NULL, key, NULL); + free(key); + + if (ref_str == NULL) + break; + + ref = strtol(ref_str, NULL, 0); + free(ref_str); + + DBG("name-ref%u = %u\n", i, ref); + + name_ref[i++] = ref; + } + nr_pages = i; + + i = 0; + while (i < nr_pages) { + char *key; + char *ref_str; + uint32_t ref; + + rc = asprintf(&key, "%s/val-ref%u", stats_state.path, i); + if (rc < 0) + goto fail3; + + ref_str = xs_read(stats_state.xsh, XBT_NULL, key, NULL); + free(key); + + if (ref_str == NULL) + break; + + ref = strtol(ref_str, NULL, 0); + free(ref_str); + + DBG("val-ref%u = %u\n", i, ref); + + val_ref[i++] = ref; + } + assert(i == nr_pages); + + DBG("%u page(s)\n", nr_pages); + + name_types = xengnttab_map_domain_grant_refs(stats_state.xgh, nr_pages, + stats_state.domid, + name_ref, + PROT_READ); + if (name_types == NULL) + goto fail4; + + rc = stats_parse_name_types(name_types, nr_pages); + if (rc < 0) + goto fail5; + + stats_state.values = xengnttab_map_domain_grant_refs(stats_state.xgh, + nr_pages, + stats_state.domid, + val_ref, + PROT_READ); + if (stats_state.values == NULL) + goto fail6; + + (void) xengnttab_unmap(stats_state.xgh, name_types, nr_pages); + + stats_state.nr_pages = nr_pages; + stats_state.bound = true; + + return 0; + +fail6: + DBG("fail6\n"); + + stats_free_name_types(); + +fail5: + DBG("fail5\n"); + + (void) xengnttab_unmap(stats_state.xgh, name_types, nr_pages); + +fail4: + DBG("fail4\n"); + +fail3: + DBG("fail3\n"); + +fail2: + DBG("fail2\n"); + + (void) xenevtchn_unbind(stats_state.xeh, stats_state.local_port); + +fail1: + DBG("fail1\n"); + + return -1; +} + +static void +stats_unbind(void) +{ + unsigned int nr_pages; + + nr_pages = stats_state.nr_pages; + + (void) xengnttab_unmap(stats_state.xgh, stats_state.values, nr_pages); + + stats_free_name_types(); + + (void) xenevtchn_unbind(stats_state.xeh, stats_state.local_port); + stats_state.bound = false; +} + +static int +stats_create_timer(void) +{ + int pfd[2]; + int flags; + timer_t tid; + struct sigevent sigev; + + memset(pfd, 0, sizeof (pfd)); + if (pipe(pfd) < 0) + goto fail1; + + flags = fcntl(pfd[0], F_GETFL); + fcntl(pfd[0], F_SETFL, flags | O_NONBLOCK); + + flags = fcntl(pfd[1], F_GETFL); + fcntl(pfd[1], F_SETFL, flags | O_NONBLOCK); + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_value.sival_int = pfd[1]; + + if (timer_create(CLOCK_MONOTONIC, &sigev, &tid) < 0) + goto fail2; + + stats_state.tid = tid; + stats_state.tfd = pfd[0]; + + return 0; + +fail2: + DBG("fail2\n"); + + close(pfd[1]); + close(pfd[0]); + +fail1: + DBG("fail1\n"); + + return -1; +} + +static void +stats_set_timer(unsigned int s) +{ + struct itimerspec it; + + it.it_interval.tv_sec = it.it_value.tv_sec = s; + it.it_interval.tv_nsec = it.it_value.tv_nsec = 0; + + (void) timer_settime(stats_state.tid, 0, &it, NULL); +} + +static void +stats_destroy_timer(void) +{ + timer_delete(stats_state.tid); + close(stats_state.tfd); +} + +static void +stats_teardown(void) +{ + if (stats_state.seq == STATS_SEQ_INITIALIZED) { + DBG("= STATS_SEQ_CTRL_OPEN) { + DBG("si_value.sival_int; + write(tfd, &buf, 1); +} + +static char * +stats_find_set(char *provider, char *set) +{ + char *path = NULL; + char **list = NULL; + unsigned int i, n; + bool found; + int rc; + + rc = asprintf(&path, "/local/domain/%u/stats", stats_state.domid); + if (rc < 0) + goto fail1; + + list = xs_directory(stats_state.xsh, XBT_NULL, path, &n); + if (list == NULL) + goto fail2; + + free(path); + path = NULL; + + found = false; + for (i = 0; i < n; i++) { + if (strcmp(provider, list[i]) == 0) { + found = true; + break; + } + } + + if (!found) + goto fail3; + + free(list); + list = NULL; + + rc = asprintf(&path, "/local/domain/%u/stats/%s", stats_state.domid, + provider); + if (rc < 0) + goto fail4; + + list = xs_directory(stats_state.xsh, XBT_NULL, path, &n); + if (list == NULL) + goto fail5; + + free(path); + path = NULL; + + found = false; + for (i = 0; i < n; i++) { + if (strcmp(set, list[i]) == 0) { + found = true; + break; + } + } + + if (!found) + goto fail6; + + free(list); + list = NULL; + + rc = asprintf(&path, "/local/domain/%u/stats/%s/%s", stats_state.domid, + provider, set); + if (rc < 0) + goto fail7; + + return path; + +fail7: + DBG("fail7\n"); + +fail6: + DBG("fail6\n"); + + free(list); + list = NULL; + +fail5: + DBG("fail5\n"); + + free(path); + path = NULL; + +fail4: + DBG("fail4\n"); + +fail3: + DBG("fail3\n"); + + if (list != NULL) { + free(list); + list = NULL; + } + +fail2: + DBG("fail2\n"); + + if (list != NULL) { + free(path); + path = NULL; + } + +fail1: + DBG("fail1\n"); + + return NULL; +} + +static int +stats_initialize(domid_t domid, char *provider, char *set) +{ + int rc; + xc_dominfo_t dominfo; + + stats_state.domid = domid; + + stats_state.xch = xc_interface_open(NULL, NULL, 0); + if (stats_state.xch == NULL) + goto fail1; + + stats_seq_next(STATS_SEQ_CTRL_OPEN); + + rc = xc_domain_getinfo(stats_state.xch, stats_state.domid, 1, &dominfo); + if (rc < 0 || dominfo.domid != stats_state.domid) + goto fail2; + + stats_state.xsh = xs_open(0); + if (stats_state.xsh == NULL) + goto fail3; + + stats_seq_next(STATS_SEQ_STORE_OPEN); + + stats_state.xeh = xenevtchn_open(NULL, 0); + + if (stats_state.xeh == NULL) + goto fail4; + + stats_seq_next(STATS_SEQ_EVTCHN_OPEN); + + stats_state.xgh = xengnttab_open(NULL, 0); + + if (stats_state.xgh == NULL) + goto fail5; + + stats_seq_next(STATS_SEQ_GNTTAB_OPEN); + + stats_state.path = stats_find_set(provider, set); + + if (stats_state.path == NULL) + goto fail6; + + stats_seq_next(STATS_SEQ_SET_FOUND); + + rc = stats_set_monitor_id(); + if (rc < 0) + goto fail7; + + stats_seq_next(STATS_SEQ_SET_NOTIFIED); + + rc = stats_create_watch(); + if (rc < 0) + goto fail8; + + stats_seq_next(STATS_SEQ_WATCH_CREATED); + + rc = stats_create_timer(); + if (rc < 0) + goto fail9; + + stats_seq_next(STATS_SEQ_TIMER_CREATED); + + stats_seq_next(STATS_SEQ_INITIALIZED); + + return 0; + +fail9: + DBG("fail9\n"); + +fail8: + DBG("fail8\n"); + +fail7: + DBG("fail7\n"); + +fail6: + DBG("fail6\n"); + +fail5: + DBG("fail5\n"); + +fail4: + DBG("fail4\n"); + +fail3: + DBG("fail3\n"); + +fail2: + DBG("fail2\n"); + +fail1: + DBG("fail1\n"); + + warn("fail"); + return -1; +} + +static void +stats_dump(void) +{ + struct xen_stats_value *value = stats_state.values; + unsigned int i; + + for (i = 0; i < stats_state.nr_stats; i++) { + switch (stats_state.type[i]) { + case XEN_STATS_TYPE_S64: + printf("%s = %ld\n", stats_state.name[i], + *(long *)value[i].buffer); + break; + + case XEN_STATS_TYPE_U64: + printf("%s = %lu\n", stats_state.name[i], + *(unsigned long *)value[i].buffer); + break; + + case XEN_STATS_TYPE_DOUBLE: + printf("%s = %f\n", stats_state.name[i], + *(double *)value[i].buffer); + break; + + case XEN_STATS_TYPE_ASCII: + printf("%s = %s\n", stats_state.name[i], + value[i].buffer); + break; + + default: + break; + } + } +} + +static void +stats_event(void) +{ + evtchn_port_t port; + + port = xenevtchn_pending(stats_state.xeh); + if (port != stats_state.local_port) + return; + + stats_dump(); + + xenevtchn_unmask(stats_state.xeh, port); +} + +static void +stats_watch(void) +{ + char **vec; + unsigned int n; + + vec = xs_read_watch(stats_state.xsh, &n); + if (vec == NULL) + return; + + assert(n == 2); + + if (strcmp(vec[XS_WATCH_TOKEN], stats_state.event_channel_token) == 0) { + char *port_str; + + port_str = xs_read(stats_state.xsh, XBT_NULL, + stats_state.event_channel_key, NULL); + if (port_str != NULL && !stats_state.bound) { + evtchn_port_t port; + + port = (evtchn_port_t)strtol(port_str, NULL, 0); + + (void) stats_bind(port); + } else if (port_str == NULL && stats_state.bound) { + stats_unbind(); + } + } + + free(vec); +} + +static void +stats_tick() +{ + if (stats_state.bound) + xenevtchn_notify(stats_state.xeh, stats_state.local_port); +} + +int +main(int argc, char **argv, char **envp) +{ + char *domain_str; + char *provider_str; + char *set_str; + char *interval_str; + int index; + domid_t domid; + unsigned int interval; + sigset_t block; + sigset_t unblock; + struct pollfd pfd[3]; + int rc; + + prog = basename(argv[0]); + + domain_str = NULL; + provider_str = NULL; + set_str = NULL; + interval_str = NULL; + + for (;;) { + char c; + + c = getopt_long(argc, argv, "", stats_option, &index); + if (c == -1) + break; + + if (c != 0) { + usage(); + /*NOTREACHED*/ + } + + DBG("--%s = '%s'\n", stats_option[index].name, optarg); + + switch (index) { + case STATS_OPT_DOMAIN: + domain_str = optarg; + break; + + case STATS_OPT_PROVIDER: + provider_str = optarg; + break; + + case STATS_OPT_SET: + set_str = optarg; + break; + + case STATS_OPT_INTERVAL: + interval_str = optarg; + break; + + default: + assert(FALSE); + break; + } + } + + if (domain_str == NULL || + provider_str == NULL || + set_str == NULL || + interval_str == NULL) { + usage(); + /*NOTREACHED*/ + } + + domid = (domid_t)strtol(domain_str, NULL, 0); + interval = (unsigned int)strtol(interval_str, NULL, 0); + + sigfillset(&block); + + memset(&sigterm_handler, 0, sizeof (struct sigaction)); + sigterm_handler.sa_handler = stats_sigabrt; + + sigaction(SIGABRT, &sigabrt_handler, NULL); + sigdelset(&block, SIGABRT); + + sigprocmask(SIG_BLOCK, &block, NULL); + + rc = stats_initialize(domid, provider_str, set_str); + if (rc < 0) { + stats_teardown(); + exit(1); + } + + sigemptyset(&unblock); + + memset(&sigterm_handler, 0, sizeof (struct sigaction)); + sigterm_handler.sa_handler = stats_sigterm; + + sigaction(SIGTERM, &sigterm_handler, NULL); + sigaddset(&unblock, SIGTERM); + + sigaction(SIGINT, &sigterm_handler, NULL); + sigaddset(&unblock, SIGINT); + + sigaction(SIGHUP, &sigterm_handler, NULL); + sigaddset(&unblock, SIGHUP); + + memset(&sigusr1_handler, 0, sizeof (struct sigaction)); + sigusr1_handler.sa_handler = stats_sigusr1; + + sigaction(SIGUSR1, &sigusr1_handler, NULL); + sigaddset(&unblock, SIGUSR1); + + memset(&sigrt_handler, 0, sizeof (struct sigaction)); + sigrt_handler.sa_flags = SA_SIGINFO; + sigrt_handler.sa_sigaction = stats_sigrt; + + sigaction(SIGRTMIN, &sigrt_handler, NULL); + sigaddset(&unblock, SIGRTMIN); + + sigprocmask(SIG_UNBLOCK, &unblock, NULL); + + pfd[0].fd = xenevtchn_fd(stats_state.xeh); + pfd[0].events = POLLIN | POLLERR | POLLHUP; + pfd[0].revents = 0; + + pfd[1].fd = xs_fileno(stats_state.xsh); + pfd[1].events = POLLIN | POLLERR | POLLHUP; + pfd[1].revents = 0; + + pfd[2].fd = stats_state.tfd; + pfd[2].events = POLLIN | POLLERR | POLLHUP; + pfd[2].revents = 0; + + stats_set_timer(interval); + + for (;;) { + rc = poll(pfd, 3, 5000); + + if (rc > 0) { + if (pfd[0].revents & POLLIN) + stats_event(); + + if (pfd[1].revents & POLLIN) + stats_watch(); + + if (pfd[2].revents & POLLIN) { + char buf; + + read(stats_state.tfd, &buf, 1); + stats_tick(); + stats_set_timer(interval); + } + } else if (rc < 0 && errno != EINTR) { + DBG("%s\n", strerror(errno)); + break; + } + } + + return 0; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * c-tab-always-indent: nil + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */