debuggers.hg

view tools/ioemu/patches/serial-port-rate-limit @ 0:7d21f7218375

Exact replica of unstable on 051908 + README-this
author Mukesh Rathor
date Mon May 19 15:34:57 2008 -0700 (2008-05-19)
parents
children
line source
1 # HG changeset patch
2 # User Steven Smith <ssmith@xensource.com>
3 # Node ID 1d3f52eb256e3522edc12daca91039b319dbbbe5
4 # Parent b7b653e36d20811831f26bb951ea66dca5854b17
5 [HVM] Rate limit guest accesses to the qemu virtual serial port. This stops
6 grub's boot menu from hammering dom0.
8 Signed-off-by: Steven Smith <sos22@cam.ac.uk>
10 Index: ioemu/hw/serial.c
11 ===================================================================
12 --- ioemu.orig/hw/serial.c 2007-05-03 18:18:01.000000000 +0100
13 +++ ioemu/hw/serial.c 2007-05-03 20:36:58.000000000 +0100
14 @@ -22,6 +22,9 @@
15 * THE SOFTWARE.
16 */
17 #include "vl.h"
18 +#include <sys/time.h>
19 +#include <time.h>
20 +#include <assert.h>
22 //#define DEBUG_SERIAL
24 @@ -140,6 +143,67 @@
25 #endif
26 }
28 +/* Rate limit serial requests so that e.g. grub on a serial console
29 + doesn't kill dom0. Simple token bucket. If we get some actual
30 + data from the user, instantly refil the bucket. */
31 +
32 +/* How long it takes to generate a token, in microseconds. */
33 +#define TOKEN_PERIOD 1000
34 +/* Maximum and initial size of token bucket */
35 +#define TOKENS_MAX 100000
36 +
37 +static int tokens_avail;
38 +
39 +static void serial_get_token(void)
40 +{
41 + static struct timeval last_refil_time;
42 + static int started;
43 +
44 + assert(tokens_avail >= 0);
45 + if (!tokens_avail) {
46 + struct timeval delta, now;
47 + int generated;
48 +
49 + if (!started) {
50 + gettimeofday(&last_refil_time, NULL);
51 + tokens_avail = TOKENS_MAX;
52 + started = 1;
53 + return;
54 + }
55 + retry:
56 + gettimeofday(&now, NULL);
57 + delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
58 + delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
59 + if (delta.tv_usec < 0) {
60 + delta.tv_usec += 1000000;
61 + delta.tv_sec--;
62 + }
63 + assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
64 + if (delta.tv_usec < TOKEN_PERIOD) {
65 + struct timespec ts;
66 + /* Wait until at least one token is available. */
67 + ts.tv_sec = TOKEN_PERIOD / 1000000;
68 + ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
69 + while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
70 + ;
71 + goto retry;
72 + }
73 + generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
74 + generated +=
75 + ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
76 + assert(generated > 0);
77 +
78 + last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
79 + last_refil_time.tv_sec += last_refil_time.tv_usec / 1000000;
80 + last_refil_time.tv_usec %= 1000000;
81 + last_refil_time.tv_sec += (generated * TOKEN_PERIOD) / 1000000;
82 + if (generated > TOKENS_MAX)
83 + generated = TOKENS_MAX;
84 + tokens_avail = generated;
85 + }
86 + tokens_avail--;
87 +}
88 +
89 static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
90 {
91 SerialState *s = opaque;
92 @@ -245,9 +309,11 @@
93 ret = s->mcr;
94 break;
95 case 5:
96 + serial_get_token();
97 ret = s->lsr;
98 break;
99 case 6:
100 + serial_get_token();
101 if (s->mcr & UART_MCR_LOOP) {
102 /* in loopback, the modem output pins are connected to the
103 inputs */
104 @@ -296,12 +362,14 @@
105 static void serial_receive1(void *opaque, const uint8_t *buf, int size)
106 {
107 SerialState *s = opaque;
108 + tokens_avail = TOKENS_MAX;
109 serial_receive_byte(s, buf[0]);
110 }
112 static void serial_event(void *opaque, int event)
113 {
114 SerialState *s = opaque;
115 + tokens_avail = TOKENS_MAX;
116 if (event == CHR_EVENT_BREAK)
117 serial_receive_break(s);
118 }