From 3a757c0c1f3f1d07c1bcfba87100164c348efa06 Mon Sep 17 00:00:00 2001 From: ngie Date: Wed, 13 May 2015 12:09:01 +0000 Subject: MFC r281593,r282071,r282074,r282133,r282134,r282135,r282136,r282137,r282138: r282071: Integrate tools/regression/mqueue into the FreeBSD test suite as tests/sys/mqueue r282074: Integrate tools/regression/aio/aiotest and tools/regression/aio/kqueue into the FreeBSD test suite as tests/sys/aio r282133: Fill in the copyright boilerplate for the test program r282134: Add initial (unpolished) macros for interfacing with the FreeBSD test suite This is very rough, but will be replaced/redesigned some time soon after I fix the Jenkins breakage I introduced r282135: Use ATF_REQUIRE_KERNEL_MODULE instead of aio_available function r282136: - Use ATF_REQUIRE_KERNEL_MDOULE to require aio(4) - Don't use /tmp as a basis for temporary files as it's outside of the ATF sandbox - Don't override MAX macro in sys/param.h r282137: Use PLAIN_REQUIRE_KERNEL_MODULE to require "mqueuefs" r282138: Adjust CFLAGS to find freebsd_test_suite/macros.h --- tests/freebsd_test_suite/macros.h | 53 +++ tests/sys/Makefile | 2 + tests/sys/aio/Makefile | 16 + tests/sys/aio/aio_kqueue_test.c | 211 ++++++++++++ tests/sys/aio/aio_test.c | 658 ++++++++++++++++++++++++++++++++++++++ tests/sys/aio/lio_kqueue_test.c | 249 +++++++++++++++ tests/sys/mqueue/Makefile | 22 ++ tests/sys/mqueue/mqtest1.c | 57 ++++ tests/sys/mqueue/mqtest2.c | 101 ++++++ tests/sys/mqueue/mqtest3.c | 116 +++++++ tests/sys/mqueue/mqtest4.c | 120 +++++++ tests/sys/mqueue/mqtest5.c | 128 ++++++++ tests/sys/mqueue/mqueue_test.sh | 81 +++++ 13 files changed, 1814 insertions(+) create mode 100644 tests/freebsd_test_suite/macros.h create mode 100644 tests/sys/aio/Makefile create mode 100644 tests/sys/aio/aio_kqueue_test.c create mode 100644 tests/sys/aio/aio_test.c create mode 100644 tests/sys/aio/lio_kqueue_test.c create mode 100644 tests/sys/mqueue/Makefile create mode 100644 tests/sys/mqueue/mqtest1.c create mode 100644 tests/sys/mqueue/mqtest2.c create mode 100644 tests/sys/mqueue/mqtest3.c create mode 100644 tests/sys/mqueue/mqtest4.c create mode 100644 tests/sys/mqueue/mqtest5.c create mode 100755 tests/sys/mqueue/mqueue_test.sh (limited to 'tests') diff --git a/tests/freebsd_test_suite/macros.h b/tests/freebsd_test_suite/macros.h new file mode 100644 index 0000000..755a994 --- /dev/null +++ b/tests/freebsd_test_suite/macros.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2015 EMC / Isilon Storage Division + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _FREEBSD_TEST_MACROS_H_ +#define _FREEBSD_TEST_MACROS_H_ + +#include +#include +#include +#include +#include + +#include + +#define ATF_REQUIRE_KERNEL_MODULE(_mod_name) do { \ + ATF_REQUIRE_MSG(modfind(_mod_name) != -1, \ + "module %s could not be resolved: %s", \ + _mod_name, strerror(errno)); \ +} while(0) + +#define PLAIN_REQUIRE_KERNEL_MODULE(_mod_name, _exit_code) do { \ + if (modfind(_mod_name) == -1) { \ + err(_exit_code, "module %s could not be resolved", \ + _mod_name); \ + } \ +} while(0) + +#endif diff --git a/tests/sys/Makefile b/tests/sys/Makefile index a1a8239..3f621ea 100644 --- a/tests/sys/Makefile +++ b/tests/sys/Makefile @@ -4,10 +4,12 @@ TESTSDIR= ${TESTSBASE}/sys +TESTS_SUBDIRS+= aio TESTS_SUBDIRS+= fifo TESTS_SUBDIRS+= file TESTS_SUBDIRS+= kern TESTS_SUBDIRS+= kqueue +TESTS_SUBDIRS+= mqueue TESTS_SUBDIRS+= netinet TESTS_SUBDIRS+= vm diff --git a/tests/sys/aio/Makefile b/tests/sys/aio/Makefile new file mode 100644 index 0000000..851252d --- /dev/null +++ b/tests/sys/aio/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/aio + +PLAIN_TESTS_C+= aio_kqueue_test +PLAIN_TESTS_C+= lio_kqueue_test +ATF_TESTS_C+= aio_test + +DPADD.aio_test+= ${LIBUTIL} +LDADD.aio_test+= -lutil + +CFLAGS+= -I${.CURDIR:H:H} + +WARNS?= 6 + +.include diff --git a/tests/sys/aio/aio_kqueue_test.c b/tests/sys/aio/aio_kqueue_test.c new file mode 100644 index 0000000..14e4729 --- /dev/null +++ b/tests/sys/aio/aio_kqueue_test.c @@ -0,0 +1,211 @@ +/*- + * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Prerequisities: + * - AIO support must be compiled into the kernel (see sys//NOTES for + * more details). + * + * Note: it is a good idea to run this against a physical drive to + * exercise the physio fast path (ie. aio_kqueue /dev/) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define PATH_TEMPLATE "aio.XXXXXXXXXX" + +#define MAX_IOCBS 128 +#define MAX_RUNS 300 +/* #define DEBUG */ + +int +main (int argc, char *argv[]) +{ + struct aiocb *iocb[MAX_IOCBS], *kq_iocb; + char *file, pathname[sizeof(PATH_TEMPLATE)+1]; + struct kevent ke, kq_returned; + struct timespec ts; + char buffer[32768]; + int cancel, error, failed = 0, fd, kq, pending, result, run; + int tmp_file = 0; + unsigned i, j; + + PLAIN_REQUIRE_KERNEL_MODULE("aio", 0); + + kq = kqueue(); + if (kq < 0) { + perror("No kqeueue\n"); + exit(1); + } + + if (argc == 1) { + strcpy(pathname, PATH_TEMPLATE); + fd = mkstemp(pathname); + file = pathname; + tmp_file = 1; + } else { + file = argv[1]; + fd = open(file, O_RDWR|O_CREAT, 0666); + } + if (fd == -1) + err(1, "Can't open %s\n", file); + + for (run = 0; run < MAX_RUNS; run++){ +#ifdef DEBUG + printf("Run %d\n", run); +#endif + for (i = 0; i < nitems(iocb); i++) { + iocb[i] = (struct aiocb *)calloc(1, + sizeof(struct aiocb)); + if (iocb[i] == NULL) + err(1, "calloc"); + } + + pending = 0; + for (i = 0; i < nitems(iocb); i++) { + pending++; + iocb[i]->aio_nbytes = sizeof(buffer); + iocb[i]->aio_buf = buffer; + iocb[i]->aio_fildes = fd; + iocb[i]->aio_offset = iocb[i]->aio_nbytes * i * run; + + iocb[i]->aio_sigevent.sigev_notify_kqueue = kq; + iocb[i]->aio_sigevent.sigev_value.sival_ptr = iocb[i]; + iocb[i]->aio_sigevent.sigev_notify = SIGEV_KEVENT; + + result = aio_write(iocb[i]); + if (result != 0) { + perror("aio_write"); + printf("Result %d iteration %d\n", result, i); + exit(1); + } +#ifdef DEBUG + printf("WRITE %d is at %p\n", i, iocb[i]); +#endif + result = rand(); + if (result < RAND_MAX/32) { + if (result > RAND_MAX/64) { + result = aio_cancel(fd, iocb[i]); +#ifdef DEBUG + printf("Cancel %d %p result %d\n", i, iocb[i], result); +#endif + if (result == AIO_CANCELED) { + aio_return(iocb[i]); + iocb[i] = NULL; + pending--; + } + } + } + } + cancel = nitems(iocb) - pending; + + i = 0; + while (pending) { + + for (;;) { + + bzero(&ke, sizeof(ke)); + bzero(&kq_returned, sizeof(ke)); + ts.tv_sec = 0; + ts.tv_nsec = 1; + result = kevent(kq, NULL, 0, + &kq_returned, 1, &ts); + error = errno; + if (result < 0) + perror("kevent error: "); + kq_iocb = kq_returned.udata; +#ifdef DEBUG + printf("kevent %d %d errno %d return.ident %p " + "return.data %p return.udata %p %p\n", + i, result, error, + kq_returned.ident, kq_returned.data, + kq_returned.udata, + kq_iocb); +#endif + + if (kq_iocb) + break; +#ifdef DEBUG + printf("Try again left %d out of %d %d\n", + pending, nitems(iocb), cancel); +#endif + } + + for (j = 0; j < nitems(iocb) && iocb[j] != kq_iocb; + j++) ; +#ifdef DEBUG + printf("kq_iocb %p\n", kq_iocb); + + printf("Error Result for %d is %d pending %d\n", + j, result, pending); +#endif + result = aio_return(kq_iocb); +#ifdef DEBUG + printf("Return Result for %d is %d\n\n", j, result); +#endif + if (result != sizeof(buffer)) { + printf("FAIL: run %d, operation %d, result %d " + " (errno=%d) should be %zu\n", run, pending, + result, errno, sizeof(buffer)); + failed++; + } else + printf("PASS: run %d, left %d\n", run, + pending - 1); + + free(kq_iocb); + iocb[j] = NULL; + pending--; + i++; + } + + for (i = 0; i < nitems(iocb); i++) + free(iocb[i]); + + } + + if (tmp_file) + unlink(pathname); + + if (failed != 0) + printf("FAIL: %d tests failed\n", failed); + else + printf("PASS: All tests passed\n"); + + exit (failed == 0 ? 0 : 1); +} diff --git a/tests/sys/aio/aio_test.c b/tests/sys/aio/aio_test.c new file mode 100644 index 0000000..4134e78 --- /dev/null +++ b/tests/sys/aio/aio_test.c @@ -0,0 +1,658 @@ +/*- + * Copyright (c) 2004 Robert N. M. Watson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Regression test to do some very basic AIO exercising on several types of + * file descriptors. Currently, the tests consist of initializing a fixed + * size buffer with pseudo-random data, writing it to one fd using AIO, then + * reading it from a second descriptor using AIO. For some targets, the same + * fd is used for write and read (i.e., file, md device), but for others the + * operation is performed on a peer (pty, socket, fifo, etc). A timeout is + * initiated to detect undo blocking. This test does not attempt to exercise + * error cases or more subtle asynchronous behavior, just make sure that the + * basic operations work on some basic object types. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "freebsd_test_suite/macros.h" + +#define PATH_TEMPLATE "aio.XXXXXXXXXX" + +/* + * GLOBAL_MAX sets the largest usable buffer size to be read and written, as + * it sizes ac_buffer in the aio_context structure. It is also the default + * size for file I/O. For other types, we use smaller blocks or we risk + * blocking (and we run in a single process/thread so that would be bad). + */ +#define GLOBAL_MAX 16384 + +#define BUFFER_MAX GLOBAL_MAX +struct aio_context { + int ac_read_fd, ac_write_fd; + long ac_seed; + char ac_buffer[GLOBAL_MAX]; + int ac_buflen; + int ac_seconds; + void (*ac_cleanup)(void *arg); + void *ac_cleanup_arg; +}; + +static int aio_timedout; + +/* + * Each test run specifies a timeout in seconds. Use the somewhat obsoleted + * signal(3) and alarm(3) APIs to set this up. + */ +static void +aio_timeout_signal(int sig __unused) +{ + + aio_timedout = 1; +} + +static void +aio_timeout_start(int seconds) +{ + + aio_timedout = 0; + ATF_REQUIRE_MSG(signal(SIGALRM, aio_timeout_signal) != SIG_ERR, + "failed to set SIGALRM handler: %s", strerror(errno)); + alarm(seconds); +} + +static void +aio_timeout_stop(void) +{ + + ATF_REQUIRE_MSG(signal(SIGALRM, NULL) != SIG_ERR, + "failed to reset SIGALRM handler to default: %s", strerror(errno)); + alarm(0); +} + +/* + * Fill a buffer given a seed that can be fed into srandom() to initialize + * the PRNG in a repeatable manner. + */ +static void +aio_fill_buffer(char *buffer, int len, long seed) +{ + char ch; + int i; + + srandom(seed); + for (i = 0; i < len; i++) { + ch = random() & 0xff; + buffer[i] = ch; + } +} + +/* + * Test that a buffer matches a given seed. See aio_fill_buffer(). Return + * (1) on a match, (0) on a mismatch. + */ +static int +aio_test_buffer(char *buffer, int len, long seed) +{ + char ch; + int i; + + srandom(seed); + for (i = 0; i < len; i++) { + ch = random() & 0xff; + if (buffer[i] != ch) + return (0); + } + return (1); +} + +/* + * Initialize a testing context given the file descriptors provided by the + * test setup. + */ +static void +aio_context_init(struct aio_context *ac, int read_fd, + int write_fd, int buflen, int seconds, void (*cleanup)(void *), + void *cleanup_arg) +{ + + ATF_REQUIRE_MSG(buflen <= BUFFER_MAX, + "aio_context_init: buffer too large (%d > %d)", + buflen, BUFFER_MAX); + bzero(ac, sizeof(*ac)); + ac->ac_read_fd = read_fd; + ac->ac_write_fd = write_fd; + ac->ac_buflen = buflen; + srandomdev(); + ac->ac_seed = random(); + aio_fill_buffer(ac->ac_buffer, buflen, ac->ac_seed); + ATF_REQUIRE_MSG(aio_test_buffer(ac->ac_buffer, buflen, + ac->ac_seed) != 0, "aio_test_buffer: internal error"); + ac->ac_seconds = seconds; + ac->ac_cleanup = cleanup; + ac->ac_cleanup_arg = cleanup_arg; +} + +/* + * Each tester can register a callback to clean up in the event the test + * fails. Preserve the value of errno so that subsequent calls to errx() + * work properly. + */ +static void +aio_cleanup(struct aio_context *ac) +{ + int error; + + if (ac->ac_cleanup == NULL) + return; + error = errno; + (ac->ac_cleanup)(ac->ac_cleanup_arg); + errno = error; +} + +/* + * Perform a simple write test of our initialized data buffer to the provided + * file descriptor. + */ +static void +aio_write_test(struct aio_context *ac) +{ + struct aiocb aio, *aiop; + ssize_t len; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + bzero(&aio, sizeof(aio)); + aio.aio_buf = ac->ac_buffer; + aio.aio_nbytes = ac->ac_buflen; + aio.aio_fildes = ac->ac_write_fd; + aio.aio_offset = 0; + + aio_timeout_start(ac->ac_seconds); + + if (aio_write(&aio) < 0) { + if (errno == EINTR) { + if (aio_timedout) { + aio_cleanup(ac); + atf_tc_fail("aio_write timed out"); + } + } + aio_cleanup(ac); + atf_tc_fail("aio_write failed: %s", strerror(errno)); + } + + len = aio_waitcomplete(&aiop, NULL); + if (len < 0) { + if (errno == EINTR) { + if (aio_timedout) { + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete timed out"); + } + } + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); + } + + aio_timeout_stop(); + + if (len != ac->ac_buflen) { + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete short write (%jd)", + (intmax_t)len); + } +} + +/* + * Perform a simple read test of our initialized data buffer from the + * provided file descriptor. + */ +static void +aio_read_test(struct aio_context *ac) +{ + struct aiocb aio, *aiop; + ssize_t len; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + bzero(ac->ac_buffer, ac->ac_buflen); + bzero(&aio, sizeof(aio)); + aio.aio_buf = ac->ac_buffer; + aio.aio_nbytes = ac->ac_buflen; + aio.aio_fildes = ac->ac_read_fd; + aio.aio_offset = 0; + + aio_timeout_start(ac->ac_seconds); + + if (aio_read(&aio) < 0) { + if (errno == EINTR) { + if (aio_timedout) { + aio_cleanup(ac); + atf_tc_fail("aio_write timed out"); + } + } + aio_cleanup(ac); + atf_tc_fail("aio_read failed: %s", strerror(errno)); + } + + len = aio_waitcomplete(&aiop, NULL); + if (len < 0) { + if (errno == EINTR) { + if (aio_timedout) { + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete timed out"); + } + } + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete failed: %s", strerror(errno)); + } + + aio_timeout_stop(); + + if (len != ac->ac_buflen) { + aio_cleanup(ac); + atf_tc_fail("aio_waitcomplete short read (%jd)", + (intmax_t)len); + } + + if (aio_test_buffer(ac->ac_buffer, ac->ac_buflen, ac->ac_seed) == 0) { + aio_cleanup(ac); + atf_tc_fail("buffer mismatched"); + } +} + +/* + * Series of type-specific tests for AIO. For now, we just make sure we can + * issue a write and then a read to each type. We assume that once a write + * is issued, a read can follow. + */ + +/* + * Test with a classic file. Assumes we can create a moderate size temporary + * file. + */ +struct aio_file_arg { + int afa_fd; + char *afa_pathname; +}; + +static void +aio_file_cleanup(void *arg) +{ + struct aio_file_arg *afa; + + afa = arg; + close(afa->afa_fd); + unlink(afa->afa_pathname); +} + +#define FILE_LEN GLOBAL_MAX +#define FILE_TIMEOUT 30 +ATF_TC_WITHOUT_HEAD(aio_file_test); +ATF_TC_BODY(aio_file_test, tc) +{ + char pathname[PATH_MAX]; + struct aio_file_arg arg; + struct aio_context ac; + int fd; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + strcpy(pathname, PATH_TEMPLATE); + fd = mkstemp(pathname); + ATF_REQUIRE_MSG(fd != -1, "mkstemp failed: %s", strerror(errno)); + + arg.afa_fd = fd; + arg.afa_pathname = pathname; + + aio_context_init(&ac, fd, fd, FILE_LEN, + FILE_TIMEOUT, aio_file_cleanup, &arg); + aio_write_test(&ac); + aio_read_test(&ac); + + aio_file_cleanup(&arg); +} + +struct aio_fifo_arg { + int afa_read_fd; + int afa_write_fd; + char *afa_pathname; +}; + +static void +aio_fifo_cleanup(void *arg) +{ + struct aio_fifo_arg *afa; + + afa = arg; + if (afa->afa_read_fd != -1) + close(afa->afa_read_fd); + if (afa->afa_write_fd != -1) + close(afa->afa_write_fd); + unlink(afa->afa_pathname); +} + +#define FIFO_LEN 256 +#define FIFO_TIMEOUT 30 +ATF_TC_WITHOUT_HEAD(aio_fifo_test); +ATF_TC_BODY(aio_fifo_test, tc) +{ + int error, read_fd = -1, write_fd = -1; + struct aio_fifo_arg arg; + char pathname[PATH_MAX]; + struct aio_context ac; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + /* + * In theory, mkstemp() can return a name that is then collided with. + * Because this is a regression test, we treat that as a test failure + * rather than retrying. + */ + strcpy(pathname, PATH_TEMPLATE); + ATF_REQUIRE_MSG(mkstemp(pathname) != -1, + "mkstemp failed: %s", strerror(errno)); + ATF_REQUIRE_MSG(unlink(pathname) == 0, + "unlink failed: %s", strerror(errno)); + ATF_REQUIRE_MSG(mkfifo(pathname, 0600) != -1, + "mkfifo failed: %s", strerror(errno)); + arg.afa_pathname = pathname; + arg.afa_read_fd = -1; + arg.afa_write_fd = -1; + + read_fd = open(pathname, O_RDONLY | O_NONBLOCK); + if (read_fd == -1) { + error = errno; + aio_fifo_cleanup(&arg); + errno = error; + atf_tc_fail("read_fd open failed: %s", + strerror(errno)); + } + arg.afa_read_fd = read_fd; + + write_fd = open(pathname, O_WRONLY); + if (write_fd == -1) { + error = errno; + aio_fifo_cleanup(&arg); + errno = error; + atf_tc_fail("write_fd open failed: %s", + strerror(errno)); + } + arg.afa_write_fd = write_fd; + + aio_context_init(&ac, read_fd, write_fd, FIFO_LEN, + FIFO_TIMEOUT, aio_fifo_cleanup, &arg); + aio_write_test(&ac); + aio_read_test(&ac); + + aio_fifo_cleanup(&arg); +} + +struct aio_unix_socketpair_arg { + int asa_sockets[2]; +}; + +static void +aio_unix_socketpair_cleanup(void *arg) +{ + struct aio_unix_socketpair_arg *asa; + + asa = arg; + close(asa->asa_sockets[0]); + close(asa->asa_sockets[1]); +} + +#define UNIX_SOCKETPAIR_LEN 256 +#define UNIX_SOCKETPAIR_TIMEOUT 30 +ATF_TC_WITHOUT_HEAD(aio_unix_socketpair_test); +ATF_TC_BODY(aio_unix_socketpair_test, tc) +{ + struct aio_unix_socketpair_arg arg; + struct aio_context ac; + int sockets[2]; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, sockets) != -1, + "socketpair failed: %s", strerror(errno)); + + arg.asa_sockets[0] = sockets[0]; + arg.asa_sockets[1] = sockets[1]; + aio_context_init(&ac, sockets[0], + sockets[1], UNIX_SOCKETPAIR_LEN, UNIX_SOCKETPAIR_TIMEOUT, + aio_unix_socketpair_cleanup, &arg); + aio_write_test(&ac); + aio_read_test(&ac); + + aio_unix_socketpair_cleanup(&arg); +} + +struct aio_pty_arg { + int apa_read_fd; + int apa_write_fd; +}; + +static void +aio_pty_cleanup(void *arg) +{ + struct aio_pty_arg *apa; + + apa = arg; + close(apa->apa_read_fd); + close(apa->apa_write_fd); +}; + +#define PTY_LEN 256 +#define PTY_TIMEOUT 30 +ATF_TC_WITHOUT_HEAD(aio_pty_test); +ATF_TC_BODY(aio_pty_test, tc) +{ + struct aio_pty_arg arg; + struct aio_context ac; + int read_fd, write_fd; + struct termios ts; + int error; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + ATF_REQUIRE_MSG(openpty(&read_fd, &write_fd, NULL, NULL, NULL) == 0, + "openpty failed: %s", strerror(errno)); + + arg.apa_read_fd = read_fd; + arg.apa_write_fd = write_fd; + + if (tcgetattr(write_fd, &ts) < 0) { + error = errno; + aio_pty_cleanup(&arg); + errno = error; + atf_tc_fail("tcgetattr failed: %s", strerror(errno)); + } + cfmakeraw(&ts); + if (tcsetattr(write_fd, TCSANOW, &ts) < 0) { + error = errno; + aio_pty_cleanup(&arg); + errno = error; + atf_tc_fail("tcsetattr failed: %s", strerror(errno)); + } + aio_context_init(&ac, read_fd, write_fd, PTY_LEN, + PTY_TIMEOUT, aio_pty_cleanup, &arg); + + aio_write_test(&ac); + aio_read_test(&ac); + + aio_pty_cleanup(&arg); +} + +static void +aio_pipe_cleanup(void *arg) +{ + int *pipes = arg; + + close(pipes[0]); + close(pipes[1]); +} + +#define PIPE_LEN 256 +#define PIPE_TIMEOUT 30 +ATF_TC_WITHOUT_HEAD(aio_pipe_test); +ATF_TC_BODY(aio_pipe_test, tc) +{ + struct aio_context ac; + int pipes[2]; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + ATF_REQUIRE_MSG(pipe(pipes) != -1, + "pipe failed: %s", strerror(errno)); + + aio_context_init(&ac, pipes[0], pipes[1], PIPE_LEN, + PIPE_TIMEOUT, aio_pipe_cleanup, pipes); + aio_write_test(&ac); + aio_read_test(&ac); + + aio_pipe_cleanup(pipes); +} + +struct aio_md_arg { + int ama_mdctl_fd; + int ama_unit; + int ama_fd; +}; + +static void +aio_md_cleanup(void *arg) +{ + struct aio_md_arg *ama; + struct md_ioctl mdio; + int error; + + ama = arg; + + if (ama->ama_fd != -1) + close(ama->ama_fd); + + if (ama->ama_unit != -1) { + bzero(&mdio, sizeof(mdio)); + mdio.md_version = MDIOVERSION; + mdio.md_unit = ama->ama_unit; + if (ioctl(ama->ama_mdctl_fd, MDIOCDETACH, &mdio) == -1) { + error = errno; + close(ama->ama_mdctl_fd); + errno = error; + atf_tc_fail("ioctl MDIOCDETACH failed: %s", + strerror(errno)); + } + } + + close(ama->ama_mdctl_fd); +} + +#define MD_LEN GLOBAL_MAX +#define MD_TIMEOUT 30 +ATF_TC(aio_md_test); +ATF_TC_HEAD(aio_md_test, tc) +{ + + atf_tc_set_md_var(tc, "require.user", "root"); +} +ATF_TC_BODY(aio_md_test, tc) +{ + int error, fd, mdctl_fd, unit; + char pathname[PATH_MAX]; + struct aio_md_arg arg; + struct aio_context ac; + struct md_ioctl mdio; + + ATF_REQUIRE_KERNEL_MODULE("aio"); + + mdctl_fd = open("/dev/" MDCTL_NAME, O_RDWR, 0); + ATF_REQUIRE_MSG(mdctl_fd != -1, + "opening /dev/%s failed: %s", MDCTL_NAME, strerror(errno)); + + bzero(&mdio, sizeof(mdio)); + mdio.md_version = MDIOVERSION; + mdio.md_type = MD_MALLOC; + mdio.md_options = MD_AUTOUNIT | MD_COMPRESS; + mdio.md_mediasize = GLOBAL_MAX; + mdio.md_sectorsize = 512; + + arg.ama_mdctl_fd = mdctl_fd; + arg.ama_unit = -1; + arg.ama_fd = -1; + if (ioctl(mdctl_fd, MDIOCATTACH, &mdio) < 0) { + error = errno; + aio_md_cleanup(&arg); + errno = error; + atf_tc_fail("ioctl MDIOCATTACH failed: %s", strerror(errno)); + } + + arg.ama_unit = unit = mdio.md_unit; + snprintf(pathname, PATH_MAX, "/dev/md%d", unit); + fd = open(pathname, O_RDWR); + ATF_REQUIRE_MSG(fd != -1, + "opening %s failed: %s", pathname, strerror(errno)); + arg.ama_fd = fd; + + aio_context_init(&ac, fd, fd, MD_LEN, MD_TIMEOUT, + aio_md_cleanup, &arg); + aio_write_test(&ac); + aio_read_test(&ac); + + aio_md_cleanup(&arg); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, aio_file_test); + ATF_TP_ADD_TC(tp, aio_fifo_test); + ATF_TP_ADD_TC(tp, aio_unix_socketpair_test); + ATF_TP_ADD_TC(tp, aio_pty_test); + ATF_TP_ADD_TC(tp, aio_pipe_test); + ATF_TP_ADD_TC(tp, aio_md_test); + + return (atf_no_error()); +} diff --git a/tests/sys/aio/lio_kqueue_test.c b/tests/sys/aio/lio_kqueue_test.c new file mode 100644 index 0000000..5cc87b3 --- /dev/null +++ b/tests/sys/aio/lio_kqueue_test.c @@ -0,0 +1,249 @@ +/*- + * Copyright (C) 2005 IronPort Systems, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +/* + * Note: it is a good idea to run this against a physical drive to + * exercise the physio fast path (ie. lio_kqueue /dev/) + * This will ensure op's counting is correct. It is currently broken. + * + * Also note that LIO & kqueue is not implemented in FreeBSD yet, LIO + * is also broken with respect to op's and some paths. + * + * A patch to make this work is at: + * http://www.ambrisko.com/doug/listio_kqueue/listio_kqueue.patch + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define PATH_TEMPLATE "aio.XXXXXXXXXX" + +#define LIO_MAX 5 +#define MAX_IOCBS LIO_MAX * 16 +#define MAX_RUNS 300 + +int +main(int argc, char *argv[]){ + int fd; + struct aiocb *iocb[MAX_IOCBS]; + struct aiocb **lio[LIO_MAX], **lio_element, **kq_lio; + int i, result, run, error, j, k; + char buffer[32768]; + int kq = kqueue(); + struct kevent ke, kq_returned; + struct timespec ts; + struct sigevent sig; + time_t time1, time2; + char *file, pathname[sizeof(PATH_TEMPLATE)-1]; + int tmp_file = 0, failed = 0; + + PLAIN_REQUIRE_KERNEL_MODULE("aio", 0); + + if (kq < 0) { + perror("No kqeueue\n"); + exit(1); + } + + if (argc == 1) { + strcpy(pathname, PATH_TEMPLATE); + fd = mkstemp(pathname); + file = pathname; + tmp_file = 1; + } else { + file = argv[1]; + fd = open(file, O_RDWR|O_CREAT, 0666); + } + if (fd < 0){ + fprintf(stderr, "Can't open %s\n", argv[1]); + perror(""); + exit(1); + } + +#ifdef DEBUG + printf("Hello kq %d fd %d\n", kq, fd); +#endif + + for (run = 0; run < MAX_RUNS; run++){ +#ifdef DEBUG + printf("Run %d\n", run); +#endif + for (j = 0; j < LIO_MAX; j++) { + lio[j] = (struct aiocb **) + malloc(sizeof(struct aiocb *) * MAX_IOCBS/LIO_MAX); + for(i = 0; i < MAX_IOCBS / LIO_MAX; i++) { + k = (MAX_IOCBS / LIO_MAX * j) + i; + lio_element = lio[j]; + lio[j][i] = iocb[k] = (struct aiocb *) + malloc(sizeof(struct aiocb)); + bzero(iocb[k], sizeof(struct aiocb)); + iocb[k]->aio_nbytes = sizeof(buffer); + iocb[k]->aio_buf = buffer; + iocb[k]->aio_fildes = fd; + iocb[k]->aio_offset + = iocb[k]->aio_nbytes * k * (run + 1); + +#ifdef DEBUG + printf("hello iocb[k] %d\n", + iocb[k]->aio_offset); +#endif + iocb[k]->aio_lio_opcode = LIO_WRITE; + } + sig.sigev_notify_kqueue = kq; + sig.sigev_value.sival_ptr = lio[j]; + sig.sigev_notify = SIGEV_KEVENT; + time(&time1); + result = lio_listio(LIO_NOWAIT, lio[j], + MAX_IOCBS / LIO_MAX, &sig); + error = errno; + time(&time2); +#ifdef DEBUG + printf("Time %d %d %d result -> %d\n", + time1, time2, time2-time1, result); +#endif + if (result != 0) { + errno = error; + perror("list_listio"); + printf("FAIL: Result %d iteration %d\n",result, j); + exit(1); + } +#ifdef DEBUG + printf("write %d is at %p\n", j, lio[j]); +#endif + } + + for(i = 0; i < LIO_MAX; i++) { + for(j = LIO_MAX - 1; j >=0; j--) { + if (lio[j]) + break; + } + + for(;;) { + bzero(&ke, sizeof(ke)); + bzero(&kq_returned, sizeof(ke)); + ts.tv_sec = 0; + ts.tv_nsec = 1; +#ifdef DEBUG + printf("FOO lio %d -> %p\n", j, lio[j]); +#endif + EV_SET(&ke, (uintptr_t)lio[j], + EVFILT_LIO, EV_ONESHOT, 0, 0, iocb[j]); + result = kevent(kq, NULL, 0, + &kq_returned, 1, &ts); + error = errno; + if (result < 0) { + perror("kevent error: "); + } + kq_lio = kq_returned.udata; +#ifdef DEBUG + printf("kevent %d %d errno %d return.ident %p " + "return.data %p return.udata %p %p\n", + i, result, error, + kq_returned.ident, kq_returned.data, + kq_returned.udata, + lio[j]); +#endif + + if(kq_lio) + break; +#ifdef DEBUG + printf("Try again\n"); +#endif + } + +#ifdef DEBUG + printf("lio %p\n", lio); +#endif + + for (j = 0; j < LIO_MAX; j++) { + if (lio[j] == kq_lio) { + break; + } + } + if (j == LIO_MAX) { + printf("FAIL:\n"); + exit(1); + } + +#ifdef DEBUG + printf("Error Result for %d is %d\n", j, result); +#endif + if (result < 0) { + printf("FAIL: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result); + failed = 1; + } else { + printf("PASS: run %d, operation %d result %d \n", run, LIO_MAX - i -1, result); + } + for(k = 0; k < MAX_IOCBS / LIO_MAX; k++){ + result = aio_return(kq_lio[k]); +#ifdef DEBUG + printf("Return Resulto for %d %d is %d\n", j, k, result); +#endif + if (result != sizeof(buffer)) { + printf("FAIL: run %d, operation %d sub-opt %d result %d (errno=%d) should be %zu\n", + run, LIO_MAX - i -1, k, result, errno, sizeof(buffer)); + } else { + printf("PASS: run %d, operation %d sub-opt %d result %d\n", + run, LIO_MAX - i -1, k, result); + } + } +#ifdef DEBUG + printf("\n"); +#endif + + for(k = 0; k < MAX_IOCBS / LIO_MAX; k++) { + free(lio[j][k]); + } + free(lio[j]); + lio[j] = NULL; + } + } +#ifdef DEBUG + printf("Done\n"); +#endif + + if (tmp_file) { + unlink(pathname); + } + + if (failed) { + printf("FAIL: Atleast one\n"); + exit(1); + } else { + printf("PASS: All\n"); + exit(0); + } +} diff --git a/tests/sys/mqueue/Makefile b/tests/sys/mqueue/Makefile new file mode 100644 index 0000000..5af8b25 --- /dev/null +++ b/tests/sys/mqueue/Makefile @@ -0,0 +1,22 @@ +# $FreeBSD$ + +TESTSDIR= ${TESTSBASE}/sys/mqueue + +ATF_TESTS_SH= mqueue_test + +BINDIR= ${TESTSDIR} + +CFLAGS+= -I${.CURDIR:H:H} + +PROGS+= mqtest1 +PROGS+= mqtest2 +PROGS+= mqtest3 +PROGS+= mqtest4 +PROGS+= mqtest5 + +LDADD+= -lrt +DPADD+= ${LIBRT} + +WARNS?= 6 + +.include diff --git a/tests/sys/mqueue/mqtest1.c b/tests/sys/mqueue/mqtest1.c new file mode 100644 index 0000000..3accb28 --- /dev/null +++ b/tests/sys/mqueue/mqtest1.c @@ -0,0 +1,57 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define MQNAME "/mytstqueue1" + +int +main(void) +{ + struct mq_attr attr, attr2; + struct sigevent sigev; + mqd_t mq; + int status; + + PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0); + + attr.mq_maxmsg = 2; + attr.mq_msgsize = 100; + mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr); + if (mq == (mqd_t)-1) + err(1, "mq_open"); + status = mq_unlink(MQNAME); + if (status) + err(1, "mq_unlink"); + status = mq_getattr(mq, &attr2); + if (status) + err(1, "mq_getattr"); + if (attr.mq_maxmsg != attr2.mq_maxmsg) + err(1, "mq_maxmsg changed"); + if (attr.mq_msgsize != attr2.mq_msgsize) + err(1, "mq_msgsize changed"); + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGRTMIN; + status = mq_notify(mq, &sigev); + if (status) + err(1, "mq_notify"); + status = mq_notify(mq, &sigev); + if (status == 0) + err(1, "mq_notify 2"); + else if (errno != EBUSY) + err(1, "mq_notify 3"); + status = mq_notify(mq, NULL); + if (status) + err(1, "mq_notify 4"); + status = mq_close(mq); + if (status) + err(1, "mq_close"); + return (0); +} diff --git a/tests/sys/mqueue/mqtest2.c b/tests/sys/mqueue/mqtest2.c new file mode 100644 index 0000000..067e619 --- /dev/null +++ b/tests/sys/mqueue/mqtest2.c @@ -0,0 +1,101 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define MQNAME "/mytstqueue2" +#define LOOPS 1000 +#define PRIO 10 + +static void +alarmhandler(int sig __unused) +{ + write(1, "timeout\n", 8); + _exit(1); +} + +int +main(void) +{ + struct mq_attr attr; + mqd_t mq; + int status; + pid_t pid; + + PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0); + + mq_unlink(MQNAME); + + attr.mq_maxmsg = 5; + attr.mq_msgsize = 128; + mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr); + if (mq == (mqd_t)-1) + err(1, "mq_open"); + status = mq_getattr(mq, &attr); + if (status) + err(1, "mq_getattr"); + pid = fork(); + if (pid == 0) { /* child */ + char *buf; + int j, i; + unsigned int prio; + + mq_close(mq); + + signal(SIGALRM, alarmhandler); + + mq = mq_open(MQNAME, O_RDWR); + if (mq == (mqd_t)-1) + err(1, "child: mq_open"); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + alarm(3); + status = mq_receive(mq, buf, attr.mq_msgsize, &prio); + if (status == -1) + err(2, "child: mq_receive"); + for (i = 0; i < attr.mq_msgsize; ++i) + if (buf[i] != i) + err(3, "child: message data corrupted"); + if (prio != PRIO) + err(4, "child: priority is incorrect: %d", + prio); + } + alarm(0); + free(buf); + mq_close(mq); + return (0); + } else if (pid == -1) { + err(1, "fork()"); + } else { + char *buf; + int i, j; + + signal(SIGALRM, alarmhandler); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + for (i = 0; i < attr.mq_msgsize; ++i) + buf[i] = i; + alarm(3); + status = mq_send(mq, buf, attr.mq_msgsize, PRIO); + if (status) + err(1, "mq_send"); + } + alarm(3); + wait(&status); + alarm(0); + } + status = mq_close(mq); + if (status) + err(1, "mq_close"); + mq_unlink(MQNAME); + return (0); +} diff --git a/tests/sys/mqueue/mqtest3.c b/tests/sys/mqueue/mqtest3.c new file mode 100644 index 0000000..c4b849e --- /dev/null +++ b/tests/sys/mqueue/mqtest3.c @@ -0,0 +1,116 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define MQNAME "/mytstqueue3" +#define LOOPS 1000 +#define PRIO 10 + +static void +sighandler(int sig __unused) +{ + write(1, "timeout\n", 8); + _exit(1); +} + +int +main(void) +{ + fd_set set; + struct mq_attr attr; + int status; + mqd_t mq; + pid_t pid; + + PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0); + + mq_unlink(MQNAME); + + attr.mq_maxmsg = 5; + attr.mq_msgsize = 128; + mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr); + if (mq == (mqd_t)-1) + err(1, "mq_open()"); + status = mq_getattr(mq, &attr); + if (status) + err(1, "mq_getattr()"); + + pid = fork(); + if (pid == 0) { /* child */ + char *buf; + int j, i; + unsigned int prio; + + mq_close(mq); + + signal(SIGALRM, sighandler); + + mq = mq_open(MQNAME, O_RDWR); + if (mq == (mqd_t)-1) + err(1, "child process: mq_open"); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + FD_ZERO(&set); + FD_SET(__mq_oshandle(mq), &set); + alarm(3); + status = select(__mq_oshandle(mq)+1, &set, NULL, NULL, NULL); + if (status != 1) + err(1, "child process: select()"); + status = mq_receive(mq, buf, attr.mq_msgsize, &prio); + if (status == -1) + err(2, "child process: mq_receive"); + for (i = 0; i < attr.mq_msgsize; ++i) + if (buf[i] != i) + err(3, "message data corrupted"); + if (prio != PRIO) + err(4, "priority is incorrect: %d", prio); + } + alarm(0); + free(buf); + mq_close(mq); + return (0); + } else if (pid == -1) { + err(1, "fork()"); + } else { + char *buf; + int i, j; + + signal(SIGALRM, sighandler); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + for (i = 0; i < attr.mq_msgsize; ++i) { + buf[i] = i; + } + alarm(3); + FD_ZERO(&set); + FD_SET(__mq_oshandle(mq), &set); + status = select(__mq_oshandle(mq)+1, NULL, &set, NULL, NULL); + if (status != 1) + err(1, "select()"); + status = mq_send(mq, buf, attr.mq_msgsize, PRIO); + if (status) { + kill(pid, SIGKILL); + err(2, "mq_send()"); + } + } + alarm(3); + wait(&status); + alarm(0); + } + status = mq_close(mq); + if (status) + err(1, "mq_close"); + mq_unlink(MQNAME); + return (0); +} diff --git a/tests/sys/mqueue/mqtest4.c b/tests/sys/mqueue/mqtest4.c new file mode 100644 index 0000000..474d212 --- /dev/null +++ b/tests/sys/mqueue/mqtest4.c @@ -0,0 +1,120 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define MQNAME "/mytstqueue4" +#define LOOPS 1000 +#define PRIO 10 + +static void +sighandler(int sig __unused) +{ + write(1, "timeout\n", 8); + _exit(1); +} + +int +main(void) +{ + struct kevent kev; + struct mq_attr attr; + mqd_t mq; + int kq, status; + pid_t pid; + + PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0); + + mq_unlink(MQNAME); + + attr.mq_maxmsg = 5; + attr.mq_msgsize = 128; + mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr); + if (mq == (mqd_t) -1) + err(1, "mq_open()"); + status = mq_getattr(mq, &attr); + if (status) + err(1, "mq_getattr()"); + pid = fork(); + if (pid == 0) { /* child */ + char *buf; + int j, i; + unsigned int prio; + + mq_close(mq); + kq = kqueue(); + mq = mq_open(MQNAME, O_RDWR); + if (mq == (mqd_t)-1) + err(1, "child: mq_open"); + EV_SET(&kev, __mq_oshandle(mq), EVFILT_READ, EV_ADD, 0, 0, 0); + status = kevent(kq, &kev, 1, NULL, 0, NULL); + if (status == -1) + err(1, "child: kevent"); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + alarm(3); + status = kevent(kq, NULL, 0, &kev, 1, NULL); + if (status != 1) + err(1, "child: kevent 2"); + status = mq_receive(mq, buf, attr.mq_msgsize, &prio); + if (status == -1) + err(2, "child: mq_receive"); + for (i = 0; i < attr.mq_msgsize; ++i) + if (buf[i] != i) + err(3, "child: message data corrupted"); + if (prio != PRIO) + err(4, "child: priority is incorrect: %d", + prio); + } + alarm(0); + free(buf); + mq_close(mq); + return (0); + } else if (pid == -1) { + err(1, "fork()"); + } else { + char *buf; + int i, j; + + signal(SIGALRM, sighandler); + kq = kqueue(); + EV_SET(&kev, __mq_oshandle(mq), EVFILT_WRITE, EV_ADD, 0, 0, 0); + status = kevent(kq, &kev, 1, NULL, 0, NULL); + if (status == -1) + err(1, "kevent"); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + for (i = 0; i < attr.mq_msgsize; ++i) { + buf[i] = i; + } + alarm(3); + status = kevent(kq, NULL, 0, &kev, 1, NULL); + if (status != 1) + err(1, "child: kevent 2"); + status = mq_send(mq, buf, attr.mq_msgsize, PRIO); + if (status) { + err(2, "mq_send()"); + } + } + free(buf); + alarm(3); + wait(&status); + alarm(0); + } + status = mq_close(mq); + if (status) + err(1, "mq_close"); + mq_unlink(MQNAME); + return (0); +} diff --git a/tests/sys/mqueue/mqtest5.c b/tests/sys/mqueue/mqtest5.c new file mode 100644 index 0000000..0c8aa89 --- /dev/null +++ b/tests/sys/mqueue/mqtest5.c @@ -0,0 +1,128 @@ +/* $FreeBSD$ */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "freebsd_test_suite/macros.h" + +#define MQNAME "/mytstqueue5" +#define LOOPS 1000 +#define PRIO 10 + +static void +sighandler(int sig __unused) +{ + write(1, "timeout\n", 8); + _exit(1); +} + +int +main(void) +{ + int status; + struct mq_attr attr; + struct sigaction sa; + sigset_t set; + siginfo_t info; + mqd_t mq; + pid_t pid; + + PLAIN_REQUIRE_KERNEL_MODULE("mqueuefs", 0); + + mq_unlink(MQNAME); + + sigemptyset(&set); + sigaddset(&set, SIGRTMIN); + sigprocmask(SIG_BLOCK, &set, NULL); + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = (void *) SIG_DFL; + sigaction(SIGRTMIN, &sa, NULL); + + attr.mq_maxmsg = 5; + attr.mq_msgsize = 128; + mq = mq_open(MQNAME, O_CREAT | O_RDWR | O_EXCL, 0666, &attr); + if (mq == (mqd_t)-1) + err(1, "mq_open()"); + status = mq_getattr(mq, &attr); + if (status) + err(1, "mq_getattr()"); + pid = fork(); + if (pid == 0) { /* child */ + int prio, j, i; + char *buf; + struct sigevent sigev; + + signal(SIGALRM, sighandler); + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_value.sival_int = 2; + + mq_close(mq); + mq = mq_open(MQNAME, O_RDWR | O_NONBLOCK); + if (mq == (mqd_t)-1) + err(1, "child: mq_open"); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + alarm(3); + status = mq_notify(mq, &sigev); + if (status) + err(1, "child: mq_notify"); + status = sigwaitinfo(&set, &info); + if (status == -1) + err(1, "child: sigwaitinfo"); + if (info.si_value.sival_int != 2) + err(1, "child: sival_int"); + status = mq_receive(mq, buf, attr.mq_msgsize, &prio); + if (status == -1) + err(2, "child: mq_receive"); + for (i = 0; i < attr.mq_msgsize; ++i) + if (buf[i] != i) + err(3, "child: message data corrupted"); + if (prio != PRIO) + err(4, "child: priority is incorrect: %d", + prio); + } + alarm(0); + free(buf); + mq_close(mq); + return (0); + } else if (pid == -1) { + err(1, "fork()"); + } else { + char *buf; + int i, j; + + signal(SIGALRM, sighandler); + buf = malloc(attr.mq_msgsize); + for (j = 0; j < LOOPS; ++j) { + for (i = 0; i < attr.mq_msgsize; ++i) { + buf[i] = i; + } + alarm(3); + status = mq_send(mq, buf, attr.mq_msgsize, PRIO); + if (status) { + kill(pid, SIGKILL); + err(2, "mq_send()"); + } + } + alarm(3); + wait(&status); + alarm(0); + } + status = mq_close(mq); + if (status) + err(1, "mq_close"); + mq_unlink(MQNAME); + return (0); +} diff --git a/tests/sys/mqueue/mqueue_test.sh b/tests/sys/mqueue/mqueue_test.sh new file mode 100755 index 0000000..4841418 --- /dev/null +++ b/tests/sys/mqueue/mqueue_test.sh @@ -0,0 +1,81 @@ +# +# Copyright (c) 2015 EMC / Isilon Storage Division +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +mqtest1_head() +{ + : +} +mqtest1_body() +{ + atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest1 +} + +mqtest2_head() +{ + : +} +mqtest2_body() +{ + atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest2 +} + +mqtest3_head() +{ + : +} +mqtest3_body() +{ + atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest3 +} + +mqtest4_head() +{ + : +} +mqtest4_body() +{ + atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest4 +} + +mqtest5_head() +{ + : +} +mqtest5_body() +{ + atf_check -s exit:0 -x $(atf_get_srcdir)/mqtest5 +} + +atf_init_test_cases() +{ + atf_add_test_case mqtest1 + atf_add_test_case mqtest2 + atf_add_test_case mqtest3 + atf_add_test_case mqtest4 + atf_add_test_case mqtest5 +} -- cgit v1.1