qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/3] Always use nonblocking mode for qemu_chr_op


From: Gerd Hoffmann
Subject: Re: [Qemu-devel] [PATCH 2/3] Always use nonblocking mode for qemu_chr_open_fd.
Date: Wed, 23 Jul 2008 16:24:23 +0200
User-agent: Thunderbird 2.0.0.14 (X11/20080501)

  Hi,

> Which means we need our own code for ptys and can't use the generic fd
> functions.  I'll go trying cooking up a patch ...

Comments on this one?

cheers,
  Gerd

-- 
http://kraxel.fedorapeople.org/xenner/
diff --git a/vl.c b/vl.c
index 1af6d10..23d92e5 100644
--- a/vl.c
+++ b/vl.c
@@ -2454,21 +2454,153 @@ void cfmakeraw (struct termios *termios_p)
 #endif
 
 #if defined(__linux__) || defined(__sun__)
+
+typedef struct {
+    int fd;
+    int connected;
+    int polling;
+    int read_bytes;
+    int interval;
+    QEMUTimer *timer;
+} PtyCharDriver;
+
+static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    PtyCharDriver *s = chr->opaque;
+    if (!s->connected)
+       return 0;
+    return unix_write(s->fd, buf, len);
+}
+
+static void pty_chr_state(CharDriverState *chr, int connected)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    if (s->connected == connected)
+       return;
+    if (connected) {
+       fprintf(stderr,"%s: %s connected\n", __FUNCTION__, ptsname(s->fd));
+       s->connected = 1;
+       qemu_chr_reset(chr);
+    } else {
+       fprintf(stderr,"%s: %s disconnected\n", __FUNCTION__, ptsname(s->fd));
+       s->connected = 0;
+       qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + s->interval);
+    }
+}
+
+static int pty_chr_read_poll(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+
+    s->read_bytes = qemu_chr_can_read(chr);
+    return s->read_bytes;
+}
+
+static void pty_chr_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    PtyCharDriver *s = chr->opaque;
+    int size, len;
+    uint8_t buf[1024];
+
+    len = sizeof(buf);
+    if (len > s->read_bytes)
+        len = s->read_bytes;
+    if (len == 0)
+        return;
+    size = read(s->fd, buf, len);
+    if ((size == -1 && EIO == errno) ||
+       (size == 0)) {
+       qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+       s->polling = 0;
+       pty_chr_state(chr, 0);
+        return;
+    }
+    if (size > 0) {
+       pty_chr_state(chr, 1);
+        qemu_chr_read(chr, buf, size);
+    }
+}
+
+static void pty_chr_update_read_handler(CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
+                        pty_chr_read, NULL, chr);
+    s->polling = 1;
+    qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + s->interval);
+}
+
+void pty_chr_timer(void *opaque)
+{
+    struct CharDriverState *chr = opaque;    
+    PtyCharDriver *s = chr->opaque;
+
+    if (s->connected) {
+       /* All fine, nothing to do. */
+       return;
+    }
+    if (s->polling) {
+       /* Ran for a while without getting EIO for reads,
+        * probably someone connected to the slave pty. */
+       pty_chr_state(chr, 1);
+       return;
+    }
+    /* Try reading again ... */
+#if 0
+    fprintf(stderr,"%s: %s checking ...\n", __FUNCTION__, ptsname(s->fd));
+#endif
+    pty_chr_update_read_handler(chr);
+}
+
+static void pty_chr_close(struct CharDriverState *chr)
+{
+    PtyCharDriver *s = chr->opaque;
+
+    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
+    close(s->fd);
+    qemu_free(s);
+}
+
 static CharDriverState *qemu_chr_open_pty(void)
 {
+    CharDriverState *chr;
+    PtyCharDriver *s;
     struct termios tty;
-    int master_fd, slave_fd;
+    int slave_fd;
+    
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    s = qemu_mallocz(sizeof(PtyCharDriver));
+    if (!s) {
+        free(chr);
+        return NULL;
+    }
 
-    if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) < 0) {
+    if (openpty(&s->fd, &slave_fd, NULL, NULL, NULL) < 0) {
         return NULL;
     }
 
     /* Set raw attributes on the pty. */
     cfmakeraw(&tty);
     tcsetattr(slave_fd, TCSAFLUSH, &tty);
+    close(slave_fd);
+    
+    fprintf(stderr, "char device redirected to %s\n", ptsname(s->fd));
+    
+    chr->opaque = s;
+    chr->chr_write = pty_chr_write;
+    chr->chr_update_read_handler = pty_chr_update_read_handler;
+    chr->chr_close = pty_chr_close;
 
-    fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd));
-    return qemu_chr_open_fd(master_fd, master_fd);
+    s->interval = 100; /* miliseconds */
+    s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
+    
+    return chr;
 }
 
 static void tty_serial_init(int fd, int speed,

reply via email to

[Prev in Thread] Current Thread [Next in Thread]