#18486 closed bug (fixed)

poll() on closed pty never unblocks

Reported by: pulkomandy Owned by: nobody
Priority: normal Milestone: R1/beta5
Component: System/POSIX Version: R1/beta4
Keywords: Cc:
Blocked By: Blocking:
Platform: All

Description

Consider the following test case:

#define _XOPEN_SOURCE 600
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#define __USE_BSD
#include <termios.h>

#define _GNU_SOURCE
#include <poll.h>


int main(void)
{
int fdm, fds, rc;
char input[150];

  fdm = posix_openpt(O_RDWR|O_NOCTTY);
  if (fdm < 0)
  {
    fprintf(stderr, "Error %d on posix_openpt()\n", errno);
    return 1;
  }

  rc = grantpt(fdm);
  if (rc != 0)
  {
    fprintf(stderr, "Error %d on grantpt()\n", errno);
    return 1;
  }

  rc = unlockpt(fdm);
  if (rc != 0)
  {
    fprintf(stderr, "Error %d on unlockpt()\n", errno);
    return 1;
  }

  // Open the slave PTY
  fds = open(ptsname(fdm), O_RDWR|O_NOCTTY);
  if (fds < 0)
  {
          fprintf(stderr, "Error %s on opening slave\n", strerror(errno));
  }

  // Creation of a child process
  if (fork())
  {
    // Father
 
    // Close the slave side of the PTY
    close(fds);
    while (1)
    {
                struct pollfd fds;
                fds.fd = fdm;
                fds.events = POLLIN;

                do {
                        rc = poll(&fds, 1, -1);
                        if (rc == -1 && errno == EINTR)
                                puts("Interrupted, try again");
                } while (rc < 0 && errno == EINTR);
                printf("poll complete, %d events, %s\n", rc, strerror(errno));

        // Get the child's answer through the PTY
        rc = read(fdm, input, sizeof(input) - 1);
                printf("read return %d\n", rc);
        if (rc > 0)
        {
          // Make the answer NUL terminated to display it as a string
          input[rc] = '\0';

          fprintf(stderr, "read from child: %s\n", input);
        }
        else
        {
          break;
        }
    } // End while
  }
  else
  {
    struct termios slave_orig_term_settings; // Saved terminal settings
    struct termios new_term_settings; // Current terminal settings

    // Child

    // Close the master side of the PTY
    close(fdm);

    // Save the default parameters of the slave side of the PTY
    rc = tcgetattr(fds, &slave_orig_term_settings);

    // Set raw mode on the slave side of the PTY
    new_term_settings = slave_orig_term_settings;
    cfmakeraw (&new_term_settings);
    tcsetattr (fds, TCSANOW, &new_term_settings);

    write(fds, "hello", 6);
  }

  return 0;
} // main

This opens a pty and runs a child process to write to it. The child writes something and then exits, leading to a SIGCHLD and (I expect) a closed PTY. On Linux, this works fine, the poll is woken up first to read the "hello" and then to read the end of file, and then it exits.

On Haiku, poll is woken up once to read the "hello", then a second time because of SIGCHLD, then polling again never returns. However, if I remove the retry on EINTR, the read() call does correctly return an end of file.

Possibly related to #7859 which is a similar problem with FIFOs?

Change History (1)

comment:1 by pulkomandy, 10 months ago

Milestone: UnscheduledR1/beta5
Resolution: fixed
Status: newclosed

Fixed in hrev57129.

Note: See TracTickets for help on using tickets.