WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

Re: [Xen-devel] [RFC] PVFB: Add refresh period to XenStore parameters?

To: Markus Armbruster <armbru@xxxxxxxxxx>
Subject: Re: [Xen-devel] [RFC] PVFB: Add refresh period to XenStore parameters?
From: Samuel Thibault <samuel.thibault@xxxxxxxxxxxxx>
Date: Thu, 8 May 2008 16:01:46 +0100
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Thu, 08 May 2008 08:02:14 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
In-reply-to: <877ie5i4n7.fsf@xxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Mail-followup-to: Samuel Thibault <samuel.thibault@xxxxxxxxxxxxx>, Markus Armbruster <armbru@xxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxx
References: <20080505091808.GC4497@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> <87ej8hysv6.fsf@xxxxxxxxxxxxxxxxx> <20080505165008.GP4497@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> <87ve1rv8xb.fsf@xxxxxxxxxxxxxxxxx> <20080506163255.GP4430@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> <87lk2ntm0z.fsf@xxxxxxxxxxxxxxxxx> <20080506172959.GR4430@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> <871w4emaxx.fsf@xxxxxxxxxxxxxxxxx> <20080507145426.GL4562@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx> <877ie5i4n7.fsf@xxxxxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.12-2006-07-14
Hello,

Markus Armbruster, le Thu 08 May 2008 10:25:32 +0200, a écrit :
> Strictly speaking, frame buffer update and update notification events
> are separate things.

Right, let's call the first one "refresh".

> What you seem to need is *not* a way to control *notifications*, but a
> way to control *updates*.  Because your shared framebuffer isn't
> really a framebuffer, but some shadow of the real framebuffer.
> Correct?

Yes.  Here is an updated patch.



pvfb/ioemu: transmit refresh interval advice from backend to frontend
which permits the frontend to avoid useless polls.

Signed-off-by: Samuel Thibault <samuel.thibault@xxxxxxxxxxxxx>

diff -r b0d7780794eb extras/mini-os/fbfront.c
--- a/extras/mini-os/fbfront.c  Thu May 08 13:40:40 2008 +0100
+++ b/extras/mini-os/fbfront.c  Thu May 08 15:47:13 2008 +0100
@@ -255,11 +255,55 @@ struct fbfront_dev {
     int offset;
 
     xenbus_event_queue events;
+
+#ifdef HAVE_LIBC
+    int fd;
+#endif
 };
 
 void fbfront_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
 {
+#ifdef HAVE_LIBC
+    struct fbfront_dev *dev = data;
+    int fd = dev->fd;
+
+    files[fd].read = 1;
+#endif
     wake_up(&fbfront_queue);
+}
+
+int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n)
+{
+    struct xenfb_page *page = dev->page;
+    uint32_t prod, cons;
+    int i;
+
+#ifdef HAVE_LIBC
+    files[dev->fd].read = 0;
+    mb(); /* Make sure to let the handler set read to 1 before we start 
looking at the ring */
+#endif
+
+    prod = page->in_prod;
+
+    if (prod == page->in_cons)
+        return 0;
+
+    rmb();      /* ensure we see ring contents up to prod */
+
+    for (i = 0, cons = page->in_cons; i < n && cons != prod; i++, cons++)
+        memcpy(buf + i, &XENFB_IN_RING_REF(page, cons), sizeof(*buf));
+
+    mb();       /* ensure we got ring contents */
+    page->in_cons = cons;
+    notify_remote_via_evtchn(dev->evtchn);
+
+#ifdef HAVE_LIBC
+    if (cons != prod)
+        /* still some events to read */
+        files[dev->fd].read = 1;
+#endif
+
+    return i;
 }
 
 struct fbfront_dev *init_fbfront(char *nodename, unsigned long *mfns, int 
width, int height, int depth, int stride, int n)
@@ -482,3 +526,14 @@ void shutdown_fbfront(struct fbfront_dev
     free(dev->backend);
     free(dev);
 }
+
+#ifdef HAVE_LIBC
+int fbfront_open(struct fbfront_dev *dev)
+{
+    dev->fd = alloc_fd(FTYPE_FB);
+    printk("fb_open(%s) -> %d\n", dev->nodename, dev->fd);
+    files[dev->fd].fb.dev = dev;
+    return dev->fd;
+}
+#endif
+
diff -r b0d7780794eb extras/mini-os/include/fbfront.h
--- a/extras/mini-os/include/fbfront.h  Thu May 08 13:40:40 2008 +0100
+++ b/extras/mini-os/include/fbfront.h  Thu May 08 15:47:13 2008 +0100
@@ -1,4 +1,5 @@
 #include <xen/io/kbdif.h>
+#include <xen/io/fbif.h>
 #include <wait.h>
 
 /* from <linux/input.h> */
@@ -36,6 +37,8 @@ int fbfront_open(struct fbfront_dev *dev
 int fbfront_open(struct fbfront_dev *dev);
 #endif
 
+int fbfront_receive(struct fbfront_dev *dev, union xenfb_in_event *buf, int n);
+extern struct wait_queue_head fbfront_queue;
 void fbfront_update(struct fbfront_dev *dev, int x, int y, int width, int 
height);
 void fbfront_resize(struct fbfront_dev *dev, int width, int height, int 
stride, int depth, int offset);
 
diff -r b0d7780794eb extras/mini-os/include/lib.h
--- a/extras/mini-os/include/lib.h      Thu May 08 13:40:40 2008 +0100
+++ b/extras/mini-os/include/lib.h      Thu May 08 15:47:13 2008 +0100
@@ -141,6 +141,7 @@ enum fd_type {
     FTYPE_TAP,
     FTYPE_BLK,
     FTYPE_KBD,
+    FTYPE_FB,
 };
 
 #define MAX_EVTCHN_PORTS 16
@@ -175,6 +176,9 @@ extern struct file {
        struct {
            struct kbdfront_dev *dev;
        } kbd;
+       struct {
+           struct fbfront_dev *dev;
+       } fb;
         struct {
             /* To each xenbus FD is associated a queue of watch events for this
              * FD.  */
diff -r b0d7780794eb extras/mini-os/kernel.c
--- a/extras/mini-os/kernel.c   Thu May 08 13:40:40 2008 +0100
+++ b/extras/mini-os/kernel.c   Thu May 08 15:47:13 2008 +0100
@@ -260,6 +260,7 @@ static void blkfront_thread(void *p)
 #define DEPTH 32
 
 static uint32_t *fb;
+static int refresh_period = 50;
 static struct fbfront_dev *fb_dev;
 static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
 
@@ -333,6 +334,10 @@
 static void refresh_cursor(int new_x, int new_y)
 {
     static int old_x = -1, old_y = -1;
+
+    if (!refresh_period)
+        return;
+
     if (old_x != -1 && old_y != -1) {
         fbfront_drawvert(old_x, old_y + 1, old_y + 8, 0xffffffff);
         fbfront_drawhoriz(old_x + 1, old_x + 8, old_y, 0xffffffff);
@@ -358,43 +363,46 @@ static void kbdfront_thread(void *p)
     down(&fbfront_sem);
     refresh_cursor(x, y);
     while (1) {
-        union xenkbd_in_event event;
+        union xenkbd_in_event kbdevent;
+        union xenfb_in_event fbevent;
+        int sleep = 1;
 
         add_waiter(w, kbdfront_queue);
+        add_waiter(w, fbfront_queue);
 
-        if (kbdfront_receive(kbd_dev, &event, 1) == 0)
-            schedule();
-        else switch(event.type) {
+        while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) {
+            sleep = 0;
+            switch(kbdevent.type) {
             case XENKBD_TYPE_MOTION:
                 printk("motion x:%d y:%d z:%d\n",
-                        event.motion.rel_x,
-                        event.motion.rel_y,
-                        event.motion.rel_z);
-                x += event.motion.rel_x;
-                y += event.motion.rel_y;
-                z += event.motion.rel_z;
+                        kbdevent.motion.rel_x,
+                        kbdevent.motion.rel_y,
+                        kbdevent.motion.rel_z);
+                x += kbdevent.motion.rel_x;
+                y += kbdevent.motion.rel_y;
+                z += kbdevent.motion.rel_z;
                 clip_cursor(&x, &y);
                 refresh_cursor(x, y);
                 break;
             case XENKBD_TYPE_POS:
                 printk("pos x:%d y:%d dz:%d\n",
-                        event.pos.abs_x,
-                        event.pos.abs_y,
-                        event.pos.rel_z);
-                x = event.pos.abs_x;
-                y = event.pos.abs_y;
-                z = event.pos.rel_z;
+                        kbdevent.pos.abs_x,
+                        kbdevent.pos.abs_y,
+                        kbdevent.pos.rel_z);
+                x = kbdevent.pos.abs_x;
+                y = kbdevent.pos.abs_y;
+                z = kbdevent.pos.rel_z;
                 clip_cursor(&x, &y);
                 refresh_cursor(x, y);
                 break;
             case XENKBD_TYPE_KEY:
                 printk("key %d %s\n",
-                        event.key.keycode,
-                        event.key.pressed ? "pressed" : "released");
-                if (event.key.keycode == BTN_LEFT) {
+                        kbdevent.key.keycode,
+                        kbdevent.key.pressed ? "pressed" : "released");
+                if (kbdevent.key.keycode == BTN_LEFT) {
                     printk("mouse %s at (%d,%d,%d)\n",
-                            event.key.pressed ? "clic" : "release", x, y, z);
-                    if (event.key.pressed) {
+                            kbdevent.key.pressed ? "clic" : "release", x, y, 
z);
+                    if (kbdevent.key.pressed) {
                         uint32_t color = rand();
                         fbfront_drawvert(x - 16, y - 16, y + 15, color);
                         fbfront_drawhoriz(x - 16, x + 15, y + 16, color);
@@ -402,13 +410,26 @@ static void kbdfront_thread(void *p)
                         fbfront_drawhoriz(x - 15, x + 16, y - 16, color);
                         fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
                     }
-                } else if (event.key.keycode == KEY_Q) {
+                } else if (kbdevent.key.keycode == KEY_Q) {
                     struct sched_shutdown sched_shutdown = { .reason = 
SHUTDOWN_poweroff };
                     HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
                     do_exit();
                 }
                 break;
+            }
         }
+        while (fbfront_receive(fb_dev, &fbevent, 1) != 0) {
+            sleep = 0;
+            switch(fbevent.type) {
+            case XENFB_TYPE_REFRESH_PERIOD:
+                refresh_period = fbevent.refresh_period.period;
+                printk("refresh period %d\n", refresh_period);
+                refresh_cursor(x, y);
+                break;
+            }
+        }
+        if (sleep)
+            schedule();
     }
 }
 
diff -r b0d7780794eb extras/mini-os/lib/sys.c
--- a/extras/mini-os/lib/sys.c  Thu May 08 13:40:40 2008 +0100
+++ b/extras/mini-os/lib/sys.c  Thu May 08 15:47:13 2008 +0100
@@ -249,6 +251,16 @@ int read(int fd, void *buf, size_t nbyte
            }
            return ret * sizeof(union xenkbd_in_event);
         }
+        case FTYPE_FB: {
+            int ret, n;
+            n = nbytes / sizeof(union xenfb_in_event);
+            ret = fbfront_receive(files[fd].fb.dev, buf, n);
+           if (ret <= 0) {
+               errno = EAGAIN;
+               return -1;
+           }
+           return ret * sizeof(union xenfb_in_event);
+        }
        case FTYPE_NONE:
        case FTYPE_XENBUS:
        case FTYPE_EVTCHN:
@@ -290,6 +302,7 @@ int write(int fd, const void *buf, size_
        case FTYPE_EVTCHN:
        case FTYPE_BLK:
        case FTYPE_KBD:
+       case FTYPE_FB:
            break;
     }
     printk("write(%d): Bad descriptor\n", fd);
@@ -348,6 +361,7 @@ int fsync(int fd) {
        case FTYPE_TAP:
        case FTYPE_BLK:
        case FTYPE_KBD:
+       case FTYPE_FB:
            break;
     }
     printk("fsync(%d): Bad descriptor\n", fd);
@@ -392,6 +406,10 @@ int close(int fd)
            return 0;
        case FTYPE_KBD:
             shutdown_kbdfront(files[fd].kbd.dev);
+            files[fd].type = FTYPE_NONE;
+            return 0;
+       case FTYPE_FB:
+            shutdown_fbfront(files[fd].fb.dev);
             files[fd].type = FTYPE_NONE;
             return 0;
        case FTYPE_NONE:
@@ -485,6 +503,7 @@ int fstat(int fd, struct stat *buf)
        case FTYPE_TAP:
        case FTYPE_BLK:
        case FTYPE_KBD:
+       case FTYPE_FB:
            break;
     }
 
@@ -513,6 +532,7 @@ int ftruncate(int fd, off_t length)
        case FTYPE_TAP:
        case FTYPE_BLK:
        case FTYPE_KBD:
+       case FTYPE_FB:
            break;
     }
 
@@ -624,6 +644,7 @@ static const char file_types[] = {
     [FTYPE_TAP]                = 'T',
     [FTYPE_BLK]                = 'B',
     [FTYPE_KBD]                = 'K',
+    [FTYPE_FB]         = 'G',
 };
 #ifdef LIBC_DEBUG
 static void dump_set(int nfds, fd_set *readfds, fd_set *writefds, fd_set 
*exceptfds, struct timeval *timeout)
@@ -732,6 +753,7 @@ static int select_poll(int nfds, fd_set 
        case FTYPE_TAP:
        case FTYPE_BLK:
        case FTYPE_KBD:
+       case FTYPE_FB:
            if (FD_ISSET(i, readfds)) {
                if (files[i].read)
                    n++;
diff -r b0d7780794eb tools/ioemu/hw/xenfb.c
--- a/tools/ioemu/hw/xenfb.c    Thu May 08 13:40:40 2008 +0100
+++ b/tools/ioemu/hw/xenfb.c    Thu May 08 15:47:13 2008 +0100
@@ -59,6 +59,7 @@ struct xenfb {
        int offset;             /* offset of the framebuffer */
        int abs_pointer_wanted; /* Whether guest supports absolute pointer */
        int button_state;       /* Last seen pointer button state */
+       int refresh_period;     /* The refresh period we have advised */
        char protocol[64];      /* frontend protocol */
 };
 
@@ -536,6 +537,41 @@ static void xenfb_on_fb_event(struct xen
        xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
 }
 
+static int xenfb_queue_full(struct xenfb *xenfb)
+{
+       struct xenfb_page *page = xenfb->fb.page;
+       uint32_t cons, prod;
+
+       prod = page->in_prod;
+       cons = page->in_cons;
+       return prod - cons == XENFB_IN_RING_LEN;
+}
+
+static void xenfb_send_event(struct xenfb *xenfb, union xenfb_in_event *event)
+{
+       uint32_t prod;
+       struct xenfb_page *page = xenfb->fb.page;
+
+       prod = page->in_prod;
+       /* caller ensures !xenfb_queue_full() */
+       xen_mb();                   /* ensure ring space available */
+       XENFB_IN_RING_REF(page, prod) = *event;
+       xen_wmb();                  /* ensure ring contents visible */
+       page->in_prod = prod + 1;
+
+       xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+static void xenfb_send_refresh_period(struct xenfb *xenfb, int period)
+{
+       union xenfb_in_event event;
+
+       memset(&event, 0, sizeof(event));
+       event.type = XENFB_TYPE_REFRESH_PERIOD;
+       event.refresh_period.period = period;
+       xenfb_send_event(xenfb, &event);
+}
+
 static void xenfb_on_kbd_event(struct xenfb *xenfb)
 {
        struct xenkbd_page *page = xenfb->kbd.page;
@@ -707,6 +743,7 @@ static int xenfb_read_frontend_fb_config
                             xenfb->protocol) < 0)
                 xenfb->protocol[0] = '\0';
         xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
+        xenfb->refresh_period = -1;
 
         /* TODO check for permitted ranges */
         fb_page = xenfb->fb.page;
@@ -1185,10 +1222,28 @@ static void xenfb_guest_copy(struct xenf
     dpy_update(xenfb->ds, x, y, w, h);
 }
 
-/* Periodic update of display, no need for any in our case */
+/* Periodic update of display, transmit the refresh interval to the frontend */
 static void xenfb_update(void *opaque)
 {
     struct xenfb *xenfb = opaque;
+    int period;
+
+    if (xenfb_queue_full(xenfb))
+        return;
+
+    if (xenfb->ds->idle)
+        period = 0;
+    else {
+        period = xenfb->ds->gui_timer_interval;
+        if (!period)
+            period = GUI_REFRESH_INTERVAL;
+    }
+
+    /* Will have to be disabled for frontends without feature-update */
+    if (xenfb->refresh_period != period) {
+        xenfb_send_refresh_period(xenfb, period);
+        xenfb->refresh_period = period;
+    }
 }
 
 /* QEMU display state changed, so refresh the framebuffer copy */
@@ -1232,11 +1287,17 @@ static int xenfb_register_console(struct
 }
 
 #ifdef CONFIG_STUBDOM
-static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
-static struct kbdfront_dev *kbd_dev;
+typedef struct XenFBState {
+    struct semaphore kbd_sem;
+    struct kbdfront_dev *kbd_dev;
+    struct fbfront_dev *fb_dev;
+    void *vga_vram, *nonshared_vram;
+    DisplayState *ds;
+} XenFBState;
+
+XenFBState *xs;
+
 static char *kbd_path, *fb_path;
-static void *vga_vram, *nonshared_vram;
-static DisplayState *xenfb_ds;
 
 static unsigned char linux2scancode[KEY_MAX + 1];
 
@@ -1254,7 +1315,8 @@ int xenfb_connect_vfb(const char *path)
 
 static void xenfb_pv_update(DisplayState *ds, int x, int y, int w, int h)
 {
-    struct fbfront_dev *fb_dev = ds->opaque;
+    XenFBState *xs = ds->opaque;
+    struct fbfront_dev *fb_dev = xs->fb_dev;
     if (!fb_dev)
         return;
     fbfront_update(fb_dev, x, y, w, h);
@@ -1262,7 +1324,8 @@ static void xenfb_pv_update(DisplayState
 
 static void xenfb_pv_resize(DisplayState *ds, int w, int h, int linesize)
 {
-    struct fbfront_dev *fb_dev = ds->opaque;
+    XenFBState *xs = ds->opaque;
+    struct fbfront_dev *fb_dev = xs->fb_dev;
     fprintf(stderr,"resize to %dx%d, %d required\n", w, h, linesize);
     ds->width = w;
     ds->height = h;
@@ -1276,14 +1339,15 @@ static void xenfb_pv_resize(DisplayState
     if (ds->shared_buf) {
         ds->data = NULL;
     } else {
-        ds->data = nonshared_vram;
+        ds->data = xs->nonshared_vram;
         fbfront_resize(fb_dev, w, h, linesize, ds->depth, VGA_RAM_SIZE);
     }
 }
 
 static void xenfb_pv_colourdepth(DisplayState *ds, int depth)
 {
-    struct fbfront_dev *fb_dev = ds->opaque;
+    XenFBState *xs = ds->opaque;
+    struct fbfront_dev *fb_dev = xs->fb_dev;
     static int lastdepth = -1;
     if (!depth) {
         ds->shared_buf = 0;
@@ -1301,15 +1365,16 @@ static void xenfb_pv_colourdepth(Display
     if (ds->shared_buf) {
         ds->data = NULL;
     } else {
-        ds->data = nonshared_vram;
+        ds->data = xs->nonshared_vram;
         fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, 
VGA_RAM_SIZE);
     }
 }
 
 static void xenfb_pv_setdata(DisplayState *ds, void *pixels)
 {
-    struct fbfront_dev *fb_dev = ds->opaque;
-    int offset = pixels - vga_vram;
+    XenFBState *xs = ds->opaque;
+    struct fbfront_dev *fb_dev = xs->fb_dev;
+    int offset = pixels - xs->vga_vram;
     ds->data = pixels;
     if (!fb_dev)
         return;
@@ -1321,16 +1386,45 @@ static void xenfb_pv_refresh(DisplayStat
     vga_hw_update();
 }
 
+static void xenfb_fb_handler(void *opaque)
+{
+#define FB_NUM_BATCH 4
+    union xenfb_in_event buf[FB_NUM_BATCH];
+    int n, i;
+    XenFBState *xs = opaque;
+    DisplayState *ds = xs->ds;
+
+    n = fbfront_receive(xs->fb_dev, buf, FB_NUM_BATCH);
+    for (i = 0; i < n; i++) {
+        switch (buf[i].type) {
+        case XENFB_TYPE_REFRESH_PERIOD:
+            if (buf[i].refresh_period.period) {
+                /* Set interval */
+                ds->idle = 0;
+                ds->gui_timer_interval = buf[i].refresh_period.period;
+            } else {
+                /* Sleeping interval */
+                ds->idle = 1;
+                ds->gui_timer_interval = 500;
+            }
+        default:
+            /* ignore unknown events */
+            break;
+        }
+    }
+}
+
 static void xenfb_kbd_handler(void *opaque)
 {
 #define KBD_NUM_BATCH 64
     union xenkbd_in_event buf[KBD_NUM_BATCH];
     int n, i;
-    DisplayState *s = opaque;
+    XenFBState *xs = opaque;
+    DisplayState *s = xs->ds;
     static int buttons;
     static int x, y;
 
-    n = kbdfront_receive(kbd_dev, buf, KBD_NUM_BATCH);
+    n = kbdfront_receive(xs->kbd_dev, buf, KBD_NUM_BATCH);
     for (i = 0; i < n; i++) {
         switch (buf[i].type) {
 
@@ -1412,12 +1506,13 @@ static void kbdfront_thread(void *p)
 static void kbdfront_thread(void *p)
 {
     int scancode, keycode;
-    kbd_dev = init_kbdfront(p, 1);
-    if (!kbd_dev) {
+    XenFBState *xs = p;
+    xs->kbd_dev = init_kbdfront(kbd_path, 1);
+    if (!xs->kbd_dev) {
         fprintf(stderr,"can't open keyboard\n");
         exit(1);
     }
-    up(&kbd_sem);
+    up(&xs->kbd_sem);
     for (scancode = 0; scancode < 128; scancode++) {
         keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode]];
         linux2scancode[keycode] = scancode;
@@ -1431,12 +1526,18 @@ int xenfb_pv_display_init(DisplayState *
     if (!fb_path || !kbd_path)
         return -1;
 
-    create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
+    xs = qemu_mallocz(sizeof(XenFBState));
+    if (!xs)
+        return -1;
 
-    xenfb_ds = ds;
+    init_SEMAPHORE(&xs->kbd_sem, 0);
+    xs->ds = ds;
 
-    ds->data = nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
+    create_thread("kbdfront", kbdfront_thread, (void*) xs);
+
+    ds->data = xs->nonshared_vram = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
     memset(ds->data, 0, VGA_RAM_SIZE);
+    ds->opaque = xs;
     ds->depth = 32;
     ds->bgr = 0;
     ds->width = 640;
@@ -1452,9 +1553,9 @@ int xenfb_pv_display_init(DisplayState *
 
 int xenfb_pv_display_start(void *data)
 {
-    DisplayState *ds = xenfb_ds;
+    DisplayState *ds = xs->ds;
     struct fbfront_dev *fb_dev;
-    int kbd_fd;
+    int kbd_fd, fb_fd;
     int offset = 0;
     unsigned long *mfns;
     int n = VGA_RAM_SIZE / PAGE_SIZE;
@@ -1463,12 +1564,12 @@ int xenfb_pv_display_start(void *data)
     if (!fb_path || !kbd_path)
         return 0;
 
-    vga_vram = data;
+    xs->vga_vram = data;
     mfns = malloc(2 * n * sizeof(*mfns));
     for (i = 0; i < n; i++)
-        mfns[i] = virtual_to_mfn(vga_vram + i * PAGE_SIZE);
+        mfns[i] = virtual_to_mfn(xs->vga_vram + i * PAGE_SIZE);
     for (i = 0; i < n; i++)
-        mfns[n + i] = virtual_to_mfn(nonshared_vram + i * PAGE_SIZE);
+        mfns[n + i] = virtual_to_mfn(xs->nonshared_vram + i * PAGE_SIZE);
 
     fb_dev = init_fbfront(fb_path, mfns, ds->width, ds->height, ds->depth, 
ds->linesize, 2 * n);
     free(mfns);
@@ -1479,21 +1580,24 @@ int xenfb_pv_display_start(void *data)
     free(fb_path);
 
     if (ds->shared_buf) {
-        offset = (void*) ds->data - vga_vram;
+        offset = (void*) ds->data - xs->vga_vram;
     } else {
         offset = VGA_RAM_SIZE;
-        ds->data = nonshared_vram;
+        ds->data = xs->nonshared_vram;
     }
     if (offset)
         fbfront_resize(fb_dev, ds->width, ds->height, ds->linesize, ds->depth, 
offset);
 
-    down(&kbd_sem);
+    down(&xs->kbd_sem);
     free(kbd_path);
 
-    kbd_fd = kbdfront_open(kbd_dev);
-    qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds);
+    kbd_fd = kbdfront_open(xs->kbd_dev);
+    qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, xs);
 
-    xenfb_ds->opaque = fb_dev;
+    fb_fd = fbfront_open(fb_dev);
+    qemu_set_fd_handler(fb_fd, xenfb_fb_handler, NULL, xs);
+
+    xs->fb_dev = fb_dev;
     return 0;
 }
 #endif
diff -r b0d7780794eb tools/ioemu/sdl.c
--- a/tools/ioemu/sdl.c Thu May 08 13:40:40 2008 +0100
+++ b/tools/ioemu/sdl.c Thu May 08 15:47:13 2008 +0100
@@ -696,9 +696,11 @@ static int select_poll(int nfds, fd_set 
                if (ev->active.gain) {
                    /* Back to default interval */
                    ds->gui_timer_interval = 0;
+                   ds->idle = 0;
                } else {
                    /* Sleeping interval */
                    ds->gui_timer_interval = 500;
+                   ds->idle = 1;
                }
            }
             break;
diff -r b0d7780794eb tools/ioemu/vl.c
--- a/tools/ioemu/vl.c  Thu May 08 13:40:40 2008 +0100
+++ b/tools/ioemu/vl.c  Thu May 08 15:47:13 2008 +0100
@@ -130,8 +130,6 @@
 #else
 #define DEFAULT_RAM_SIZE 128
 #endif
-/* in ms */
-#define GUI_REFRESH_INTERVAL 30
 
 /* Max number of USB devices that can be specified on the commandline.  */
 #define MAX_USB_CMDLINE 8
@@ -4467,6 +4465,8 @@ void dumb_display_init(DisplayState *ds)
     ds->dpy_resize = dumb_resize;
     ds->dpy_colourdepth = NULL;
     ds->dpy_refresh = dumb_refresh;
+    ds->gui_timer_interval = 500;
+    ds->idle = 1;
 }
 
 /***********************************************************/
diff -r b0d7780794eb tools/ioemu/vl.h
--- a/tools/ioemu/vl.h  Thu May 08 13:40:40 2008 +0100
+++ b/tools/ioemu/vl.h  Thu May 08 15:47:13 2008 +0100
@@ -929,6 +929,9 @@ extern struct soundhw soundhw[];
 
 #define VGA_RAM_SIZE (8192 * 1024)
 
+/* in ms */
+#define GUI_REFRESH_INTERVAL 30
+
 struct DisplayState {
     uint8_t *data;
     int linesize;
@@ -939,6 +942,7 @@ struct DisplayState {
     void *opaque;
     uint32_t *palette;
     uint64_t gui_timer_interval;
+    int idle;
 
     int shared_buf;
     
diff -r b0d7780794eb tools/ioemu/vnc.c
--- a/tools/ioemu/vnc.c Thu May 08 13:40:40 2008 +0100
+++ b/tools/ioemu/vnc.c Thu May 08 15:47:13 2008 +0100
@@ -778,6 +778,7 @@ static void _vnc_update_client(void *opa
     vs->has_update = 0;
     vnc_flush(vs);
     vs->last_update_time = now;
+    vs->ds->idle = 0;
 
     vs->timer_interval /= 2;
     if (vs->timer_interval < VNC_REFRESH_INTERVAL_BASE)
@@ -790,26 +791,29 @@ static void _vnc_update_client(void *opa
     vs->timer_interval += VNC_REFRESH_INTERVAL_INC;
     if (vs->timer_interval > VNC_REFRESH_INTERVAL_MAX) {
        vs->timer_interval = VNC_REFRESH_INTERVAL_MAX;
-       if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL &&
-            vs->update_requested) {
-           /* Send a null update.  If the client is no longer
-              interested (e.g. minimised) it'll ignore this, and we
-              can stop scanning the buffer until it sends another
-              update request. */
-           /* It turns out that there's a bug in realvncviewer 4.1.2
-              which means that if you send a proper null update (with
-              no update rectangles), it gets a bit out of sync and
-              never sends any further requests, regardless of whether
-              it needs one or not.  Fix this by sending a single 1x1
-              update rectangle instead. */
-           vnc_write_u8(vs, 0);
-           vnc_write_u8(vs, 0);
-           vnc_write_u16(vs, 1);
-           send_framebuffer_update(vs, 0, 0, 1, 1);
-           vnc_flush(vs);
-           vs->last_update_time = now;
-            vs->update_requested--;
-           return;
+       if (now - vs->last_update_time >= VNC_MAX_UPDATE_INTERVAL) {
+            if (!vs->update_requested) {
+                vs->ds->idle = 1;
+            } else {
+                /* Send a null update.  If the client is no longer
+                   interested (e.g. minimised) it'll ignore this, and we
+                   can stop scanning the buffer until it sends another
+                   update request. */
+                /* It turns out that there's a bug in realvncviewer 4.1.2
+                   which means that if you send a proper null update (with
+                   no update rectangles), it gets a bit out of sync and
+                   never sends any further requests, regardless of whether
+                   it needs one or not.  Fix this by sending a single 1x1
+                   update rectangle instead. */
+                vnc_write_u8(vs, 0);
+                vnc_write_u8(vs, 0);
+                vnc_write_u16(vs, 1);
+                send_framebuffer_update(vs, 0, 0, 1, 1);
+                vnc_flush(vs);
+                vs->last_update_time = now;
+                vs->update_requested--;
+                return;
+            }
        }
     }
     qemu_mod_timer(vs->timer, now + vs->timer_interval);
@@ -970,6 +974,7 @@ static int vnc_client_io_error(VncState 
        qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
        closesocket(vs->csock);
        vs->csock = -1;
+       vs->ds->idle = 1;
        buffer_reset(&vs->input);
        buffer_reset(&vs->output);
         free_queue(vs);
@@ -2443,6 +2448,7 @@ static void vnc_listen_read(void *opaque
     vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
     if (vs->csock != -1) {
        VNC_DEBUG("New client on socket %d\n", vs->csock);
+       vs->ds->idle = 0;
         socket_set_nonblock(vs->csock);
        qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
        vnc_write(vs, "RFB 003.008\n", 12);
@@ -2468,6 +2474,7 @@ void vnc_display_init(DisplayState *ds)
        exit(1);
 
     ds->opaque = vs;
+    ds->idle = 1;
     vnc_state = vs;
     vs->display = NULL;
     vs->password = NULL;
diff -r b0d7780794eb xen/include/public/io/fbif.h
--- a/xen/include/public/io/fbif.h      Thu May 08 13:40:40 2008 +0100
+++ b/xen/include/public/io/fbif.h      Thu May 08 15:47:13 2008 +0100
@@ -79,15 +79,27 @@ union xenfb_out_event
 /* In events (backend -> frontend) */
 
 /*
- * Frontends should ignore unknown in events.
- * No in events currently defined.
+ * Framebuffer refresh period advice
+ * Backend sends it to advise the frontend the period of refresh it should use,
+ * i.e how often it should take care to update the FB with its internal state.
+ *
+ * If the frontend uses the advice, it should refresh and send an update event
+ * in response to this event.
  */
+#define XENFB_TYPE_REFRESH_PERIOD 1
+
+struct xenfb_refresh_period
+{
+    uint8_t type;    /* XENFB_TYPE_UPDATE_PERIOD */
+    uint32_t period; /* period of refresh, in ms, 0 if no refresh is needed */
+};
 
 #define XENFB_IN_EVENT_SIZE 40
 
 union xenfb_in_event
 {
     uint8_t type;
+    struct xenfb_refresh_period refresh_period;
     char pad[XENFB_IN_EVENT_SIZE];
 };
 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel