summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/freebsd_test_suite/macros.h53
-rw-r--r--tests/sys/Makefile2
-rw-r--r--tests/sys/aio/Makefile16
-rw-r--r--tests/sys/aio/aio_kqueue_test.c211
-rw-r--r--tests/sys/aio/aio_test.c658
-rw-r--r--tests/sys/aio/lio_kqueue_test.c249
-rw-r--r--tests/sys/mqueue/Makefile22
-rw-r--r--tests/sys/mqueue/mqtest1.c57
-rw-r--r--tests/sys/mqueue/mqtest2.c101
-rw-r--r--tests/sys/mqueue/mqtest3.c116
-rw-r--r--tests/sys/mqueue/mqtest4.c120
-rw-r--r--tests/sys/mqueue/mqtest5.c128
-rwxr-xr-xtests/sys/mqueue/mqueue_test.sh81
13 files changed, 1814 insertions, 0 deletions
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 <sys/param.h>
+#include <sys/module.h>
+#include <string.h>
+#include <err.h>
+#include <errno.h>
+
+#include <atf-c.h>
+
+#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 <bsd.test.mk>
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/<arch>/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/<something safe>)
+ */
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <aio.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <sys/param.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/mdioctl.h>
+
+#include <aio.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#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/<something safe>)
+ * 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 <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <aio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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 <bsd.test.mk>
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 <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+
+#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 <sys/types.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 <sys/types.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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 <sys/types.h>
+#include <sys/event.h>
+#include <sys/select.h>
+#include <sys/wait.h>
+#include <err.h>
+#include <fcntl.h>
+#include <mqueue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#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
+}
OpenPOWER on IntegriCloud