#include #include #include #include #include #include #include #include #include #include int main(void) { // Check up front that stdout is a pipe. Otherwise we're going to // spew to the terminal or use up someone's disk. struct stat stat_buf; if ( fstat(1, &stat_buf) ) { err(EX_OSERR, "fstat"); } if ( (stat_buf.st_mode & S_IFMT) != S_IFIFO ) { errx(EX_USAGE, "stdout is not a pipe"); } // ignore SIGPIPE; set stdout nonblocking signal(SIGPIPE, SIG_IGN); int flags = fcntl(1, F_GETFL); if ( flags < 0 ) { err(EX_OSERR, "fcntl(F_GETFL)"); } if ( fcntl(1, F_SETFL, flags | O_NONBLOCK) ) { err(EX_OSERR, "fcntl(F_SETFL)"); } // Attempt to fill up the pipe that is stdout. char buf[4096]; memset(buf, 'a', sizeof(buf)); int got_eagain = 0; do { ssize_t nwritten = write(1, buf, sizeof(buf)); if ( nwritten < 0 ) { if ( errno == EAGAIN ) { got_eagain = 1; } else { err(EX_OSERR, "write"); } } } while ( !got_eagain ); // wait for something interesting to happen on stdout. int kq = kqueue(); if ( kq < 0 ) { errx(EX_OSERR, "kevent"); } struct kevent kev; EV_SET(&kev, 1, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL); struct kevent result = { 0 }; int wait_result = kevent(kq, &kev, 1, &result, 1, NULL); fprintf(stderr, "kevent returned %d\n", wait_result); if ( wait_result > 0 ) { fprintf(stderr, "\t%llu %d %d %d %lld %p\n", (unsigned long long)result.ident, (int)result.filter, (int)result.flags, (int)result.fflags, (long long)result.data, result.udata); } return 0; }