tech-kern archive

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

kevent() not reporting closed slave pty (via master pty)



Hi,

I've been debugging a hanging test in LLDB.  The particular test is
meant to verify that LLDB handles EOF on pty correctly.  For this
purpose, it creates a pty and monitors it via kevent, then opens a slave
and closes it.  Apparently, it expects kevent to report that master pty
has no longer any slaves open.

I've tested this a bit and verified that read() from master pty returns
immediately if slave pty is closed.  However, it seems that closing
the slave pty prevents kevent from reporting anything, therefore making
it wait forever.

For comparison, on FreeBSD kevent() reports the fd with EOF flag:

  kevent(5,0x0,0,{ 3,EVFILT_READ,EV_EOF,0x0,0x0,0x0 },4,{ 2.000000000 }) = 1 (0x1)

The relevant passage from kqueue(2) seems to be:

                    Fifos, Pipes
                        Returns when there is data to read; data contains the
                        number of bytes available.

                        When the last writer disconnects, the filter will set
                        EV_EOF in flags.  This may be cleared by passing in
                        EV_CLEAR, at which point the filter will resume
                        waiting for data to become available before returning.

Though I'm not sure if I'm interpreting this correctly.  Is returning
with EV_EOF expected behavior here?

'Minimal' reproducer:

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <sys/event.h>
#include <sys/time.h>

int main() {
  int master_pty = posix_openpt(O_RDWR);
  int ret;
  assert(master_pty != -1);
  ret = grantpt(master_pty);
  assert(ret != -1);
  ret = unlockpt(master_pty);
  assert(ret != -1);

  const char* slave_name = ptsname(master_pty);
  assert(slave_name);
  int slave_pty = open(slave_name, O_RDWR | O_NOCTTY);
  assert(slave_pty != -1);

  int kq = kqueue();
  assert(kq != -1);

  struct kevent ev;
  struct kevent out_ev[4];
  const struct timespec timeout = {2,0};
  EV_SET(&ev, master_pty, EVFILT_READ, EV_ADD, 0, 0, 0);
  ret = kevent(kq, &ev, 1, out_ev, 4, &timeout);
  printf("kev = %d\n", ret);

  ret = close(slave_pty);
  assert(ret != -1);

  ret = kevent(kq, 0, 0, out_ev, 4, &timeout);
  // expected: 1
  printf("kev = %d\n", ret);

  return 0;
}

-- 
Best regards,
Michał Górny

Attachment: signature.asc
Description: This is a digitally signed message part



Home | Main Index | Thread Index | Old Index