diff options
author | Keir Fraser <keir@xensource.com> | 2007-10-29 14:43:19 +0000 |
---|---|---|
committer | Keir Fraser <keir@xensource.com> | 2007-10-29 14:43:19 +0000 |
commit | 14012a15e8c08c5852694c6ee170bf421480d817 (patch) | |
tree | 9d75aa56c3f35b26c606e62ee457a0c694bd3510 /tools/console | |
parent | ee41f1c835dd41a418b1afcd7394bcb4a16da6e1 (diff) | |
download | xen-14012a15e8c08c5852694c6ee170bf421480d817.tar.gz xen-14012a15e8c08c5852694c6ee170bf421480d817.tar.bz2 xen-14012a15e8c08c5852694c6ee170bf421480d817.zip |
xenconsoled: Rate-limit activity caused by each domU.
Allow each domU to fire its event channel at most 30 times every 200ms.
Signed-off by: Daniel P. Berrange <berrange@redhat.com>
Diffstat (limited to 'tools/console')
-rw-r--r-- | tools/console/daemon/io.c | 74 |
1 files changed, 68 insertions, 6 deletions
diff --git a/tools/console/daemon/io.c b/tools/console/daemon/io.c index e463a61b09..87b45cb9bd 100644 --- a/tools/console/daemon/io.c +++ b/tools/console/daemon/io.c @@ -35,6 +35,7 @@ #include <termios.h> #include <stdarg.h> #include <sys/mman.h> +#include <sys/time.h> #if defined(__NetBSD__) || defined(__OpenBSD__) #include <util.h> #elif defined(__linux__) || defined(__Linux__) @@ -47,6 +48,11 @@ /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */ #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2) +/* How many events are allowed in each time period */ +#define RATE_LIMIT_ALLOWANCE 30 +/* Duration of each time period in ms */ +#define RATE_LIMIT_PERIOD 200 + extern int log_reload; extern int log_guest; extern int log_hv; @@ -82,6 +88,8 @@ struct domain evtchn_port_or_error_t remote_port; int xce_handle; struct xencons_interface *interface; + int event_count; + long long next_period; }; static struct domain *dom_head; @@ -494,6 +502,13 @@ static struct domain *create_domain(int domid) { struct domain *dom; char *s; + struct timeval tv; + + if (gettimeofday(&tv, NULL) < 0) { + dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d", + __FILE__, __FUNCTION__, __LINE__); + return NULL; + } dom = (struct domain *)malloc(sizeof(struct domain)); if (dom == NULL) { @@ -529,6 +544,8 @@ static struct domain *create_domain(int domid) dom->buffer.size = 0; dom->buffer.capacity = 0; dom->buffer.max_capacity = 0; + dom->event_count = 0; + dom->next_period = (tv.tv_sec * 1000) + (tv.tv_usec / 1000) + RATE_LIMIT_PERIOD; dom->next = NULL; dom->ring_ref = -1; @@ -720,9 +737,12 @@ static void handle_ring_read(struct domain *dom) if ((port = xc_evtchn_pending(dom->xce_handle)) == -1) return; + dom->event_count++; + buffer_append(dom); - (void)xc_evtchn_unmask(dom->xce_handle, port); + if (dom->event_count < RATE_LIMIT_ALLOWANCE) + (void)xc_evtchn_unmask(dom->xce_handle, port); } static void handle_xs(void) @@ -820,6 +840,9 @@ void handle_io(void) for (;;) { struct domain *d, *n; int max_fd = -1; + struct timeval timeout; + struct timeval tv; + long long now, next_timeout = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); @@ -832,8 +855,33 @@ void handle_io(void) max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd); } + if (gettimeofday(&tv, NULL) < 0) + return; + now = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); + + /* Re-calculate any event counter allowances & unblock + domains with new allowance */ for (d = dom_head; d; d = d->next) { - if (d->xce_handle != -1) { + /* Add 5ms of fuzz since select() often returns + a couple of ms sooner than requested. Without + the fuzz we typically do an extra spin in select() + with a 1/2 ms timeout every other iteration */ + if ((now+5) > d->next_period) { + d->next_period = now + RATE_LIMIT_PERIOD; + if (d->event_count >= RATE_LIMIT_ALLOWANCE) { + (void)xc_evtchn_unmask(d->xce_handle, d->local_port); + } + d->event_count = 0; + } + } + + for (d = dom_head; d; d = d->next) { + if (d->event_count >= RATE_LIMIT_ALLOWANCE) { + /* Determine if we're going to be the next time slice to expire */ + if (!next_timeout || + d->next_period < next_timeout) + next_timeout = d->next_period; + } else if (d->xce_handle != -1) { int evtchn_fd = xc_evtchn_fd(d->xce_handle); FD_SET(evtchn_fd, &readfds); max_fd = MAX(evtchn_fd, max_fd); @@ -849,7 +897,19 @@ void handle_io(void) } } - ret = select(max_fd + 1, &readfds, &writefds, 0, NULL); + /* If any domain has been rate limited, we need to work + out what timeout to supply to select */ + if (next_timeout) { + long long duration = (next_timeout - now); + if (duration <= 0) /* sanity check */ + duration = 1; + timeout.tv_sec = duration / 1000; + timeout.tv_usec = ((duration - (timeout.tv_sec * 1000)) + * 1000); + } + + ret = select(max_fd + 1, &readfds, &writefds, 0, + next_timeout ? &timeout : NULL); if (log_reload) { handle_log_reload(); @@ -877,9 +937,11 @@ void handle_io(void) for (d = dom_head; d; d = n) { n = d->next; - if (d->xce_handle != -1 && - FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds)) - handle_ring_read(d); + if (d->event_count < RATE_LIMIT_ALLOWANCE) { + if (d->xce_handle != -1 && + FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds)) + handle_ring_read(d); + } if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &readfds)) handle_tty_read(d); |