Path: blob/main/tests/sys/kqueue/libkqueue/main.c
101672 views
/*1* Copyright (c) 2009 Mark Heily <[email protected]>2*3* Permission to use, copy, modify, and distribute this software for any4* purpose with or without fee is hereby granted, provided that the above5* copyright notice and this permission notice appear in all copies.6*7* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES8* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF9* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR10* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES11* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN12* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF13* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.14*/1516#include <sys/types.h>1718#include "config.h"19#include "common.h"2021int kqfd;22static char *cur_test_id = NULL;23static int testnum = 1;2425/* Checks if any events are pending, which is an error. */26void27_test_no_kevents(const char *file, int line)28{29int nfds;30struct timespec timeo;31struct kevent kev;32char *kev_str;3334puts("confirming that there are no events pending");35memset(&timeo, 0, sizeof(timeo));36nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);37if (nfds != 0) {38printf("\n[%s:%d]: Unexpected event:", file, line);39kev_str = kevent_to_str(&kev);40puts(kev_str);41free(kev_str);42errx(1, "%d event(s) pending, but none expected:", nfds);43}44}4546/* Checks if any events are pending, which is an error. Do not print47* out anything unless events are found.48*/49void50test_no_kevents_quietly(void)51{52int nfds;53struct timespec timeo;54struct kevent kev;55char *kev_str;5657memset(&timeo, 0, sizeof(timeo));58nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);59if (nfds != 0) {60puts("\nUnexpected event:");61kev_str = kevent_to_str(&kev);62puts(kev_str);63free(kev_str);64errx(1, "%d event(s) pending, but none expected:", nfds);65}66}6768/* Retrieve a single kevent */69struct kevent *70kevent_get(int fd)71{72int nfds;73struct kevent *kev;7475if ((kev = calloc(1, sizeof(*kev))) == NULL)76err(1, "out of memory");7778nfds = kevent(fd, NULL, 0, kev, 1, NULL);79if (nfds < 1)80err(1, "kevent(2)");8182return (kev);83}8485/* Retrieve a single kevent, specifying a maximum time to wait for it. */86struct kevent *87kevent_get_timeout(int fd, int seconds)88{89int nfds;90struct kevent *kev;91struct timespec timeout = {seconds, 0};9293if ((kev = calloc(1, sizeof(*kev))) == NULL)94err(1, "out of memory");9596nfds = kevent(fd, NULL, 0, kev, 1, &timeout);97if (nfds < 0) {98err(1, "kevent(2)");99} else if (nfds == 0) {100free(kev);101kev = NULL;102}103104return (kev);105}106107static char *108kevent_fflags_dump(struct kevent *kev)109{110char *buf;111112#define KEVFFL_DUMP(attrib) \113if (kev->fflags & attrib) \114strncat(buf, #attrib" ", 64);115116if ((buf = calloc(1, 1024)) == NULL)117abort();118119/* Not every filter has meaningful fflags */120if (kev->filter == EVFILT_PROC) {121snprintf(buf, 1024, "fflags = %x (", kev->fflags);122KEVFFL_DUMP(NOTE_EXIT);123KEVFFL_DUMP(NOTE_FORK);124KEVFFL_DUMP(NOTE_EXEC);125KEVFFL_DUMP(NOTE_CHILD);126KEVFFL_DUMP(NOTE_TRACKERR);127KEVFFL_DUMP(NOTE_TRACK);128buf[strlen(buf) - 1] = ')';129} else if (kev->filter == EVFILT_PROCDESC) {130snprintf(buf, 1024, "fflags = %x (", kev->fflags);131KEVFFL_DUMP(NOTE_EXIT);132KEVFFL_DUMP(NOTE_FORK);133KEVFFL_DUMP(NOTE_EXEC);134buf[strlen(buf) - 1] = ')';135} else if (kev->filter == EVFILT_VNODE) {136snprintf(buf, 1024, "fflags = %x (", kev->fflags);137KEVFFL_DUMP(NOTE_DELETE);138KEVFFL_DUMP(NOTE_WRITE);139KEVFFL_DUMP(NOTE_EXTEND);140#if HAVE_NOTE_TRUNCATE141KEVFFL_DUMP(NOTE_TRUNCATE);142#endif143KEVFFL_DUMP(NOTE_ATTRIB);144KEVFFL_DUMP(NOTE_LINK);145KEVFFL_DUMP(NOTE_RENAME);146#if HAVE_NOTE_REVOKE147KEVFFL_DUMP(NOTE_REVOKE);148#endif149buf[strlen(buf) - 1] = ')';150} else {151snprintf(buf, 1024, "fflags = %x", kev->fflags);152}153154return (buf);155}156157static char *158kevent_flags_dump(struct kevent *kev)159{160char *buf;161162#define KEVFL_DUMP(attrib) \163if (kev->flags & attrib) \164strncat(buf, #attrib" ", 64);165166if ((buf = calloc(1, 1024)) == NULL)167abort();168169snprintf(buf, 1024, "flags = %d (", kev->flags);170KEVFL_DUMP(EV_ADD);171KEVFL_DUMP(EV_ENABLE);172KEVFL_DUMP(EV_DISABLE);173KEVFL_DUMP(EV_DELETE);174KEVFL_DUMP(EV_ONESHOT);175KEVFL_DUMP(EV_CLEAR);176KEVFL_DUMP(EV_EOF);177KEVFL_DUMP(EV_ERROR);178#if HAVE_EV_DISPATCH179KEVFL_DUMP(EV_DISPATCH);180#endif181#if HAVE_EV_RECEIPT182KEVFL_DUMP(EV_RECEIPT);183#endif184buf[strlen(buf) - 1] = ')';185186return (buf);187}188189/* Copied from ../kevent.c kevent_dump() and improved */190char *191kevent_to_str(struct kevent *kev)192{193char buf[512];194char *flags_str = kevent_flags_dump(kev);195char *fflags_str = kevent_fflags_dump(kev);196197snprintf(&buf[0], sizeof(buf),198"[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, "199"ext=[%jx %jx %jx %jx]",200(uintmax_t) kev->ident,201kev->filter,202flags_str,203fflags_str,204(uintmax_t)kev->data,205kev->udata,206(uintmax_t)kev->ext[0],207(uintmax_t)kev->ext[1],208(uintmax_t)kev->ext[2],209(uintmax_t)kev->ext[3]);210211free(flags_str);212free(fflags_str);213214return (strdup(buf));215}216217void218kevent_add(int fd, struct kevent *kev,219uintptr_t ident,220short filter,221u_short flags,222u_int fflags,223intptr_t data,224void *udata)225{226char *kev_str;227228EV_SET(kev, ident, filter, flags, fflags, data, udata);229if (kevent(fd, kev, 1, NULL, 0, NULL) < 0) {230kev_str = kevent_to_str(kev);231printf("Unable to add the following kevent:\n%s\n",232kev_str);233free(kev_str);234err(1, "kevent(): %s", strerror(errno));235}236}237238void239_kevent_cmp(struct kevent *k1, struct kevent *k2, const char *file, int line)240{241char *kev1_str;242char *kev2_str;243244/* XXX-245Workaround for inconsistent implementation of kevent(2)246*/247#ifdef __FreeBSD__248if (k1->flags & EV_ADD)249k2->flags |= EV_ADD;250#endif251if (k1->ident != k2->ident || k1->filter != k2->filter ||252k1->flags != k2->flags || k1->fflags != k2->fflags ||253k1->data != k2->data || k1->udata != k2->udata ||254k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] ||255k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) {256kev1_str = kevent_to_str(k1);257kev2_str = kevent_to_str(k2);258printf("[%s:%d]: kevent_cmp: mismatch:\n %s !=\n %s\n",259file, line, kev1_str, kev2_str);260free(kev1_str);261free(kev2_str);262abort();263}264}265266void267test_begin(const char *func)268{269if (cur_test_id)270free(cur_test_id);271cur_test_id = strdup(func);272if (!cur_test_id)273err(1, "strdup failed");274275printf("\n\nTest %d: %s\n", testnum++, func);276}277278void279success(void)280{281printf("%-70s %s\n", cur_test_id, "passed");282free(cur_test_id);283cur_test_id = NULL;284}285286static void287test_kqueue(void)288{289test_begin("kqueue()");290if ((kqfd = kqueue()) < 0)291err(1, "kqueue()");292test_no_kevents();293success();294}295296static void297test_kqueue_close(void)298{299test_begin("close(kq)");300if (close(kqfd) < 0)301err(1, "close()");302success();303}304305int306main(int argc, char **argv)307{308int test_proc = 1;309int test_socket = 1;310int test_signal = 1;311int test_vnode = 1;312int test_timer = 1;313#ifdef __FreeBSD__314int test_user = 1;315#else316/* XXX-FIXME temporary */317int test_user = 0;318#endif319320while (argc) {321if (strcmp(argv[0], "--no-proc") == 0)322test_proc = 0;323if (strcmp(argv[0], "--no-socket") == 0)324test_socket = 0;325if (strcmp(argv[0], "--no-timer") == 0)326test_timer = 0;327if (strcmp(argv[0], "--no-signal") == 0)328test_signal = 0;329if (strcmp(argv[0], "--no-vnode") == 0)330test_vnode = 0;331if (strcmp(argv[0], "--no-user") == 0)332test_user = 0;333argv++;334argc--;335}336337/*338* Some tests fork. If output is fully buffered,339* the children inherit some buffered data and flush340* it when they exit, causing some data to be printed twice.341* Use line buffering to avoid this problem.342*/343setlinebuf(stdout);344setlinebuf(stderr);345346test_kqueue();347test_kqueue_close();348349if (test_socket)350test_evfilt_read();351if (test_signal)352test_evfilt_signal();353if (test_vnode)354test_evfilt_vnode();355#if HAVE_EVFILT_USER356if (test_user)357test_evfilt_user();358#endif359if (test_timer)360test_evfilt_timer();361if (test_proc)362test_evfilt_proc();363364printf("\n---\n"365"+OK All %d tests completed.\n", testnum - 1);366return (0);367}368369370