Commit 279e694bc7bae106dc1178e7fbb60dfb832396e7

Authored by aliguori
1 parent 4a40e231

Attempt to detect unconnected ptys (Gerd Hoffman)

This patch moves the pty char device imlementation away from the generic
filehandle code.  It tries to detect as good as possible whenever there
is someone connected to the slave pty device and only send data down the
road in case someone is listening.  Unfortunaly we have to poll via
timer once in a while to check the status because we have to use read()
on the master pty to figure the status (returns -EIO when unconnected).

Poll intervall for an idle guest is one second, when the guest sends
data to the virtual device linked to the pty we check more frequently.

The point for all of this is to avoid qemu blocking and not responding
any more.  Writing to the master pty handle succeeds even when nobody is
connected to (and reading from) to the slave end of the pty.  The kernel
just bufferes the writes.  And as soon as the kernel buffer is full the
write() call blocks forever ...

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4956 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 145 additions and 4 deletions
... ... @@ -2464,21 +2464,162 @@ void cfmakeraw (struct termios *termios_p)
2464 2464 #endif
2465 2465  
2466 2466 #if defined(__linux__) || defined(__sun__)
  2467 +
  2468 +typedef struct {
  2469 + int fd;
  2470 + int connected;
  2471 + int polling;
  2472 + int read_bytes;
  2473 + QEMUTimer *timer;
  2474 +} PtyCharDriver;
  2475 +
  2476 +static void pty_chr_update_read_handler(CharDriverState *chr);
  2477 +static void pty_chr_state(CharDriverState *chr, int connected);
  2478 +
  2479 +static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
  2480 +{
  2481 + PtyCharDriver *s = chr->opaque;
  2482 +
  2483 + if (!s->connected) {
  2484 + /* guest sends data, check for (re-)connect */
  2485 + pty_chr_update_read_handler(chr);
  2486 + return 0;
  2487 + }
  2488 + return unix_write(s->fd, buf, len);
  2489 +}
  2490 +
  2491 +static int pty_chr_read_poll(void *opaque)
  2492 +{
  2493 + CharDriverState *chr = opaque;
  2494 + PtyCharDriver *s = chr->opaque;
  2495 +
  2496 + s->read_bytes = qemu_chr_can_read(chr);
  2497 + return s->read_bytes;
  2498 +}
  2499 +
  2500 +static void pty_chr_read(void *opaque)
  2501 +{
  2502 + CharDriverState *chr = opaque;
  2503 + PtyCharDriver *s = chr->opaque;
  2504 + int size, len;
  2505 + uint8_t buf[1024];
  2506 +
  2507 + len = sizeof(buf);
  2508 + if (len > s->read_bytes)
  2509 + len = s->read_bytes;
  2510 + if (len == 0)
  2511 + return;
  2512 + size = read(s->fd, buf, len);
  2513 + if ((size == -1 && errno == EIO) ||
  2514 + (size == 0)) {
  2515 + pty_chr_state(chr, 0);
  2516 + return;
  2517 + }
  2518 + if (size > 0) {
  2519 + pty_chr_state(chr, 1);
  2520 + qemu_chr_read(chr, buf, size);
  2521 + }
  2522 +}
  2523 +
  2524 +static void pty_chr_update_read_handler(CharDriverState *chr)
  2525 +{
  2526 + PtyCharDriver *s = chr->opaque;
  2527 +
  2528 + qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
  2529 + pty_chr_read, NULL, chr);
  2530 + s->polling = 1;
  2531 + /*
  2532 + * Short timeout here: just need wait long enougth that qemu makes
  2533 + * it through the poll loop once. When reconnected we want a
  2534 + * short timeout so we notice it almost instantly. Otherwise
  2535 + * read() gives us -EIO instantly, making pty_chr_state() reset the
  2536 + * timeout to the normal (much longer) poll interval before the
  2537 + * timer triggers.
  2538 + */
  2539 + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 10);
  2540 +}
  2541 +
  2542 +static void pty_chr_state(CharDriverState *chr, int connected)
  2543 +{
  2544 + PtyCharDriver *s = chr->opaque;
  2545 +
  2546 + if (!connected) {
  2547 + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  2548 + s->connected = 0;
  2549 + s->polling = 0;
  2550 + /* (re-)connect poll interval for idle guests: once per second.
  2551 + * We check more frequently in case the guests sends data to
  2552 + * the virtual device linked to our pty. */
  2553 + qemu_mod_timer(s->timer, qemu_get_clock(rt_clock) + 1000);
  2554 + } else {
  2555 + if (!s->connected)
  2556 + qemu_chr_reset(chr);
  2557 + s->connected = 1;
  2558 + }
  2559 +}
  2560 +
  2561 +void pty_chr_timer(void *opaque)
  2562 +{
  2563 + struct CharDriverState *chr = opaque;
  2564 + PtyCharDriver *s = chr->opaque;
  2565 +
  2566 + if (s->connected)
  2567 + return;
  2568 + if (s->polling) {
  2569 + /* If we arrive here without polling being cleared due
  2570 + * read returning -EIO, then we are (re-)connected */
  2571 + pty_chr_state(chr, 1);
  2572 + return;
  2573 + }
  2574 +
  2575 + /* Next poll ... */
  2576 + pty_chr_update_read_handler(chr);
  2577 +}
  2578 +
  2579 +static void pty_chr_close(struct CharDriverState *chr)
  2580 +{
  2581 + PtyCharDriver *s = chr->opaque;
  2582 +
  2583 + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
  2584 + close(s->fd);
  2585 + qemu_free(s);
  2586 +}
  2587 +
2467 2588 static CharDriverState *qemu_chr_open_pty(void)
2468 2589 {
  2590 + CharDriverState *chr;
  2591 + PtyCharDriver *s;
2469 2592 struct termios tty;
2470   - int master_fd, slave_fd;
  2593 + int slave_fd;
2471 2594  
2472   - if (openpty(&master_fd, &slave_fd, NULL, NULL, NULL) < 0) {
  2595 + chr = qemu_mallocz(sizeof(CharDriverState));
  2596 + if (!chr)
  2597 + return NULL;
  2598 + s = qemu_mallocz(sizeof(PtyCharDriver));
  2599 + if (!s) {
  2600 + qemu_free(chr);
  2601 + return NULL;
  2602 + }
  2603 +
  2604 + if (openpty(&s->fd, &slave_fd, NULL, NULL, NULL) < 0) {
2473 2605 return NULL;
2474 2606 }
2475 2607  
2476 2608 /* Set raw attributes on the pty. */
2477 2609 cfmakeraw(&tty);
2478 2610 tcsetattr(slave_fd, TCSAFLUSH, &tty);
  2611 + close(slave_fd);
  2612 +
  2613 + fprintf(stderr, "char device redirected to %s\n", ptsname(s->fd));
2479 2614  
2480   - fprintf(stderr, "char device redirected to %s\n", ptsname(master_fd));
2481   - return qemu_chr_open_fd(master_fd, master_fd);
  2615 + chr->opaque = s;
  2616 + chr->chr_write = pty_chr_write;
  2617 + chr->chr_update_read_handler = pty_chr_update_read_handler;
  2618 + chr->chr_close = pty_chr_close;
  2619 +
  2620 + s->timer = qemu_new_timer(rt_clock, pty_chr_timer, chr);
  2621 +
  2622 + return chr;
2482 2623 }
2483 2624  
2484 2625 static void tty_serial_init(int fd, int speed,
... ...