aboutsummaryrefslogtreecommitdiffstats
path: root/tools/console/daemon
diff options
context:
space:
mode:
authorKeir Fraser <keir@xensource.com>2007-10-29 14:43:19 +0000
committerKeir Fraser <keir@xensource.com>2007-10-29 14:43:19 +0000
commit14012a15e8c08c5852694c6ee170bf421480d817 (patch)
tree9d75aa56c3f35b26c606e62ee457a0c694bd3510 /tools/console/daemon
parentee41f1c835dd41a418b1afcd7394bcb4a16da6e1 (diff)
downloadxen-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/daemon')
-rw-r--r--tools/console/daemon/io.c74
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);