Page MenuHomeFreeBSD

D56223.diff
No OneTemporary

D56223.diff

diff --git a/tests/sys/kqueue/kqueue_fork.c b/tests/sys/kqueue/kqueue_fork.c
--- a/tests/sys/kqueue/kqueue_fork.c
+++ b/tests/sys/kqueue/kqueue_fork.c
@@ -27,9 +27,13 @@
*/
#include <sys/event.h>
+#include <sys/procdesc.h>
+#include <sys/stat.h>
+#include <sys/user.h>
#include <sys/wait.h>
#include <err.h>
+#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
@@ -81,9 +85,145 @@
ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
}
+#define TIMER_FORKED 0
+#define TIMER_TIMEOUT 1
+
+#define RECV_TIMER 0x01
+#define RECV_VNODE 0x02
+#define RECV_CLOREAD 0x04
+#define RECV_ERROR 0x80
+#define RECV_ALL (RECV_TIMER | RECV_VNODE)
+
+static int
+cponfork_notes_check(int kq, int clofd)
+{
+ struct kevent ev;
+ int error, received = 0;
+
+ EV_SET(&ev, TIMER_TIMEOUT, EVFILT_TIMER,
+ EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_SECONDS, 4, NULL);
+ error = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (error == -1)
+ return (RECV_ERROR);
+
+ while ((received & RECV_ALL) != RECV_ALL) {
+ error = kevent(kq, NULL, 0, &ev, 1, NULL);
+ if (error < 0)
+ return (RECV_ERROR);
+ else if (error == 0)
+ break;
+
+ switch (ev.filter) {
+ case EVFILT_TIMER:
+ if (ev.ident == TIMER_TIMEOUT)
+ return (received | RECV_ERROR);
+
+ received |= RECV_TIMER;
+ break;
+ case EVFILT_VNODE:
+ received |= RECV_VNODE;
+ break;
+ case EVFILT_READ:
+ if ((int)ev.ident != clofd)
+ return (received | RECV_ERROR);
+ received |= RECV_CLOREAD;
+ break;
+ }
+ }
+
+ return (received);
+}
+
+ATF_TC_WITHOUT_HEAD(cponfork_notes);
+ATF_TC_BODY(cponfork_notes, tc)
+{
+ struct kevent ev[3];
+ int clofd, dfd, error, kq, pdfd, pmask, status;
+ pid_t pid;
+
+ kq = kqueuex(KQUEUE_CPONFORK);
+ ATF_REQUIRE(kq >= 0);
+
+ dfd = open(".", O_DIRECTORY);
+ ATF_REQUIRE(dfd >= 0);
+
+ clofd = kqueue();
+ ATF_REQUIRE(clofd >= 0);
+
+ /*
+ * Setup an event on clofd that we can trigger to make it readable,
+ * as we'll want this ready to go when we fork to be sure that if we
+ * *were* going to receive an event from it, it would have occurred
+ * before the three-second timer that would normally close out the child
+ * fires.
+ */
+ EV_SET(&ev[0], 0, EVFILT_USER, EV_ADD | EV_ENABLE, 0, 0, NULL);
+ error = kevent(clofd, &ev[0], 1, NULL, 0, NULL);
+ ATF_REQUIRE(error != -1);
+
+ /*
+ * Every event we setup here we should expect to observe in both the
+ * child and the parent, with exception to the EVFILT_READ of clofd. We
+ * except that one to be dropped in the child when the kqueue it's
+ * attached to goes away, thus its exclusion from the RECV_ALL mask.
+ */
+ EV_SET(&ev[0], dfd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_WRITE, 0, NULL);
+ EV_SET(&ev[1], TIMER_FORKED, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT,
+ NOTE_SECONDS, 3, NULL);
+ EV_SET(&ev[2], clofd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_ONESHOT, 0,
+ 0, NULL);
+ error = kevent(kq, &ev[0], 3, NULL, 0, NULL);
+ ATF_REQUIRE(error != -1);
+
+ /* Fire off an event to make clofd readable. */
+ EV_SET(&ev[0], 0, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+ error = kevent(clofd, &ev[0], 1, NULL, 0, NULL);
+
+ /*
+ * We're only using pdfork here for the kill-on-exit semantics, in case
+ * the parent fails to setup some context needed for one of our events
+ * to fire.
+ */
+ pid = pdfork(&pdfd, 0);
+ ATF_REQUIRE(pid != -1);
+ if (pid == 0) {
+ struct kinfo_file kf = { .kf_structsize = sizeof(kf) };
+
+ if (fcntl(kq, F_KINFO, &kf) != 0)
+ _exit(RECV_ERROR);
+ else if (kf.kf_type != KF_TYPE_KQUEUE)
+ _exit(RECV_ERROR);
+
+ _exit(cponfork_notes_check(kq, clofd));
+ }
+
+ /* Setup anything we need to fire off any of our events above. */
+ error = mkdir("canary", 0755);
+ ATF_REQUIRE(error == 0);
+
+ /*
+ * We'll simultaneously do the same exercise of polling the kqueue in
+ * the parent, to demonstrate that forking doesn't "steal" any of the
+ * knotes from us -- all of the events we've added are one-shot and
+ * still fire twice (once in parent, once in child).
+ */
+ pmask = cponfork_notes_check(kq, clofd);
+ ATF_REQUIRE_EQ(pmask, RECV_ALL | RECV_CLOREAD);
+
+ /* Wait for the child to timeout or observe the timer. */
+ _Static_assert(RECV_ALL <= UCHAR_MAX,
+ "Too many events to observe -- switch from waitpid -> waitid");
+ error = waitpid(pid, &status, 0);
+ ATF_REQUIRE(error != -1);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), RECV_ALL);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, shared_table_filt_sig);
+ ATF_TP_ADD_TC(tp, cponfork_notes);
return (atf_no_error());
}

File Metadata

Mime Type
text/plain
Expires
Fri, Jul 3, 3:27 PM (11 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31007805
Default Alt Text
D56223.diff (4 KB)

Event Timeline