[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] Paravirt framebuffer backend tools [2/5]
On Mon, 2006-09-04 at 10:01 +0100, Steven Smith wrote: > > +CFLAGS += -g -Wall > You shouldn't need to add -g here; Rules.mk handles it for you if > debug is set. *nod* -Wall gets set in Config.mk as well -- will nuke. > > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > > +++ b/tools/xenfb/keymapping.c Sat Sep 02 15:19:25 2006 -0400 > > @@ -0,0 +1,141 @@ > > +#include <stdint.h> > > +#include <gdk/gdkkeysyms.h> > > +#include <linux/input.h> > > + > > +uint32_t gdk_linux_mapping[0x10000] = { > > + [GDK_a] = KEY_A, > This is kind of ugly. Is there any chance it could be autogenerated? > Also, where did 0x10000 come from? > > Also, depending on GTK just for the keymap table is a real pain. Or > is it already required for libvncserver? libvncserver requires GTK. And I don't know that there's really any good way to auto-generate it unfortunately. I somehow expect that 0x10000 came from "it'll be big enough" but Anthony would have to confirm :-) The mappings are unfortunately a bit of a fact of life since we have to convert from what the X layer gets to what the kernel expects. And the two couldn't be farther from the same. And then it's even more fun when toolkits get involved. > > --- /dev/null Thu Jan 01 00:00:00 1970 +0000 > > +++ b/tools/xenfb/sdlfb.c Sat Sep 02 15:19:25 2006 -0400 > > @@ -0,0 +1,191 @@ > > +#include <SDL.h> > > +#include <sys/types.h> > > +#include <sys/select.h> > > +#include <stdlib.h> > > +#include <linux/input.h> > > +#include <getopt.h> > > +#include <string.h> > > +#include "xenfb.h" > > + > > +struct data > That's a really wonderful name. Sold one SDLFBData :-) > > +int sdl2linux[1024] = { > > + [SDLK_a] = KEY_A, > Another really ugly mapping table, although not quite as bad as the > GTK one. [snip] > Where'd the magic 1024 come from? Same basic idea > > + > > + while ((opt = getopt_long(argc, argv, "d:t:", options, > > + NULL)) != -1) { > > + switch (opt) { > > + case 'd': > > + domid = strtol(optarg, NULL, 10); > It'd be nice to check for a malformed argument here. Can change the check to be for domid <= 0 below which will catch the case of no domid being passed or strtol failing (it'll return 0) > > + break; > > + case 't': > > + title = strdup(optarg); > This can fail. In which case title will still be NULL and we fall back to the default which is sane. > > + break; > > + } > > + } > > + if (optind != argc) { > > + fprintf(stderr, "Invalid options!\n"); > > + exit(1); > errx() maybe? I tend to prefer being explicit. > > + } > > + if (domid == -1) { > > + fprintf(stderr, "Domain ID must be specified!\n"); > > + exit(1); > > + } > > + > > + xenfb = xenfb_new(); > > + if (xenfb == NULL) > > + return 1; > Why have you used exit(1) in some places and return 1 in others? I'm guessing that some are Anthony's checks and some are later added by Markus and/or myself. > Also, an error message here would be a good idea. Agreed on the error messages, will add > > + if (title == NULL) > > + title = strdup("xen-sdlfb"); > This can fail. At which point you just end up without a window title. [snip] > > + while (!do_quit && select(fd + 1, &readfds, NULL, NULL, &tv) != -1) { > Select can say -1 because of EINTR (e.g. when strace attaches). It's > not clear to me whether you want to exit or retry in that case. > > Also, if you quit because select returns -1, you need an error > message. Reasonable enough and easy to add [snip] > > + tv = (struct timeval){0, 500}; > I think 500us is a little short here. About ten milliseconds sounds > more plausible. This is a bit of a bikeshed. > > It's a pity SDL doesn't allow you to wait for either an SDL event or > an fd to become readable. Could you do something like spawn a thread > which does the selects in a loop, and then SDL_PushEvent()s a user > event when the fd becomes readable? > > Admittedly, SDL_WaitEvent also contains this kind of loop-with-sleep, > but it'd reduce the number of magic tunables a bit. I don't see why we wouldn't just want to use SDL_WaitEvent unless I'm just not awake enough... > > --- b/tools/xenfb/vncfb.c Sat Sep 02 15:19:25 2006 -0400 > > +++ b/tools/xenfb/vncfb.c Sat Sep 02 15:22:19 2006 -0400 > > Minor nit: generally, putting a vnc_ prefix on these functions > confused me, since it looks like they should be in libvncserver. This > may just be because I'm not paying enough attention. Maybe use xenvnc for the things here just to make it more clear? Although I think the vncserver stuff is actually prefixed with rfb just to make things extra exciting :) > > +static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl) > > +{ > > + extern uint32_t gdk_linux_mapping[0x10000]; > Is there any chance of moving this into a header file somewhere? I don't see any reason why keymapping.c couldn't be keymapping.h and just #include'd [snip] > > + for (i = 0; i < 8; i++) { > > + if ((last_button & (1 << i)) != > > + (buttonMask & (1 << i))) { > > + printf("%d %d\n", buttonMask & (1 << i), i); > Umm? Debug creeping in > > + > > + buf = malloc(256); > Could fail. Also, consider using asprintf. Yeah, asprintf makes lots of sense, changed > > + if (snprintf(buf, 256, "%s/console/vnc-port", path) == -1) > > + goto out; > > + > > + portstr = malloc(10); > Why is this on the heap rather than the stack? I've been bitten too many times with variables on the stack and calling conventions on bizarre arches > > +static int vnc_start_viewer(int port) > I'm not convinced the backend server process is the best place to > start the viewer from. Perhaps xend would be a better choice? Not > sure about this. I did it here to keep similarity with how FV works -- the viewer is spawned there by qemu. So while I also could go either way, I think the important thing is having it be the same for FV and PV. [snip] > This is ignored. Also, the parent process makes no attempt to check > whether the child was exec()ed successfully or anything along those > lines. This is enough of a pain to fix that I'd probably just ignore > it, though. Yeah -- and even if the parent noticed, it's not going to actually do much useful. This is pretty much purely from qemu > > + struct xenfb *xenfb; > > + fd_set readfds; > > + int fd; > > + char buffer[1024]; > Could do with a better name, and is larger than it needs to be. Will rename to portstr and make it smaller > > + int opt; > > + bool unused = FALSE; > You're inconsistent about the capitalisation of bools. Consistent on a per-file basis -- have a preference? > > + bool viewer = FALSE; > > + > > + while ((opt = getopt_long(argc, argv, "d:p:t:u", options, > > + NULL)) != -1) { > > + switch (opt) { > > + case 'd': > > + domid = strtol(optarg, NULL, 10); > It would be nice to sanity check the argument here. Will do sanity checking on the argument handling the same as with sdlfb > > + if (listen != NULL) > > + fake_argv[6] = listen; > > + > > + if (listen != NULL) > > + fake_argv[6] = listen; > Umm... What's going on here? Merge error between a few trees [snip] > > + > > +struct xenfb_private > > +{ > > + struct xenfb pub; > > + int domid; > > + unsigned long fbdev_mfn, kbd_mfn; > > + int fbdev_evtchn, kbd_evtchn; > > + evtchn_port_t fbdev_port, kbd_port; > How do {fbdev,kbd}_port differ from {fbdev,kbd}_evtchn? _evtchn the actual remote port ({vfb,vkbd}/event-channel) and _port is the event port > The _evtchn fields are only ever accessed from xenfb_attach_dom. Could > they be locals to that function? They could be -- not sure what it actually buys [snip] > > + struct xenfb_private *xenfb = malloc(sizeof(*xenfb)); > > + > > + if (xenfb == NULL) > > + return NULL; > > + > > + memset(xenfb, 0, sizeof(*xenfb)); > Use calloc instead of malloc, perhaps? I have some vague recollection of calloc() bad, but my neurons aren't firing to tell me why I remember that > > + if (xenfb->xc == -1) { > > + int serrno = errno; > > + xc_evtchn_close(xenfb->evt_xch); > > + free(xenfb); > > + errno = serrno; > > + return NULL; > It's a pity we don't have a macro which hides this ugliness. Perhaps > > #define PRESERVING_ERRNO(x) do { > int tmp = errno; > x; > errno = tmp; > } while (0) > > You could then do something like > > if (xenfb_evt_sch == -1) { > PRESERVING_ERRNO(xc_evtchn_close(xenfb->evt_xch);free(xenfb)); > return NULL; > } > > Not sure whether that's more or less ugly, to be honest. I think it makes it a little bit less clear what's going on. But that's just me > > +static char *xenfb_path_in_dom(struct xs_handle *h, > > + unsigned domid, const char *path, > > + char *buffer, size_t size) > > +{ > > + char *domp = xs_get_domain_path(h, domid); > Can fail. Catching that case > > +static int xenfb_xs_scanf1(struct xs_handle *xsh, unsigned domid, > > + const char *path, const char *fmt, > > + void *dest) > > +{ > > + char buffer[1024]; > > + char *p; > > + int ret; > > + > > + p = xenfb_path_in_dom(xsh, domid, path, buffer, sizeof(buffer)); > What happens if this fails? I think we should probably do the wait and loop -- changed so that it actually happens > > + p = xs_read(xsh, XBT_NULL, p, NULL); > > + if (!p) > > + return -ENOENT; > > + ret = sscanf(p, fmt, dest); > > + free(p); > > + if (ret != 1) > > + return -EDOM; > > + return 0; > > +} > You're somewhat inconsistent about returning error numbers as negative > return values or through errno. I'd prefer the latter in userspace > code, but it doesn't matter too much, privided you pick one. Switched to the latter -- I think it's actually on here where it's inconsistent. > > + for (;;) { > > + ret = xenfb_xs_scanf1(xsh, domid, "vfb/page-ref", "%lu", > > + &xenfb->fbdev_mfn); > > + if (ret == -ENOENT || ret == -EAGAIN) > xenfb_xs_scanf can't return -EAGAIN. What are you trying to achieve > here? I can't really see anything either -- simplified > > + wait: > > + printf("Waiting...\n"); > Where does this message go? With it being spawned from xend, it'll go to xend-debug.log > > + xenfb->fb = xc_map_foreign_batch(xenfb->xc, domid, PROT_READ | > > PROT_WRITE, xenfb->fbmfns, xenfb->n_fbmfns); > > + if (xenfb->fb == NULL) > > + goto error_fbmfns; > > + > > + event.type = XENFB_TYPE_SET_EVENTS; > > + event.set_events.flags = XENFB_FLAG_UPDATE; > > + if (xenfb_fb_event(xenfb, &event)) > > + goto error_fb; > > + > > + munmap(xenfb->fbmfns, xenfb->n_fbdirs * XC_PAGE_SIZE); > Please make fbmfns a local rather than putting it in the info > structure. Done > > + > > + xenfb->domid = domid; > > + > > + xenfb->pub.pixels = xenfb->fb; > > + > > + xenfb->pub.row_stride = xenfb->fb_info->line_length; > > + xenfb->pub.depth = xenfb->fb_info->depth; > > + xenfb->pub.width = xenfb->fb_info->width; > > + xenfb->pub.height = xenfb->fb_info->height; > > + > > + return true; > > + > > + error_fb: > The error path here is utterly revolting. Perhaps something like this: Heh, indeed :-) I don't see why that can't work > > + xs_daemon_close(xsh); > I think you may end up closing the connection to the daemon twice here. I don't see how we could close it twice -- and if we do > > +static void xenfb_update(struct xenfb_private *xenfb, int x, int y, int > > width, int height) > > +{ > > + if (xenfb->pub.update) > > + xenfb->pub.update(&xenfb->pub, x, y, width, height); > > +} > I'm not convinced this wrapper is actually needed, given that it's > utterly trivial and only called from one place. Sure! > > +static void xenfb_on_kbd_event(struct xenfb_private *xenfb) [snip] > I'd replace this with Doesn't this go back to "we need to consume events out of the ring to remain compatible if there are later events that could be understood"? > > + > > +int xenfb_on_incoming(struct xenfb *xenfb_pub) > > +{ > > + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; > > + evtchn_port_t port; > > + > > + port = xc_evtchn_pending(xenfb->evt_xch); > > + if (port == -1) > > + return -1; > > + > > + if (port == xenfb->fbdev_port) { > > + xenfb_on_fb_event(xenfb); > > + } else if (port == xenfb->kbd_port) { > > + xenfb_on_kbd_event(xenfb); > > + } > > + > > + if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) > > + return -1; > > + > > + return 0; > > +} > > + > > +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode) > > +{ > > + struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; > > + union xenkbd_in_event event; > > + > > + event.type = XENKBD_TYPE_KEY; > > + event.key.pressed = down ? 1 : 0; > > + event.key.keycode = keycode; > > + > > + return xenfb_kbd_event(xenfb, &event); > > +} > > + > > +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y) > Is this sending XENKBD_TYPE_MOTION or XENFB_TYPE_MOTION? It's a "keyboard" event, so XENKBD_TYPE_MOTION Jeremy _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |