Date: Fri, 26 Jul 2013 11:52:32 -0700 From: John-Mark Gurney <jmg@funkthat.com> To: John Baldwin <jhb@freebsd.org> Cc: arch@freebsd.org Subject: Re: EVFILT_PROC always returns an EV_EOF event Message-ID: <20130726185232.GR26412@funkthat.com> In-Reply-To: <201307251537.04491.jhb@freebsd.org> References: <201307251537.04491.jhb@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
John Baldwin wrote this message on Thu, Jul 25, 2013 at 15:37 -0400: > A co-worker ran into this undocumented behavior today. If you register an > EVFILT_PROC event but do not set NOTE_EXIT, you can still get an event with > fflags set to 0 but EV_EOF set. This is not documented in the manpage, and > it seems inconsistent to me. If the caller hasn't set NOTE_EXIT, then > presumably they do not wish to know about NOTE_EXIT events. This is probably to let the consumer know that the process no longer exists and that there will be no more events delivered for this process.. This allows the process to clean up in this case.. If you look at the code in filt_proc in kern_event.c, you'll also see that is forces _ONESHOT to be set, meaning that the knote will be deleted... It is someone documented: EV_EOF Filters may set this flag to indicate filter-specific EOF condition. But I do agree that the documentation could be better... I don't have a strong opinion on which behavior is best. I do think that delivering the EOF is best, since on an fd, you get _EOF when the socket closes, even though you didn't ask for it.. it's implicit.. > I have a specific test case below (watch for NOTE_EXEC on a process that only > exits). Is this behavior desired or should this be fixed? If we want it > fixed I have a possible fix (tested with this test case) at > http://people.freebsd.org/~jhb/patches/kevent_proc_eof.patch Nice addition of drop... The patch looks good if we decide to go this route... > #include <sys/types.h> > #include <sys/event.h> > #include <assert.h> > #include <err.h> > #include <stdint.h> > #include <stdio.h> > #include <stdlib.h> > #include <unistd.h> > > static pid_t master; > static int kq; > > static void > watch(uintptr_t ident, short filter, u_short flags, u_int fflags, > intptr_t data, void *udata) > { > struct kevent ev; > > EV_SET(&ev, ident, filter, flags, fflags, data, udata); > if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0) > err(1, "kevent"); > } > > static void > dump_fflags(u_int fflags) > { > int pipe; > > assert(fflags != 0); > pipe = 0; > #define DUMP_FLAG(FLAG) do { \ > if (fflags & FLAG) { \ > printf("%s" #FLAG, pipe ? " | " : ""); \ > pipe = 1; \ > } \ > } while (0) > > DUMP_FLAG(NOTE_EXIT); > DUMP_FLAG(NOTE_FORK); > DUMP_FLAG(NOTE_EXEC); > DUMP_FLAG(NOTE_TRACK); > DUMP_FLAG(NOTE_TRACKERR); > DUMP_FLAG(NOTE_CHILD); > > fflags &= ~(NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK | > NOTE_TRACKERR | NOTE_CHILD); > if (fflags != 0) > printf("%s%u", pipe ? " | " : "", fflags); > } > > static void > dump_event(struct kevent *ev) > { > > assert(ev->filter == EVFILT_PROC); > printf("pid: %5d%s flags: ", (int)ev->ident, > ev->flags & EV_EOF ? " EV_EOF" : ""); > dump_fflags(ev->fflags); > if (ev->data != 0) > printf(" data: %jd", (uintmax_t)ev->data); > printf("\n"); > } > > static void > child(int fd) > { > pid_t pid; > char c; > > if (fd > 0) > (void)read(fd, &c, sizeof(c)); > pid = fork(); > if (pid == -1) > err(1, "fork"); > usleep(5000); > exit(1); > } > > static void > waitfor(int count, const char *msg) > { > struct timespec ts; > struct kevent ev; > int rv; > > printf("%s:\n", msg); > > /* Wait up to 250 ms before timing out. */ > ts.tv_sec = 0; > ts.tv_nsec = 250 * 1000 * 1000; > for (;;) { > rv = kevent(kq, NULL, 0, &ev, 1, &ts); > if (rv < 0) > err(1, "kevent"); > if (rv == 0) > break; > dump_event(&ev); > --count; > } > > if (count > 0) > warnx("%d events missing for %s", count, msg); > else if (count < 0) > warnx("%d extra events for %s", -count, msg); > } > > int > main(int ac, char **av) > { > pid_t pid; > int fds[2]; > char c; > > kq = kqueue(); > if (kq < 0) > err(1, "kqueue"); > if (pipe(fds) < 0) > err(1, "pipe"); > master = getpid(); > printf("master: %d\n", (int)master); > > /* Test for a dummy EV_EOF event. */ > pid = fork(); > if (pid == -1) > err(1, "fork"); > if (pid == 0) > child(fds[1]); > watch(pid, EVFILT_PROC, EV_ADD, NOTE_EXEC, 0, 0); > write(fds[0], &c, sizeof(c)); > > /* Should not get any events at all. */ > waitfor(0, "dummy EV_EOF"); > > return (0); > } > > -- > John Baldwin > _______________________________________________ > freebsd-arch@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-arch > To unsubscribe, send any mail to "freebsd-arch-unsubscribe@freebsd.org" -- John-Mark Gurney Voice: +1 415 225 5579 "All that I will do, has been done, All that I have, has not."
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20130726185232.GR26412>