freebsd-nq/tools/regression/kqueue/proc.c
Jonathan Anderson 345f2b96e2 Clarify the meaning of a test.
Rather than using err() if either of two failure conditions
fires (which can produce spurious error messages), just use
errx() if the one condition that really matters fires.

In practice, this single test is enough to detect the failure
mode we're looking for (kqueue being inherited across fork).

Approved by: mentor (rwatson), re (Capsicum blanket)
Sponsored by: Google Inc
2011-07-08 12:16:30 +00:00

256 lines
5.9 KiB
C

/*
* Copyright (c) 2009 Mark Heily <mark@heily.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#include <sys/stat.h>
#include <err.h>
#include "config.h"
#include "common.h"
static int sigusr1_caught = 0;
int kqfd;
static void
sig_handler(int signum)
{
sigusr1_caught = 1;
}
static void
add_and_delete(void)
{
struct kevent kev;
pid_t pid;
/* Create a child that waits to be killed and then exits */
pid = fork();
if (pid == 0) {
struct stat s;
if (fstat(kqfd, &s) != -1)
errx(1, "kqueue inherited across fork! (%s() at %s:%d)",
__func__, __FILE__, __LINE__);
pause();
exit(2);
}
printf(" -- child created (pid %d)\n", (int) pid);
test_begin("kevent(EVFILT_PROC, EV_ADD)");
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
test_no_kevents();
success();
test_begin("kevent(EVFILT_PROC, EV_DELETE)");
sleep(1);
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL);
if (kill(pid, SIGKILL) < 0)
err(1, "kill");
sleep(1);
test_no_kevents();
success();
}
#ifdef TODO
static void
event_trigger(void)
{
struct kevent kev;
pid_t pid;
test_begin("kevent(EVFILT_PROC, wait)");
/* Create a child that waits to be killed and then exits */
pid = fork();
if (pid == 0) {
pause();
printf(" -- child caught signal, exiting\n");
exit(2);
}
printf(" -- child created (pid %d)\n", (int) pid);
test_no_kevents();
kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL);
/* Cause the child to exit, then retrieve the event */
printf(" -- killing process %d\n", (int) pid);
if (kill(pid, SIGUSR1) < 0)
err(1, "kill");
kevent_cmp(&kev, kevent_get(kqfd));
test_no_kevents();
success();
}
void
test_kevent_signal_disable(void)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
struct kevent kev;
test_begin(test_id);
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Block SIGUSR1, then send it to ourselves */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGKILL) < 0)
err(1, "kill");
test_no_kevents();
success();
}
void
test_kevent_signal_enable(void)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
struct kevent kev;
test_begin(test_id);
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Block SIGUSR1, then send it to ourselves */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGUSR1) < 0)
err(1, "kill");
kev.flags = EV_ADD | EV_CLEAR;
#if LIBKQUEUE
kev.data = 1; /* WORKAROUND */
#else
kev.data = 2; // one extra time from test_kevent_signal_disable()
#endif
kevent_cmp(&kev, kevent_get(kqfd));
/* Delete the watch */
kev.flags = EV_DELETE;
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
success();
}
void
test_kevent_signal_del(void)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
struct kevent kev;
test_begin(test_id);
/* Delete the kevent */
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Block SIGUSR1, then send it to ourselves */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGUSR1) < 0)
err(1, "kill");
test_no_kevents();
success();
}
void
test_kevent_signal_oneshot(void)
{
const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
struct kevent kev;
test_begin(test_id);
EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
/* Block SIGUSR1, then send it to ourselves */
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
err(1, "sigprocmask");
if (kill(getpid(), SIGUSR1) < 0)
err(1, "kill");
kev.flags |= EV_CLEAR;
kev.data = 1;
kevent_cmp(&kev, kevent_get(kqfd));
/* Send another one and make sure we get no events */
if (kill(getpid(), SIGUSR1) < 0)
err(1, "kill");
test_no_kevents();
success();
}
#endif
void
test_evfilt_proc()
{
kqfd = kqueue();
signal(SIGUSR1, sig_handler);
add_and_delete();
#if TODO
event_trigger();
#endif
signal(SIGUSR1, SIG_DFL);
#if TODO
test_kevent_signal_add();
test_kevent_signal_del();
test_kevent_signal_get();
test_kevent_signal_disable();
test_kevent_signal_enable();
test_kevent_signal_oneshot();
#endif
close(kqfd);
}