Re: [PATCH -next] selftests/ipc: Consolidate posix and sysv msg queue tests

Shuah Khan
2015-06-09T12:56:19Z

On 06/08/2015 05:51 PM, Davidlohr Bueso wrote:
> Move them both in the their own directory, under selftests/ipc/.
> As with the actual code, all forms of ipc tend to reside in the
> same directory, so apply this to selftests.
>
> Keep the Makefiles (at least for now), with some minor path
> hierarchy tweaks, for both msg and mqueue. Add a trivial
> ipc/Makefile that simply passes the building to the individual
> subdirectory.
>
> Signed-off-by: Davidlohr Bueso <dbueso@suse.de>

Looks good in general. Please see comments below.

> ---
> tools/testing/selftests/ipc/.gitignore | 3 +
> tools/testing/selftests/ipc/Makefile | 32 +-
> tools/testing/selftests/ipc/mqueue/Makefile | 22 +
> tools/testing/selftests/ipc/mqueue/mq_open_tests.c | 500 ++++++++++++++
> tools/testing/selftests/ipc/mqueue/mq_perf_tests.c | 742 +++++++++++++++++++++
> tools/testing/selftests/ipc/msg/Makefile | 22 +
> tools/testing/selftests/ipc/msg/msgque.c | 254 +++++++
> tools/testing/selftests/ipc/msgque.c | 254 -------
> tools/testing/selftests/mqueue/.gitignore | 2 -
> tools/testing/selftests/mqueue/Makefile | 22 -
> tools/testing/selftests/mqueue/mq_open_tests.c | 500 --------------
> tools/testing/selftests/mqueue/mq_perf_tests.c | 742 ---------------------
> 12 files changed, 1559 insertions(+), 1536 deletions(-)
> create mode 100644 tools/testing/selftests/ipc/.gitignore
> create mode 100644 tools/testing/selftests/ipc/mqueue/Makefile
> create mode 100644 tools/testing/selftests/ipc/mqueue/mq_open_tests.c
> create mode 100644 tools/testing/selftests/ipc/mqueue/mq_perf_tests.c
> create mode 100644 tools/testing/selftests/ipc/msg/Makefile
> create mode 100644 tools/testing/selftests/ipc/msg/msgque.c
> delete mode 100644 tools/testing/selftests/ipc/msgque.c
> delete mode 100644 tools/testing/selftests/mqueue/.gitignore
> delete mode 100644 tools/testing/selftests/mqueue/Makefile
> delete mode 100644 tools/testing/selftests/mqueue/mq_open_tests.c
> delete mode 100644 tools/testing/selftests/mqueue/mq_perf_tests.c
>
> diff --git a/tools/testing/selftests/ipc/.gitignore b/tools/testing/selftests/ipc/.gitignore
> new file mode 100644
> index 0000000..3d8a449
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/.gitignore
> @@ -0,0 +1,3 @@
> +mqueue/mq_open_tests
> +mqueue/mq_perf_tests
> +msg/msgque_test
> diff --git a/tools/testing/selftests/ipc/Makefile b/tools/testing/selftests/ipc/Makefile
> index 25d2e70..8686551 100644
> --- a/tools/testing/selftests/ipc/Makefile
> +++ b/tools/testing/selftests/ipc/Makefile
> @@ -1,22 +1,22 @@
> -uname_M := $(shell uname -m 2>/dev/null || echo not)
> -ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
> -ifeq ($(ARCH),i386)
> - ARCH := x86
> - CFLAGS := -DCONFIG_X86_32 -D__i386__
> -endif
> -ifeq ($(ARCH),x86_64)
> - ARCH := x86
> - CFLAGS := -DCONFIG_X86_64 -D__x86_64__
> -endif
> -
> -CFLAGS += -I../../../../usr/include/

Hmm. This looks like more than a moving code and cleanup change.
The above is removing special handling for x86 and x86_64.

I would like to see this as a separate patch and not combined
with the moving code.

> +SUBDIRS := msg
> +SUBDIRS += mqueue
>
> +.PHONY: all clean
> all:
> - $(CC) $(CFLAGS) msgque.c -o msgque_test
> -
> -TEST_PROGS := msgque_test
> + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
>
> include ../lib.mk
> +override define RUN_TESTS
> + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
> +endef
> +
> +override define INSTALL_RULE
> + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
> +endef
> +
> +override define EMIT_TESTS
> + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
> +endef
>
> clean:
> - rm -fr ./msgque_test
> + for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
> diff --git a/tools/testing/selftests/ipc/mqueue/Makefile b/tools/testing/selftests/ipc/mqueue/Makefile
> new file mode 100644
> index 0000000..1fa56ea
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/mqueue/Makefile
> @@ -0,0 +1,22 @@
> +CFLAGS = -O2
> +
> +all:
> + $(CC) $(CFLAGS) mq_open_tests.c -o mq_open_tests -lrt
> + $(CC) $(CFLAGS) -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt
> +
> +include ../../lib.mk
> +
> +override define RUN_TESTS
> + @./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]"
> + @./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]"
> +endef
> +
> +TEST_PROGS := mq_open_tests mq_perf_tests
> +
> +override define EMIT_TESTS
> + echo "./mq_open_tests /test1 || echo \"selftests: mq_open_tests [FAIL]\""
> + echo "./mq_perf_tests || echo \"selftests: mq_perf_tests [FAIL]\""
> +endef
> +
> +clean:
> + rm -f mq_open_tests mq_perf_tests
> diff --git a/tools/testing/selftests/ipc/mqueue/mq_open_tests.c b/tools/testing/selftests/ipc/mqueue/mq_open_tests.c
> new file mode 100644
> index 0000000..9c1a5d35
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/mqueue/mq_open_tests.c
> @@ -0,0 +1,500 @@
> +/*
> + * This application is Copyright 2012 Red Hat, Inc.
> + * Doug Ledford <dledford@redhat.com>
> + *
> + * mq_open_tests is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, version 3.
> + *
> + * mq_open_tests is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * For the full text of the license, see <http://www.gnu.org/licenses/>.
> + *
> + * mq_open_tests.c
> + * Tests the various situations that should either succeed or fail to
> + * open a posix message queue and then reports whether or not they
> + * did as they were supposed to.
> + *
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <errno.h>
> +#include <sys/types.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +#include <sys/stat.h>
> +#include <mqueue.h>
> +
> +static char *usage =
> +"Usage:\n"
> +" %s path\n"
> +"\n"
> +" path Path name of the message queue to create\n"
> +"\n"
> +" Note: this program must be run as root in order to enable all tests\n"
> +"\n";
> +
> +char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
> +char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
> +char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
> +char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
> +
> +int default_settings;
> +struct rlimit saved_limits, cur_limits;
> +int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
> +int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
> +FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
> +char *queue_path;
> +mqd_t queue = -1;
> +
> +static inline void __set(FILE *stream, int value, char *err_msg);
> +void shutdown(int exit_val, char *err_cause, int line_no);
> +static inline int get(FILE *stream);
> +static inline void set(FILE *stream, int value);
> +static inline void getr(int type, struct rlimit *rlim);
> +static inline void setr(int type, struct rlimit *rlim);
> +void validate_current_settings();
> +static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
> +static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
> +
> +static inline void __set(FILE *stream, int value, char *err_msg)
> +{
> + rewind(stream);
> + if (fprintf(stream, "%d", value) < 0)
> + perror(err_msg);
> +}
> +
> +
> +void shutdown(int exit_val, char *err_cause, int line_no)
> +{
> + static int in_shutdown = 0;
> +
> + /* In case we get called recursively by a set() call below */
> + if (in_shutdown++)
> + return;
> +
> + if (seteuid(0) == -1)
> + perror("seteuid() failed");
> +
> + if (queue != -1)
> + if (mq_close(queue))
> + perror("mq_close() during shutdown");
> + if (queue_path)
> + /*
> + * Be silent if this fails, if we cleaned up already it's
> + * expected to fail
> + */
> + mq_unlink(queue_path);
> + if (default_settings) {
> + if (saved_def_msgs)
> + __set(def_msgs, saved_def_msgs,
> + "failed to restore saved_def_msgs");
> + if (saved_def_msgsize)
> + __set(def_msgsize, saved_def_msgsize,
> + "failed to restore saved_def_msgsize");
> + }
> + if (saved_max_msgs)
> + __set(max_msgs, saved_max_msgs,
> + "failed to restore saved_max_msgs");
> + if (saved_max_msgsize)
> + __set(max_msgsize, saved_max_msgsize,
> + "failed to restore saved_max_msgsize");
> + if (exit_val)
> + error(exit_val, errno, "%s at %d", err_cause, line_no);
> + exit(0);
> +}
> +
> +static inline int get(FILE *stream)
> +{
> + int value;
> + rewind(stream);
> + if (fscanf(stream, "%d", &value) != 1)
> + shutdown(4, "Error reading /proc entry", __LINE__ - 1);
> + return value;
> +}
> +
> +static inline void set(FILE *stream, int value)
> +{
> + int new_value;
> +
> + rewind(stream);
> + if (fprintf(stream, "%d", value) < 0)
> + return shutdown(5, "Failed writing to /proc file",
> + __LINE__ - 1);
> + new_value = get(stream);
> + if (new_value != value)
> + return shutdown(5, "We didn't get what we wrote to /proc back",
> + __LINE__ - 1);
> +}
> +
> +static inline void getr(int type, struct rlimit *rlim)
> +{
> + if (getrlimit(type, rlim))
> + shutdown(6, "getrlimit()", __LINE__ - 1);
> +}
> +
> +static inline void setr(int type, struct rlimit *rlim)
> +{
> + if (setrlimit(type, rlim))
> + shutdown(7, "setrlimit()", __LINE__ - 1);
> +}
> +
> +void validate_current_settings()
> +{
> + int rlim_needed;
> +
> + if (cur_limits.rlim_cur < 4096) {
> + printf("Current rlimit value for POSIX message queue bytes is "
> + "unreasonably low,\nincreasing.\n\n");
> + cur_limits.rlim_cur = 8192;
> + cur_limits.rlim_max = 16384;
> + setr(RLIMIT_MSGQUEUE, &cur_limits);
> + }
> +
> + if (default_settings) {
> + rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
> + 2 * sizeof(void *));
> + if (rlim_needed > cur_limits.rlim_cur) {
> + printf("Temporarily lowering default queue parameters "
> + "to something that will work\n"
> + "with the current rlimit values.\n\n");
> + set(def_msgs, 10);
> + cur_def_msgs = 10;
> + set(def_msgsize, 128);
> + cur_def_msgsize = 128;
> + }
> + } else {
> + rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
> + 2 * sizeof(void *));
> + if (rlim_needed > cur_limits.rlim_cur) {
> + printf("Temporarily lowering maximum queue parameters "
> + "to something that will work\n"
> + "with the current rlimit values in case this is "
> + "a kernel that ties the default\n"
> + "queue parameters to the maximum queue "
> + "parameters.\n\n");
> + set(max_msgs, 10);
> + cur_max_msgs = 10;
> + set(max_msgsize, 128);
> + cur_max_msgsize = 128;
> + }
> + }
> +}
> +
> +/*
> + * test_queue - Test opening a queue, shutdown if we fail. This should
> + * only be called in situations that should never fail. We clean up
> + * after ourselves and return the queue attributes in *result.
> + */
> +static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
> +{
> + int flags = O_RDWR | O_EXCL | O_CREAT;
> + int perms = DEFFILEMODE;
> +
> + if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
> + shutdown(1, "mq_open()", __LINE__);
> + if (mq_getattr(queue, result))
> + shutdown(1, "mq_getattr()", __LINE__);
> + if (mq_close(queue))
> + shutdown(1, "mq_close()", __LINE__);
> + queue = -1;
> + if (mq_unlink(queue_path))
> + shutdown(1, "mq_unlink()", __LINE__);
> +}
> +
> +/*
> + * Same as test_queue above, but failure is not fatal.
> + * Returns:
> + * 0 - Failed to create a queue
> + * 1 - Created a queue, attributes in *result
> + */
> +static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
> +{
> + int flags = O_RDWR | O_EXCL | O_CREAT;
> + int perms = DEFFILEMODE;
> +
> + if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
> + return 0;
> + if (mq_getattr(queue, result))
> + shutdown(1, "mq_getattr()", __LINE__);
> + if (mq_close(queue))
> + shutdown(1, "mq_close()", __LINE__);
> + queue = -1;
> + if (mq_unlink(queue_path))
> + shutdown(1, "mq_unlink()", __LINE__);
> + return 1;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + struct mq_attr attr, result;
> +
> + if (argc != 2) {
> + fprintf(stderr, "Must pass a valid queue name\n\n");
> + fprintf(stderr, usage, argv[0]);
> + exit(1);
> + }
> +
> + /*
> + * Although we can create a msg queue with a non-absolute path name,
> + * unlink will fail. So, if the name doesn't start with a /, add one
> + * when we save it.
> + */
> + if (*argv[1] == '/')
> + queue_path = strdup(argv[1]);
> + else {
> + queue_path = malloc(strlen(argv[1]) + 2);
> + if (!queue_path) {
> + perror("malloc()");
> + exit(1);
> + }
> + queue_path[0] = '/';
> + queue_path[1] = 0;
> + strcat(queue_path, argv[1]);
> + }
> +
> + if (getuid() != 0) {
> + fprintf(stderr, "Not running as root, but almost all tests "
> + "require root in order to modify\nsystem settings. "
> + "Exiting.\n");
> + exit(1);
> + }
> +
> + /* Find out what files there are for us to make tweaks in */
> + def_msgs = fopen(DEF_MSGS, "r+");
> + def_msgsize = fopen(DEF_MSGSIZE, "r+");
> + max_msgs = fopen(MAX_MSGS, "r+");
> + max_msgsize = fopen(MAX_MSGSIZE, "r+");
> +
> + if (!max_msgs)
> + shutdown(2, "Failed to open msg_max", __LINE__);
> + if (!max_msgsize)
> + shutdown(2, "Failed to open msgsize_max", __LINE__);
> + if (def_msgs || def_msgsize)
> + default_settings = 1;
> +
> + /* Load up the current system values for everything we can */
> + getr(RLIMIT_MSGQUEUE, &saved_limits);
> + cur_limits = saved_limits;
> + if (default_settings) {
> + saved_def_msgs = cur_def_msgs = get(def_msgs);
> + saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
> + }
> + saved_max_msgs = cur_max_msgs = get(max_msgs);
> + saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
> +
> + /* Tell the user our initial state */
> + printf("\nInitial system state:\n");
> + printf("\tUsing queue path:\t\t%s\n", queue_path);
> + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
> + (long) saved_limits.rlim_cur);
> + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
> + (long) saved_limits.rlim_max);
> + printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
> + printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
> + if (default_settings) {
> + printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
> + printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
> + } else {
> + printf("\tDefault Message Size:\t\tNot Supported\n");
> + printf("\tDefault Queue Size:\t\tNot Supported\n");
> + }
> + printf("\n");
> +
> + validate_current_settings();
> +
> + printf("Adjusted system state for testing:\n");
> + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
> + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
> + printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
> + printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
> + if (default_settings) {
> + printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
> + printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
> + }
> +
> + printf("\n\nTest series 1, behavior when no attr struct "
> + "passed to mq_open:\n");
> + if (!default_settings) {
> + test_queue(NULL, &result);
> + printf("Given sane system settings, mq_open without an attr "
> + "struct succeeds:\tPASS\n");
> + if (result.mq_maxmsg != cur_max_msgs ||
> + result.mq_msgsize != cur_max_msgsize) {
> + printf("Kernel does not support setting the default "
> + "mq attributes,\nbut also doesn't tie the "
> + "defaults to the maximums:\t\t\tPASS\n");
> + } else {
> + set(max_msgs, ++cur_max_msgs);
> + set(max_msgsize, ++cur_max_msgsize);
> + test_queue(NULL, &result);
> + if (result.mq_maxmsg == cur_max_msgs &&
> + result.mq_msgsize == cur_max_msgsize)
> + printf("Kernel does not support setting the "
> + "default mq attributes and\n"
> + "also ties system wide defaults to "
> + "the system wide maximums:\t\t"
> + "FAIL\n");
> + else
> + printf("Kernel does not support setting the "
> + "default mq attributes,\n"
> + "but also doesn't tie the defaults to "
> + "the maximums:\t\t\tPASS\n");
> + }
> + } else {
> + printf("Kernel supports setting defaults separately from "
> + "maximums:\t\tPASS\n");
> + /*
> + * While we are here, go ahead and test that the kernel
> + * properly follows the default settings
> + */
> + test_queue(NULL, &result);
> + printf("Given sane values, mq_open without an attr struct "
> + "succeeds:\t\tPASS\n");
> + if (result.mq_maxmsg != cur_def_msgs ||
> + result.mq_msgsize != cur_def_msgsize)
> + printf("Kernel supports setting defaults, but does "
> + "not actually honor them:\tFAIL\n\n");
> + else {
> + set(def_msgs, ++cur_def_msgs);
> + set(def_msgsize, ++cur_def_msgsize);
> + /* In case max was the same as the default */
> + set(max_msgs, ++cur_max_msgs);
> + set(max_msgsize, ++cur_max_msgsize);
> + test_queue(NULL, &result);
> + if (result.mq_maxmsg != cur_def_msgs ||
> + result.mq_msgsize != cur_def_msgsize)
> + printf("Kernel supports setting defaults, but "
> + "does not actually honor them:\t"
> + "FAIL\n");
> + else
> + printf("Kernel properly honors default setting "
> + "knobs:\t\t\t\tPASS\n");
> + }
> + set(def_msgs, cur_max_msgs + 1);
> + cur_def_msgs = cur_max_msgs + 1;
> + set(def_msgsize, cur_max_msgsize + 1);
> + cur_def_msgsize = cur_max_msgsize + 1;
> + if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
> + cur_limits.rlim_cur) {
> + cur_limits.rlim_cur = (cur_def_msgs + 2) *
> + (cur_def_msgsize + 2 * sizeof(void *));
> + cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
> + setr(RLIMIT_MSGQUEUE, &cur_limits);
> + }
> + if (test_queue_fail(NULL, &result)) {
> + if (result.mq_maxmsg == cur_max_msgs &&
> + result.mq_msgsize == cur_max_msgsize)
> + printf("Kernel properly limits default values "
> + "to lesser of default/max:\t\tPASS\n");
> + else
> + printf("Kernel does not properly set default "
> + "queue parameters when\ndefaults > "
> + "max:\t\t\t\t\t\t\t\tFAIL\n");
> + } else
> + printf("Kernel fails to open mq because defaults are "
> + "greater than maximums:\tFAIL\n");
> + set(def_msgs, --cur_def_msgs);
> + set(def_msgsize, --cur_def_msgsize);
> + cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
> + cur_def_msgsize;
> + setr(RLIMIT_MSGQUEUE, &cur_limits);
> + if (test_queue_fail(NULL, &result))
> + printf("Kernel creates queue even though defaults "
> + "would exceed\nrlimit setting:"
> + "\t\t\t\t\t\t\t\tFAIL\n");
> + else
> + printf("Kernel properly fails to create queue when "
> + "defaults would\nexceed rlimit:"
> + "\t\t\t\t\t\t\t\tPASS\n");
> + }
> +
> + /*
> + * Test #2 - open with an attr struct that exceeds rlimit
> + */
> + printf("\n\nTest series 2, behavior when attr struct is "
> + "passed to mq_open:\n");
> + cur_max_msgs = 32;
> + cur_max_msgsize = cur_limits.rlim_max >> 4;
> + set(max_msgs, cur_max_msgs);
> + set(max_msgsize, cur_max_msgsize);
> + attr.mq_maxmsg = cur_max_msgs;
> + attr.mq_msgsize = cur_max_msgsize;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open in excess of rlimit max when euid = 0 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open in excess of rlimit max when euid = 0 "
> + "failed:\t\tPASS\n");
> + attr.mq_maxmsg = cur_max_msgs + 1;
> + attr.mq_msgsize = 10;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with mq_maxmsg > limit when euid = 0 "
> + "succeeded:\t\tPASS\n");
> + else
> + printf("Queue open with mq_maxmsg > limit when euid = 0 "
> + "failed:\t\tFAIL\n");
> + attr.mq_maxmsg = 1;
> + attr.mq_msgsize = cur_max_msgsize + 1;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with mq_msgsize > limit when euid = 0 "
> + "succeeded:\t\tPASS\n");
> + else
> + printf("Queue open with mq_msgsize > limit when euid = 0 "
> + "failed:\t\tFAIL\n");
> + attr.mq_maxmsg = 65536;
> + attr.mq_msgsize = 65536;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with total size > 2GB when euid = 0 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open with total size > 2GB when euid = 0 "
> + "failed:\t\t\tPASS\n");
> +
> + if (seteuid(99) == -1) {
> + perror("seteuid() failed");
> + exit(1);
> + }
> +
> + attr.mq_maxmsg = cur_max_msgs;
> + attr.mq_msgsize = cur_max_msgsize;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open in excess of rlimit max when euid = 99 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open in excess of rlimit max when euid = 99 "
> + "failed:\t\tPASS\n");
> + attr.mq_maxmsg = cur_max_msgs + 1;
> + attr.mq_msgsize = 10;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with mq_maxmsg > limit when euid = 99 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open with mq_maxmsg > limit when euid = 99 "
> + "failed:\t\tPASS\n");
> + attr.mq_maxmsg = 1;
> + attr.mq_msgsize = cur_max_msgsize + 1;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with mq_msgsize > limit when euid = 99 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open with mq_msgsize > limit when euid = 99 "
> + "failed:\t\tPASS\n");
> + attr.mq_maxmsg = 65536;
> + attr.mq_msgsize = 65536;
> + if (test_queue_fail(&attr, &result))
> + printf("Queue open with total size > 2GB when euid = 99 "
> + "succeeded:\t\tFAIL\n");
> + else
> + printf("Queue open with total size > 2GB when euid = 99 "
> + "failed:\t\t\tPASS\n");
> +
> + shutdown(0,"",0);
> +}
> diff --git a/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c b/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c
> new file mode 100644
> index 0000000..8519e9e
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/mqueue/mq_perf_tests.c
> @@ -0,0 +1,742 @@
> +/*
> + * This application is Copyright 2012 Red Hat, Inc.
> + * Doug Ledford <dledford@redhat.com>
> + *
> + * mq_perf_tests is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, version 3.
> + *
> + * mq_perf_tests is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * For the full text of the license, see <http://www.gnu.org/licenses/>.
> + *
> + * mq_perf_tests.c
> + * Tests various types of message queue workloads, concentrating on those
> + * situations that invole large message sizes, large message queue depths,
> + * or both, and reports back useful metrics about kernel message queue
> + * performance.
> + *
> + */
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <string.h>
> +#include <limits.h>
> +#include <errno.h>
> +#include <signal.h>
> +#include <pthread.h>
> +#include <sched.h>
> +#include <sys/types.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +#include <sys/stat.h>
> +#include <mqueue.h>
> +#include <popt.h>
> +
> +static char *usage =
> +"Usage:\n"
> +" %s [-c #[,#..] -f] path\n"
> +"\n"
> +" -c # Skip most tests and go straight to a high queue depth test\n"
> +" and then run that test continuously (useful for running at\n"
> +" the same time as some other workload to see how much the\n"
> +" cache thrashing caused by adding messages to a very deep\n"
> +" queue impacts the performance of other programs). The number\n"
> +" indicates which CPU core we should bind the process to during\n"
> +" the run. If you have more than one physical CPU, then you\n"
> +" will need one copy per physical CPU package, and you should\n"
> +" specify the CPU cores to pin ourself to via a comma separated\n"
> +" list of CPU values.\n"
> +" -f Only usable with continuous mode. Pin ourself to the CPUs\n"
> +" as requested, then instead of looping doing a high mq\n"
> +" workload, just busy loop. This will allow us to lock up a\n"
> +" single CPU just like we normally would, but without actually\n"
> +" thrashing the CPU cache. This is to make it easier to get\n"
> +" comparable numbers from some other workload running on the\n"
> +" other CPUs. One set of numbers with # CPUs locked up running\n"
> +" an mq workload, and another set of numbers with those same\n"
> +" CPUs locked away from the test workload, but not doing\n"
> +" anything to trash the cache like the mq workload might.\n"
> +" path Path name of the message queue to create\n"
> +"\n"
> +" Note: this program must be run as root in order to enable all tests\n"
> +"\n";
> +
> +char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
> +char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
> +
> +#define min(a, b) ((a) < (b) ? (a) : (b))
> +#define MAX_CPUS 64
> +char *cpu_option_string;
> +int cpus_to_pin[MAX_CPUS];
> +int num_cpus_to_pin;
> +pthread_t cpu_threads[MAX_CPUS];
> +pthread_t main_thread;
> +cpu_set_t *cpu_set;
> +int cpu_set_size;
> +int cpus_online;
> +
> +#define MSG_SIZE 16
> +#define TEST1_LOOPS 10000000
> +#define TEST2_LOOPS 100000
> +int continuous_mode;
> +int continuous_mode_fake;
> +
> +struct rlimit saved_limits, cur_limits;
> +int saved_max_msgs, saved_max_msgsize;
> +int cur_max_msgs, cur_max_msgsize;
> +FILE *max_msgs, *max_msgsize;
> +int cur_nice;
> +char *queue_path = "/mq_perf_tests";
> +mqd_t queue = -1;
> +struct mq_attr result;
> +int mq_prio_max;
> +
> +const struct poptOption options[] = {
> + {
> + .longName = "continuous",
> + .shortName = 'c',
> + .argInfo = POPT_ARG_STRING,
> + .arg = &cpu_option_string,
> + .val = 'c',
> + .descrip = "Run continuous tests at a high queue depth in "
> + "order to test the effects of cache thrashing on "
> + "other tasks on the system. This test is intended "
> + "to be run on one core of each physical CPU while "
> + "some other CPU intensive task is run on all the other "
> + "cores of that same physical CPU and the other task "
> + "is timed. It is assumed that the process of adding "
> + "messages to the message queue in a tight loop will "
> + "impact that other task to some degree. Once the "
> + "tests are performed in this way, you should then "
> + "re-run the tests using fake mode in order to check "
> + "the difference in time required to perform the CPU "
> + "intensive task",
> + .argDescrip = "cpu[,cpu]",
> + },
> + {
> + .longName = "fake",
> + .shortName = 'f',
> + .argInfo = POPT_ARG_NONE,
> + .arg = &continuous_mode_fake,
> + .val = 0,
> + .descrip = "Tie up the CPUs that we would normally tie up in"
> + "continuous mode, but don't actually do any mq stuff, "
> + "just keep the CPU busy so it can't be used to process "
> + "system level tasks as this would free up resources on "
> + "the other CPU cores and skew the comparison between "
> + "the no-mqueue work and mqueue work tests",
> + .argDescrip = NULL,
> + },
> + {
> + .longName = "path",
> + .shortName = 'p',
> + .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
> + .arg = &queue_path,
> + .val = 'p',
> + .descrip = "The name of the path to use in the mqueue "
> + "filesystem for our tests",
> + .argDescrip = "pathname",
> + },
> + POPT_AUTOHELP
> + POPT_TABLEEND
> +};
> +
> +static inline void __set(FILE *stream, int value, char *err_msg);
> +void shutdown(int exit_val, char *err_cause, int line_no);
> +void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
> +void sig_action(int signum, siginfo_t *info, void *context);
> +static inline int get(FILE *stream);
> +static inline void set(FILE *stream, int value);
> +static inline int try_set(FILE *stream, int value);
> +static inline void getr(int type, struct rlimit *rlim);
> +static inline void setr(int type, struct rlimit *rlim);
> +static inline void open_queue(struct mq_attr *attr);
> +void increase_limits(void);
> +
> +static inline void __set(FILE *stream, int value, char *err_msg)
> +{
> + rewind(stream);
> + if (fprintf(stream, "%d", value) < 0)
> + perror(err_msg);
> +}
> +
> +
> +void shutdown(int exit_val, char *err_cause, int line_no)
> +{
> + static int in_shutdown = 0;
> + int errno_at_shutdown = errno;
> + int i;
> +
> + /* In case we get called by multiple threads or from an sighandler */
> + if (in_shutdown++)
> + return;
> +
> + for (i = 0; i < num_cpus_to_pin; i++)
> + if (cpu_threads[i]) {
> + pthread_kill(cpu_threads[i], SIGUSR1);
> + pthread_join(cpu_threads[i], NULL);
> + }
> +
> + if (queue != -1)
> + if (mq_close(queue))
> + perror("mq_close() during shutdown");
> + if (queue_path)
> + /*
> + * Be silent if this fails, if we cleaned up already it's
> + * expected to fail
> + */
> + mq_unlink(queue_path);
> + if (saved_max_msgs)
> + __set(max_msgs, saved_max_msgs,
> + "failed to restore saved_max_msgs");
> + if (saved_max_msgsize)
> + __set(max_msgsize, saved_max_msgsize,
> + "failed to restore saved_max_msgsize");
> + if (exit_val)
> + error(exit_val, errno_at_shutdown, "%s at %d",
> + err_cause, line_no);
> + exit(0);
> +}
> +
> +void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
> +{
> + if (pthread_self() != main_thread)
> + pthread_exit(0);
> + else {
> + fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
> + "exiting\n", signum);
> + shutdown(0, "", 0);
> + fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
> + exit(0);
> + }
> +}
> +
> +void sig_action(int signum, siginfo_t *info, void *context)
> +{
> + if (pthread_self() != main_thread)
> + pthread_kill(main_thread, signum);
> + else {
> + fprintf(stderr, "Caught signal %d, exiting\n", signum);
> + shutdown(0, "", 0);
> + fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
> + exit(0);
> + }
> +}
> +
> +static inline int get(FILE *stream)
> +{
> + int value;
> + rewind(stream);
> + if (fscanf(stream, "%d", &value) != 1)
> + shutdown(4, "Error reading /proc entry", __LINE__);
> + return value;
> +}
> +
> +static inline void set(FILE *stream, int value)
> +{
> + int new_value;
> +
> + rewind(stream);
> + if (fprintf(stream, "%d", value) < 0)
> + return shutdown(5, "Failed writing to /proc file", __LINE__);
> + new_value = get(stream);
> + if (new_value != value)
> + return shutdown(5, "We didn't get what we wrote to /proc back",
> + __LINE__);
> +}
> +
> +static inline int try_set(FILE *stream, int value)
> +{
> + int new_value;
> +
> + rewind(stream);
> + fprintf(stream, "%d", value);
> + new_value = get(stream);
> + return new_value == value;
> +}
> +
> +static inline void getr(int type, struct rlimit *rlim)
> +{
> + if (getrlimit(type, rlim))
> + shutdown(6, "getrlimit()", __LINE__);
> +}
> +
> +static inline void setr(int type, struct rlimit *rlim)
> +{
> + if (setrlimit(type, rlim))
> + shutdown(7, "setrlimit()", __LINE__);
> +}
> +
> +/**
> + * open_queue - open the global queue for testing
> + * @attr - An attr struct specifying the desired queue traits
> + * @result - An attr struct that lists the actual traits the queue has
> + *
> + * This open is not allowed to fail, failure will result in an orderly
> + * shutdown of the program. The global queue_path is used to set what
> + * queue to open, the queue descriptor is saved in the global queue
> + * variable.
> + */
> +static inline void open_queue(struct mq_attr *attr)
> +{
> + int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
> + int perms = DEFFILEMODE;
> +
> + queue = mq_open(queue_path, flags, perms, attr);
> + if (queue == -1)
> + shutdown(1, "mq_open()", __LINE__);
> + if (mq_getattr(queue, &result))
> + shutdown(1, "mq_getattr()", __LINE__);
> + printf("\n\tQueue %s created:\n", queue_path);
> + printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
> + "O_NONBLOCK" : "(null)");
> + printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
> + printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
> + printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
> +}
> +
> +void *fake_cont_thread(void *arg)
> +{
> + int i;
> +
> + for (i = 0; i < num_cpus_to_pin; i++)
> + if (cpu_threads[i] == pthread_self())
> + break;
> + printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
> + cpus_to_pin[i]);
> + while (1)
> + ;
> +}
> +
> +void *cont_thread(void *arg)
> +{
> + char buff[MSG_SIZE];
> + int i, priority;
> +
> + for (i = 0; i < num_cpus_to_pin; i++)
> + if (cpu_threads[i] == pthread_self())
> + break;
> + printf("\tStarted continuous mode thread %d on CPU %d\n", i,
> + cpus_to_pin[i]);
> + while (1) {
> + while (mq_send(queue, buff, sizeof(buff), 0) == 0)
> + ;
> + mq_receive(queue, buff, sizeof(buff), &priority);
> + }
> +}
> +
> +#define drain_queue() \
> + while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
> +
> +#define do_untimed_send() \
> + do { \
> + if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
> + shutdown(3, "Test send failure", __LINE__); \
> + } while (0)
> +
> +#define do_send_recv() \
> + do { \
> + clock_gettime(clock, &start); \
> + if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
> + shutdown(3, "Test send failure", __LINE__); \
> + clock_gettime(clock, &middle); \
> + if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
> + shutdown(3, "Test receive failure", __LINE__); \
> + clock_gettime(clock, &end); \
> + nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
> + (middle.tv_nsec - start.tv_nsec); \
> + send_total.tv_nsec += nsec; \
> + if (send_total.tv_nsec >= 1000000000) { \
> + send_total.tv_sec++; \
> + send_total.tv_nsec -= 1000000000; \
> + } \
> + nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
> + (end.tv_nsec - middle.tv_nsec); \
> + recv_total.tv_nsec += nsec; \
> + if (recv_total.tv_nsec >= 1000000000) { \
> + recv_total.tv_sec++; \
> + recv_total.tv_nsec -= 1000000000; \
> + } \
> + } while (0)
> +
> +struct test {
> + char *desc;
> + void (*func)(int *);
> +};
> +
> +void const_prio(int *prio)
> +{
> + return;
> +}
> +
> +void inc_prio(int *prio)
> +{
> + if (++*prio == mq_prio_max)
> + *prio = 0;
> +}
> +
> +void dec_prio(int *prio)
> +{
> + if (--*prio < 0)
> + *prio = mq_prio_max - 1;
> +}
> +
> +void random_prio(int *prio)
> +{
> + *prio = random() % mq_prio_max;
> +}
> +
> +struct test test2[] = {
> + {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
> + const_prio},
> + {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
> + inc_prio},
> + {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
> + dec_prio},
> + {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
> + random_prio},
> + {NULL, NULL}
> +};
> +
> +/**
> + * Tests to perform (all done with MSG_SIZE messages):
> + *
> + * 1) Time to add/remove message with 0 messages on queue
> + * 1a) with constant prio
> + * 2) Time to add/remove message when queue close to capacity:
> + * 2a) with constant prio
> + * 2b) with increasing prio
> + * 2c) with decreasing prio
> + * 2d) with random prio
> + * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
> + */
> +void *perf_test_thread(void *arg)
> +{
> + char buff[MSG_SIZE];
> + int prio_out, prio_in;
> + int i;
> + clockid_t clock;
> + pthread_t *t;
> + struct timespec res, start, middle, end, send_total, recv_total;
> + unsigned long long nsec;
> + struct test *cur_test;
> +
> + t = &cpu_threads[0];
> + printf("\n\tStarted mqueue performance test thread on CPU %d\n",
> + cpus_to_pin[0]);
> + mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
> + if (mq_prio_max == -1)
> + shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
> + if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
> + shutdown(2, "pthread_getcpuclockid", __LINE__);
> +
> + if (clock_getres(clock, &res))
> + shutdown(2, "clock_getres()", __LINE__);
> +
> + printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
> + printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
> + res.tv_nsec > 1 ? "s" : "");
> +
> +
> +
> + printf("\n\tTest #1: Time send/recv message, queue empty\n");
> + printf("\t\t(%d iterations)\n", TEST1_LOOPS);
> + prio_out = 0;
> + send_total.tv_sec = 0;
> + send_total.tv_nsec = 0;
> + recv_total.tv_sec = 0;
> + recv_total.tv_nsec = 0;
> + for (i = 0; i < TEST1_LOOPS; i++)
> + do_send_recv();
> + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
> + send_total.tv_sec, send_total.tv_nsec);
> + nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
> + send_total.tv_nsec) / TEST1_LOOPS;
> + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
> + recv_total.tv_sec, recv_total.tv_nsec);
> + nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
> + recv_total.tv_nsec) / TEST1_LOOPS;
> + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> +
> +
> + for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
> + printf("%s:\n", cur_test->desc);
> + printf("\t\t(%d iterations)\n", TEST2_LOOPS);
> + prio_out = 0;
> + send_total.tv_sec = 0;
> + send_total.tv_nsec = 0;
> + recv_total.tv_sec = 0;
> + recv_total.tv_nsec = 0;
> + printf("\t\tFilling queue...");
> + fflush(stdout);
> + clock_gettime(clock, &start);
> + for (i = 0; i < result.mq_maxmsg - 1; i++) {
> + do_untimed_send();
> + cur_test->func(&prio_out);
> + }
> + clock_gettime(clock, &end);
> + nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
> + 1000000000) + (end.tv_nsec - start.tv_nsec);
> + printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
> + nsec % 1000000000);
> + printf("\t\tTesting...");
> + fflush(stdout);
> + for (i = 0; i < TEST2_LOOPS; i++) {
> + do_send_recv();
> + cur_test->func(&prio_out);
> + }
> + printf("done.\n");
> + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
> + send_total.tv_sec, send_total.tv_nsec);
> + nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
> + send_total.tv_nsec) / TEST2_LOOPS;
> + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
> + recv_total.tv_sec, recv_total.tv_nsec);
> + nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
> + recv_total.tv_nsec) / TEST2_LOOPS;
> + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> + printf("\t\tDraining queue...");
> + fflush(stdout);
> + clock_gettime(clock, &start);
> + drain_queue();
> + clock_gettime(clock, &end);
> + nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
> + 1000000000) + (end.tv_nsec - start.tv_nsec);
> + printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
> + nsec % 1000000000);
> + }
> + return 0;
> +}
> +
> +void increase_limits(void)
> +{
> + cur_limits.rlim_cur = RLIM_INFINITY;
> + cur_limits.rlim_max = RLIM_INFINITY;
> + setr(RLIMIT_MSGQUEUE, &cur_limits);
> + while (try_set(max_msgs, cur_max_msgs += 10))
> + ;
> + cur_max_msgs = get(max_msgs);
> + while (try_set(max_msgsize, cur_max_msgsize += 1024))
> + ;
> + cur_max_msgsize = get(max_msgsize);
> + if (setpriority(PRIO_PROCESS, 0, -20) != 0)
> + shutdown(2, "setpriority()", __LINE__);
> + cur_nice = -20;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> + struct mq_attr attr;
> + char *option, *next_option;
> + int i, cpu, rc;
> + struct sigaction sa;
> + poptContext popt_context;
> + void *retval;
> +
> + main_thread = pthread_self();
> + num_cpus_to_pin = 0;
> +
> + if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
> + perror("sysconf(_SC_NPROCESSORS_ONLN)");
> + exit(1);
> + }
> + cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
> + cpu_set = CPU_ALLOC(cpus_online);
> + if (cpu_set == NULL) {
> + perror("CPU_ALLOC()");
> + exit(1);
> + }
> + cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
> + CPU_ZERO_S(cpu_set_size, cpu_set);
> +
> + popt_context = poptGetContext(NULL, argc, (const char **)argv,
> + options, 0);
> +
> + while ((rc = poptGetNextOpt(popt_context)) > 0) {
> + switch (rc) {
> + case 'c':
> + continuous_mode = 1;
> + option = cpu_option_string;
> + do {
> + next_option = strchr(option, ',');
> + if (next_option)
> + *next_option = '\0';
> + cpu = atoi(option);
> + if (cpu >= cpus_online)
> + fprintf(stderr, "CPU %d exceeds "
> + "cpus online, ignoring.\n",
> + cpu);
> + else
> + cpus_to_pin[num_cpus_to_pin++] = cpu;
> + if (next_option)
> + option = ++next_option;
> + } while (next_option && num_cpus_to_pin < MAX_CPUS);
> + /* Double check that they didn't give us the same CPU
> + * more than once */
> + for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
> + if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
> + cpu_set)) {
> + fprintf(stderr, "Any given CPU may "
> + "only be given once.\n");
> + exit(1);
> + } else
> + CPU_SET_S(cpus_to_pin[cpu],
> + cpu_set_size, cpu_set);
> + }
> + break;
> + case 'p':
> + /*
> + * Although we can create a msg queue with a
> + * non-absolute path name, unlink will fail. So,
> + * if the name doesn't start with a /, add one
> + * when we save it.
> + */
> + option = queue_path;
> + if (*option != '/') {
> + queue_path = malloc(strlen(option) + 2);
> + if (!queue_path) {
> + perror("malloc()");
> + exit(1);
> + }
> + queue_path[0] = '/';
> + queue_path[1] = 0;
> + strcat(queue_path, option);
> + free(option);
> + }
> + break;
> + }
> + }
> +
> + if (continuous_mode && num_cpus_to_pin == 0) {
> + fprintf(stderr, "Must pass at least one CPU to continuous "
> + "mode.\n");
> + poptPrintUsage(popt_context, stderr, 0);
> + exit(1);
> + } else if (!continuous_mode) {
> + num_cpus_to_pin = 1;
> + cpus_to_pin[0] = cpus_online - 1;
> + }
> +
> + if (getuid() != 0) {
> + fprintf(stderr, "Not running as root, but almost all tests "
> + "require root in order to modify\nsystem settings. "
> + "Exiting.\n");
> + exit(1);
> + }
> +
> + max_msgs = fopen(MAX_MSGS, "r+");
> + max_msgsize = fopen(MAX_MSGSIZE, "r+");
> + if (!max_msgs)
> + shutdown(2, "Failed to open msg_max", __LINE__);
> + if (!max_msgsize)
> + shutdown(2, "Failed to open msgsize_max", __LINE__);
> +
> + /* Load up the current system values for everything we can */
> + getr(RLIMIT_MSGQUEUE, &saved_limits);
> + cur_limits = saved_limits;
> + saved_max_msgs = cur_max_msgs = get(max_msgs);
> + saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
> + errno = 0;
> + cur_nice = getpriority(PRIO_PROCESS, 0);
> + if (errno)
> + shutdown(2, "getpriority()", __LINE__);
> +
> + /* Tell the user our initial state */
> + printf("\nInitial system state:\n");
> + printf("\tUsing queue path:\t\t\t%s\n", queue_path);
> + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
> + (long) saved_limits.rlim_cur);
> + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
> + (long) saved_limits.rlim_max);
> + printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
> + printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
> + printf("\tNice value:\t\t\t\t%d\n", cur_nice);
> + printf("\n");
> +
> + increase_limits();
> +
> + printf("Adjusted system state for testing:\n");
> + if (cur_limits.rlim_cur == RLIM_INFINITY) {
> + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
> + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
> + } else {
> + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
> + (long) cur_limits.rlim_cur);
> + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
> + (long) cur_limits.rlim_max);
> + }
> + printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
> + printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
> + printf("\tNice value:\t\t\t\t%d\n", cur_nice);
> + printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
> + (continuous_mode_fake ? "fake mode" : "enabled") :
> + "disabled");
> + printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
> + for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
> + printf(",%d", cpus_to_pin[cpu]);
> + printf("\n");
> +
> + sa.sa_sigaction = sig_action_SIGUSR1;
> + sigemptyset(&sa.sa_mask);
> + sigaddset(&sa.sa_mask, SIGHUP);
> + sigaddset(&sa.sa_mask, SIGINT);
> + sigaddset(&sa.sa_mask, SIGQUIT);
> + sigaddset(&sa.sa_mask, SIGTERM);
> + sa.sa_flags = SA_SIGINFO;
> + if (sigaction(SIGUSR1, &sa, NULL) == -1)
> + shutdown(1, "sigaction(SIGUSR1)", __LINE__);
> + sa.sa_sigaction = sig_action;
> + if (sigaction(SIGHUP, &sa, NULL) == -1)
> + shutdown(1, "sigaction(SIGHUP)", __LINE__);
> + if (sigaction(SIGINT, &sa, NULL) == -1)
> + shutdown(1, "sigaction(SIGINT)", __LINE__);
> + if (sigaction(SIGQUIT, &sa, NULL) == -1)
> + shutdown(1, "sigaction(SIGQUIT)", __LINE__);
> + if (sigaction(SIGTERM, &sa, NULL) == -1)
> + shutdown(1, "sigaction(SIGTERM)", __LINE__);
> +
> + if (!continuous_mode_fake) {
> + attr.mq_flags = O_NONBLOCK;
> + attr.mq_maxmsg = cur_max_msgs;
> + attr.mq_msgsize = MSG_SIZE;
> + open_queue(&attr);
> + }
> + for (i = 0; i < num_cpus_to_pin; i++) {
> + pthread_attr_t thread_attr;
> + void *thread_func;
> +
> + if (continuous_mode_fake)
> + thread_func = &fake_cont_thread;
> + else if (continuous_mode)
> + thread_func = &cont_thread;
> + else
> + thread_func = &perf_test_thread;
> +
> + CPU_ZERO_S(cpu_set_size, cpu_set);
> + CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
> + pthread_attr_init(&thread_attr);
> + pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
> + cpu_set);
> + if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
> + NULL))
> + shutdown(1, "pthread_create()", __LINE__);
> + pthread_attr_destroy(&thread_attr);
> + }
> +
> + if (!continuous_mode) {
> + pthread_join(cpu_threads[0], &retval);
> + shutdown((long)retval, "perf_test_thread()", __LINE__);
> + } else {
> + while (1)
> + sleep(1);
> + }
> + shutdown(0, "", 0);
> +}
> diff --git a/tools/testing/selftests/ipc/msg/Makefile b/tools/testing/selftests/ipc/msg/Makefile
> new file mode 100644
> index 0000000..777ca76
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/msg/Makefile
> @@ -0,0 +1,22 @@
> +uname_M := $(shell uname -m 2>/dev/null || echo not)
> +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/)
> +ifeq ($(ARCH),i386)
> + ARCH := x86
> + CFLAGS := -DCONFIG_X86_32 -D__i386__
> +endif
> +ifeq ($(ARCH),x86_64)
> + ARCH := x86
> + CFLAGS := -DCONFIG_X86_64 -D__x86_64__
> +endif
> +
> +CFLAGS += -I../../../../usr/include/
> +
> +all:
> + $(CC) $(CFLAGS) msgque.c -o msgque_test
> +
> +TEST_PROGS := msgque_test
> +
> +include ../../lib.mk
> +
> +clean:
> + rm -fr ./msgque_test
> diff --git a/tools/testing/selftests/ipc/msg/msgque.c b/tools/testing/selftests/ipc/msg/msgque.c
> new file mode 100644
> index 0000000..69d539d
> --- /dev/null
> +++ b/tools/testing/selftests/ipc/msg/msgque.c
> @@ -0,0 +1,254 @@
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <linux/msg.h>
> +#include <fcntl.h>
> +
> +#include "../../kselftest.h"
> +
> +#define MAX_MSG_SIZE 32
> +
> +struct msg1 {
> + int msize;
> + long mtype;
> + char mtext[MAX_MSG_SIZE];
> +};
> +
> +#define TEST_STRING "Test sysv5 msg"
> +#define MSG_TYPE 1
> +
> +#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
> +#define ANOTHER_MSG_TYPE 26538
> +
> +struct msgque_data {
> + key_t key;
> + int msq_id;
> + int qbytes;
> + int qnum;
> + int mode;
> + struct msg1 *messages;
> +};
> +
> +int restore_queue(struct msgque_data *msgque)
> +{
> + int fd, ret, id, i;
> + char buf[32];
> +
> + fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
> + if (fd == -1) {
> + printf("Failed to open /proc/sys/kernel/msg_next_id\n");
> + return -errno;
> + }
> + sprintf(buf, "%d", msgque->msq_id);
> +
> + ret = write(fd, buf, strlen(buf));
> + if (ret != strlen(buf)) {
> + printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
> + return -errno;
> + }
> +
> + id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
> + if (id == -1) {
> + printf("Failed to create queue\n");
> + return -errno;
> + }
> +
> + if (id != msgque->msq_id) {
> + printf("Restored queue has wrong id (%d instead of %d)\n",
> + id, msgque->msq_id);
> + ret = -EFAULT;
> + goto destroy;
> + }
> +
> + for (i = 0; i < msgque->qnum; i++) {
> + if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
> + msgque->messages[i].msize, IPC_NOWAIT) != 0) {
> + printf("msgsnd failed (%m)\n");
> + ret = -errno;
> + goto destroy;
> + };
> + }
> + return 0;
> +
> +destroy:
> + if (msgctl(id, IPC_RMID, 0))
> + printf("Failed to destroy queue: %d\n", -errno);
> + return ret;
> +}
> +
> +int check_and_destroy_queue(struct msgque_data *msgque)
> +{
> + struct msg1 message;
> + int cnt = 0, ret;
> +
> + while (1) {
> + ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
> + 0, IPC_NOWAIT);
> + if (ret < 0) {
> + if (errno == ENOMSG)
> + break;
> + printf("Failed to read IPC message: %m\n");
> + ret = -errno;
> + goto err;
> + }
> + if (ret != msgque->messages[cnt].msize) {
> + printf("Wrong message size: %d (expected %d)\n", ret,
> + msgque->messages[cnt].msize);
> + ret = -EINVAL;
> + goto err;
> + }
> + if (message.mtype != msgque->messages[cnt].mtype) {
> + printf("Wrong message type\n");
> + ret = -EINVAL;
> + goto err;
> + }
> + if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
> + printf("Wrong message content\n");
> + ret = -EINVAL;
> + goto err;
> + }
> + cnt++;
> + }
> +
> + if (cnt != msgque->qnum) {
> + printf("Wrong message number\n");
> + ret = -EINVAL;
> + goto err;
> + }
> +
> + ret = 0;
> +err:
> + if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
> + printf("Failed to destroy queue: %d\n", -errno);
> + return -errno;
> + }
> + return ret;
> +}
> +
> +int dump_queue(struct msgque_data *msgque)
> +{
> + struct msqid64_ds ds;
> + int kern_id;
> + int i, ret;
> +
> + for (kern_id = 0; kern_id < 256; kern_id++) {
> + ret = msgctl(kern_id, MSG_STAT, &ds);
> + if (ret < 0) {
> + if (errno == -EINVAL)
> + continue;
> + printf("Failed to get stats for IPC queue with id %d\n",
> + kern_id);
> + return -errno;
> + }
> +
> + if (ret == msgque->msq_id)
> + break;
> + }
> +
> + msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
> + if (msgque->messages == NULL) {
> + printf("Failed to get stats for IPC queue\n");
> + return -ENOMEM;
> + }
> +
> + msgque->qnum = ds.msg_qnum;
> + msgque->mode = ds.msg_perm.mode;
> + msgque->qbytes = ds.msg_qbytes;
> +
> + for (i = 0; i < msgque->qnum; i++) {
> + ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
> + MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
> + if (ret < 0) {
> + printf("Failed to copy IPC message: %m (%d)\n", errno);
> + return -errno;
> + }
> + msgque->messages[i].msize = ret;
> + }
> + return 0;
> +}
> +
> +int fill_msgque(struct msgque_data *msgque)
> +{
> + struct msg1 msgbuf;
> +
> + msgbuf.mtype = MSG_TYPE;
> + memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
> + if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
> + IPC_NOWAIT) != 0) {
> + printf("First message send failed (%m)\n");
> + return -errno;
> + };
> +
> + msgbuf.mtype = ANOTHER_MSG_TYPE;
> + memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
> + if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
> + IPC_NOWAIT) != 0) {
> + printf("Second message send failed (%m)\n");
> + return -errno;
> + };
> + return 0;
> +}
> +
> +int main(int argc, char **argv)
> +{
> + int msg, pid, err;
> + struct msgque_data msgque;
> +
> + if (getuid() != 0) {
> + printf("Please run the test as root - Exiting.\n");
> + return ksft_exit_fail();
> + }
> +
> + msgque.key = ftok(argv[0], 822155650);
> + if (msgque.key == -1) {
> + printf("Can't make key: %d\n", -errno);
> + return ksft_exit_fail();
> + }
> +
> + msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
> + if (msgque.msq_id == -1) {
> + err = -errno;
> + printf("Can't create queue: %d\n", err);
> + goto err_out;
> + }
> +
> + err = fill_msgque(&msgque);
> + if (err) {
> + printf("Failed to fill queue: %d\n", err);
> + goto err_destroy;
> + }
> +
> + err = dump_queue(&msgque);
> + if (err) {
> + printf("Failed to dump queue: %d\n", err);
> + goto err_destroy;
> + }
> +
> + err = check_and_destroy_queue(&msgque);
> + if (err) {
> + printf("Failed to check and destroy queue: %d\n", err);
> + goto err_out;
> + }
> +
> + err = restore_queue(&msgque);
> + if (err) {
> + printf("Failed to restore queue: %d\n", err);
> + goto err_destroy;
> + }
> +
> + err = check_and_destroy_queue(&msgque);
> + if (err) {
> + printf("Failed to test queue: %d\n", err);
> + goto err_out;
> + }
> + return ksft_exit_pass();
> +
> +err_destroy:
> + if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
> + printf("Failed to destroy queue: %d\n", -errno);
> + return ksft_exit_fail();
> + }
> +err_out:
> + return ksft_exit_fail();
> +}
> diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c
> deleted file mode 100644
> index 1b2ce33..0000000
> --- a/tools/testing/selftests/ipc/msgque.c
> +++ /dev/null
> @@ -1,254 +0,0 @@
> -#include <stdlib.h>
> -#include <stdio.h>
> -#include <string.h>
> -#include <errno.h>
> -#include <linux/msg.h>
> -#include <fcntl.h>
> -
> -#include "../kselftest.h"
> -
> -#define MAX_MSG_SIZE 32
> -
> -struct msg1 {
> - int msize;
> - long mtype;
> - char mtext[MAX_MSG_SIZE];
> -};
> -
> -#define TEST_STRING "Test sysv5 msg"
> -#define MSG_TYPE 1
> -
> -#define ANOTHER_TEST_STRING "Yet another test sysv5 msg"
> -#define ANOTHER_MSG_TYPE 26538
> -
> -struct msgque_data {
> - key_t key;
> - int msq_id;
> - int qbytes;
> - int qnum;
> - int mode;
> - struct msg1 *messages;
> -};
> -
> -int restore_queue(struct msgque_data *msgque)
> -{
> - int fd, ret, id, i;
> - char buf[32];
> -
> - fd = open("/proc/sys/kernel/msg_next_id", O_WRONLY);
> - if (fd == -1) {
> - printf("Failed to open /proc/sys/kernel/msg_next_id\n");
> - return -errno;
> - }
> - sprintf(buf, "%d", msgque->msq_id);
> -
> - ret = write(fd, buf, strlen(buf));
> - if (ret != strlen(buf)) {
> - printf("Failed to write to /proc/sys/kernel/msg_next_id\n");
> - return -errno;
> - }
> -
> - id = msgget(msgque->key, msgque->mode | IPC_CREAT | IPC_EXCL);
> - if (id == -1) {
> - printf("Failed to create queue\n");
> - return -errno;
> - }
> -
> - if (id != msgque->msq_id) {
> - printf("Restored queue has wrong id (%d instead of %d)\n",
> - id, msgque->msq_id);
> - ret = -EFAULT;
> - goto destroy;
> - }
> -
> - for (i = 0; i < msgque->qnum; i++) {
> - if (msgsnd(msgque->msq_id, &msgque->messages[i].mtype,
> - msgque->messages[i].msize, IPC_NOWAIT) != 0) {
> - printf("msgsnd failed (%m)\n");
> - ret = -errno;
> - goto destroy;
> - };
> - }
> - return 0;
> -
> -destroy:
> - if (msgctl(id, IPC_RMID, 0))
> - printf("Failed to destroy queue: %d\n", -errno);
> - return ret;
> -}
> -
> -int check_and_destroy_queue(struct msgque_data *msgque)
> -{
> - struct msg1 message;
> - int cnt = 0, ret;
> -
> - while (1) {
> - ret = msgrcv(msgque->msq_id, &message.mtype, MAX_MSG_SIZE,
> - 0, IPC_NOWAIT);
> - if (ret < 0) {
> - if (errno == ENOMSG)
> - break;
> - printf("Failed to read IPC message: %m\n");
> - ret = -errno;
> - goto err;
> - }
> - if (ret != msgque->messages[cnt].msize) {
> - printf("Wrong message size: %d (expected %d)\n", ret,
> - msgque->messages[cnt].msize);
> - ret = -EINVAL;
> - goto err;
> - }
> - if (message.mtype != msgque->messages[cnt].mtype) {
> - printf("Wrong message type\n");
> - ret = -EINVAL;
> - goto err;
> - }
> - if (memcmp(message.mtext, msgque->messages[cnt].mtext, ret)) {
> - printf("Wrong message content\n");
> - ret = -EINVAL;
> - goto err;
> - }
> - cnt++;
> - }
> -
> - if (cnt != msgque->qnum) {
> - printf("Wrong message number\n");
> - ret = -EINVAL;
> - goto err;
> - }
> -
> - ret = 0;
> -err:
> - if (msgctl(msgque->msq_id, IPC_RMID, 0)) {
> - printf("Failed to destroy queue: %d\n", -errno);
> - return -errno;
> - }
> - return ret;
> -}
> -
> -int dump_queue(struct msgque_data *msgque)
> -{
> - struct msqid64_ds ds;
> - int kern_id;
> - int i, ret;
> -
> - for (kern_id = 0; kern_id < 256; kern_id++) {
> - ret = msgctl(kern_id, MSG_STAT, &ds);
> - if (ret < 0) {
> - if (errno == -EINVAL)
> - continue;
> - printf("Failed to get stats for IPC queue with id %d\n",
> - kern_id);
> - return -errno;
> - }
> -
> - if (ret == msgque->msq_id)
> - break;
> - }
> -
> - msgque->messages = malloc(sizeof(struct msg1) * ds.msg_qnum);
> - if (msgque->messages == NULL) {
> - printf("Failed to get stats for IPC queue\n");
> - return -ENOMEM;
> - }
> -
> - msgque->qnum = ds.msg_qnum;
> - msgque->mode = ds.msg_perm.mode;
> - msgque->qbytes = ds.msg_qbytes;
> -
> - for (i = 0; i < msgque->qnum; i++) {
> - ret = msgrcv(msgque->msq_id, &msgque->messages[i].mtype,
> - MAX_MSG_SIZE, i, IPC_NOWAIT | MSG_COPY);
> - if (ret < 0) {
> - printf("Failed to copy IPC message: %m (%d)\n", errno);
> - return -errno;
> - }
> - msgque->messages[i].msize = ret;
> - }
> - return 0;
> -}
> -
> -int fill_msgque(struct msgque_data *msgque)
> -{
> - struct msg1 msgbuf;
> -
> - msgbuf.mtype = MSG_TYPE;
> - memcpy(msgbuf.mtext, TEST_STRING, sizeof(TEST_STRING));
> - if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(TEST_STRING),
> - IPC_NOWAIT) != 0) {
> - printf("First message send failed (%m)\n");
> - return -errno;
> - };
> -
> - msgbuf.mtype = ANOTHER_MSG_TYPE;
> - memcpy(msgbuf.mtext, ANOTHER_TEST_STRING, sizeof(ANOTHER_TEST_STRING));
> - if (msgsnd(msgque->msq_id, &msgbuf.mtype, sizeof(ANOTHER_TEST_STRING),
> - IPC_NOWAIT) != 0) {
> - printf("Second message send failed (%m)\n");
> - return -errno;
> - };
> - return 0;
> -}
> -
> -int main(int argc, char **argv)
> -{
> - int msg, pid, err;
> - struct msgque_data msgque;
> -
> - if (getuid() != 0) {
> - printf("Please run the test as root - Exiting.\n");
> - return ksft_exit_fail();
> - }
> -
> - msgque.key = ftok(argv[0], 822155650);
> - if (msgque.key == -1) {
> - printf("Can't make key: %d\n", -errno);
> - return ksft_exit_fail();
> - }
> -
> - msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666);
> - if (msgque.msq_id == -1) {
> - err = -errno;
> - printf("Can't create queue: %d\n", err);
> - goto err_out;
> - }
> -
> - err = fill_msgque(&msgque);
> - if (err) {
> - printf("Failed to fill queue: %d\n", err);
> - goto err_destroy;
> - }
> -
> - err = dump_queue(&msgque);
> - if (err) {
> - printf("Failed to dump queue: %d\n", err);
> - goto err_destroy;
> - }
> -
> - err = check_and_destroy_queue(&msgque);
> - if (err) {
> - printf("Failed to check and destroy queue: %d\n", err);
> - goto err_out;
> - }
> -
> - err = restore_queue(&msgque);
> - if (err) {
> - printf("Failed to restore queue: %d\n", err);
> - goto err_destroy;
> - }
> -
> - err = check_and_destroy_queue(&msgque);
> - if (err) {
> - printf("Failed to test queue: %d\n", err);
> - goto err_out;
> - }
> - return ksft_exit_pass();
> -
> -err_destroy:
> - if (msgctl(msgque.msq_id, IPC_RMID, 0)) {
> - printf("Failed to destroy queue: %d\n", -errno);
> - return ksft_exit_fail();
> - }
> -err_out:
> - return ksft_exit_fail();
> -}
> diff --git a/tools/testing/selftests/mqueue/.gitignore b/tools/testing/selftests/mqueue/.gitignore
> deleted file mode 100644
> index d8d4237..0000000
> --- a/tools/testing/selftests/mqueue/.gitignore
> +++ /dev/null
> @@ -1,2 +0,0 @@
> -mq_open_tests
> -mq_perf_tests
> diff --git a/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile
> deleted file mode 100644
> index 0e3b41e..0000000
> --- a/tools/testing/selftests/mqueue/Makefile
> +++ /dev/null
> @@ -1,22 +0,0 @@
> -CFLAGS = -O2
> -
> -all:
> - $(CC) $(CFLAGS) mq_open_tests.c -o mq_open_tests -lrt
> - $(CC) $(CFLAGS) -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt
> -
> -include ../lib.mk
> -
> -override define RUN_TESTS
> - @./mq_open_tests /test1 || echo "selftests: mq_open_tests [FAIL]"
> - @./mq_perf_tests || echo "selftests: mq_perf_tests [FAIL]"
> -endef
> -
> -TEST_PROGS := mq_open_tests mq_perf_tests
> -
> -override define EMIT_TESTS
> - echo "./mq_open_tests /test1 || echo \"selftests: mq_open_tests [FAIL]\""
> - echo "./mq_perf_tests || echo \"selftests: mq_perf_tests [FAIL]\""
> -endef
> -
> -clean:
> - rm -f mq_open_tests mq_perf_tests
> diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
> deleted file mode 100644
> index 9c1a5d35..0000000
> --- a/tools/testing/selftests/mqueue/mq_open_tests.c
> +++ /dev/null
> @@ -1,500 +0,0 @@
> -/*
> - * This application is Copyright 2012 Red Hat, Inc.
> - * Doug Ledford <dledford@redhat.com>
> - *
> - * mq_open_tests is free software: you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation, version 3.
> - *
> - * mq_open_tests is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * For the full text of the license, see <http://www.gnu.org/licenses/>.
> - *
> - * mq_open_tests.c
> - * Tests the various situations that should either succeed or fail to
> - * open a posix message queue and then reports whether or not they
> - * did as they were supposed to.
> - *
> - */
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <unistd.h>
> -#include <fcntl.h>
> -#include <string.h>
> -#include <limits.h>
> -#include <errno.h>
> -#include <sys/types.h>
> -#include <sys/time.h>
> -#include <sys/resource.h>
> -#include <sys/stat.h>
> -#include <mqueue.h>
> -
> -static char *usage =
> -"Usage:\n"
> -" %s path\n"
> -"\n"
> -" path Path name of the message queue to create\n"
> -"\n"
> -" Note: this program must be run as root in order to enable all tests\n"
> -"\n";
> -
> -char *DEF_MSGS = "/proc/sys/fs/mqueue/msg_default";
> -char *DEF_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_default";
> -char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
> -char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
> -
> -int default_settings;
> -struct rlimit saved_limits, cur_limits;
> -int saved_def_msgs, saved_def_msgsize, saved_max_msgs, saved_max_msgsize;
> -int cur_def_msgs, cur_def_msgsize, cur_max_msgs, cur_max_msgsize;
> -FILE *def_msgs, *def_msgsize, *max_msgs, *max_msgsize;
> -char *queue_path;
> -mqd_t queue = -1;
> -
> -static inline void __set(FILE *stream, int value, char *err_msg);
> -void shutdown(int exit_val, char *err_cause, int line_no);
> -static inline int get(FILE *stream);
> -static inline void set(FILE *stream, int value);
> -static inline void getr(int type, struct rlimit *rlim);
> -static inline void setr(int type, struct rlimit *rlim);
> -void validate_current_settings();
> -static inline void test_queue(struct mq_attr *attr, struct mq_attr *result);
> -static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result);
> -
> -static inline void __set(FILE *stream, int value, char *err_msg)
> -{
> - rewind(stream);
> - if (fprintf(stream, "%d", value) < 0)
> - perror(err_msg);
> -}
> -
> -
> -void shutdown(int exit_val, char *err_cause, int line_no)
> -{
> - static int in_shutdown = 0;
> -
> - /* In case we get called recursively by a set() call below */
> - if (in_shutdown++)
> - return;
> -
> - if (seteuid(0) == -1)
> - perror("seteuid() failed");
> -
> - if (queue != -1)
> - if (mq_close(queue))
> - perror("mq_close() during shutdown");
> - if (queue_path)
> - /*
> - * Be silent if this fails, if we cleaned up already it's
> - * expected to fail
> - */
> - mq_unlink(queue_path);
> - if (default_settings) {
> - if (saved_def_msgs)
> - __set(def_msgs, saved_def_msgs,
> - "failed to restore saved_def_msgs");
> - if (saved_def_msgsize)
> - __set(def_msgsize, saved_def_msgsize,
> - "failed to restore saved_def_msgsize");
> - }
> - if (saved_max_msgs)
> - __set(max_msgs, saved_max_msgs,
> - "failed to restore saved_max_msgs");
> - if (saved_max_msgsize)
> - __set(max_msgsize, saved_max_msgsize,
> - "failed to restore saved_max_msgsize");
> - if (exit_val)
> - error(exit_val, errno, "%s at %d", err_cause, line_no);
> - exit(0);
> -}
> -
> -static inline int get(FILE *stream)
> -{
> - int value;
> - rewind(stream);
> - if (fscanf(stream, "%d", &value) != 1)
> - shutdown(4, "Error reading /proc entry", __LINE__ - 1);
> - return value;
> -}
> -
> -static inline void set(FILE *stream, int value)
> -{
> - int new_value;
> -
> - rewind(stream);
> - if (fprintf(stream, "%d", value) < 0)
> - return shutdown(5, "Failed writing to /proc file",
> - __LINE__ - 1);
> - new_value = get(stream);
> - if (new_value != value)
> - return shutdown(5, "We didn't get what we wrote to /proc back",
> - __LINE__ - 1);
> -}
> -
> -static inline void getr(int type, struct rlimit *rlim)
> -{
> - if (getrlimit(type, rlim))
> - shutdown(6, "getrlimit()", __LINE__ - 1);
> -}
> -
> -static inline void setr(int type, struct rlimit *rlim)
> -{
> - if (setrlimit(type, rlim))
> - shutdown(7, "setrlimit()", __LINE__ - 1);
> -}
> -
> -void validate_current_settings()
> -{
> - int rlim_needed;
> -
> - if (cur_limits.rlim_cur < 4096) {
> - printf("Current rlimit value for POSIX message queue bytes is "
> - "unreasonably low,\nincreasing.\n\n");
> - cur_limits.rlim_cur = 8192;
> - cur_limits.rlim_max = 16384;
> - setr(RLIMIT_MSGQUEUE, &cur_limits);
> - }
> -
> - if (default_settings) {
> - rlim_needed = (cur_def_msgs + 1) * (cur_def_msgsize + 1 +
> - 2 * sizeof(void *));
> - if (rlim_needed > cur_limits.rlim_cur) {
> - printf("Temporarily lowering default queue parameters "
> - "to something that will work\n"
> - "with the current rlimit values.\n\n");
> - set(def_msgs, 10);
> - cur_def_msgs = 10;
> - set(def_msgsize, 128);
> - cur_def_msgsize = 128;
> - }
> - } else {
> - rlim_needed = (cur_max_msgs + 1) * (cur_max_msgsize + 1 +
> - 2 * sizeof(void *));
> - if (rlim_needed > cur_limits.rlim_cur) {
> - printf("Temporarily lowering maximum queue parameters "
> - "to something that will work\n"
> - "with the current rlimit values in case this is "
> - "a kernel that ties the default\n"
> - "queue parameters to the maximum queue "
> - "parameters.\n\n");
> - set(max_msgs, 10);
> - cur_max_msgs = 10;
> - set(max_msgsize, 128);
> - cur_max_msgsize = 128;
> - }
> - }
> -}
> -
> -/*
> - * test_queue - Test opening a queue, shutdown if we fail. This should
> - * only be called in situations that should never fail. We clean up
> - * after ourselves and return the queue attributes in *result.
> - */
> -static inline void test_queue(struct mq_attr *attr, struct mq_attr *result)
> -{
> - int flags = O_RDWR | O_EXCL | O_CREAT;
> - int perms = DEFFILEMODE;
> -
> - if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
> - shutdown(1, "mq_open()", __LINE__);
> - if (mq_getattr(queue, result))
> - shutdown(1, "mq_getattr()", __LINE__);
> - if (mq_close(queue))
> - shutdown(1, "mq_close()", __LINE__);
> - queue = -1;
> - if (mq_unlink(queue_path))
> - shutdown(1, "mq_unlink()", __LINE__);
> -}
> -
> -/*
> - * Same as test_queue above, but failure is not fatal.
> - * Returns:
> - * 0 - Failed to create a queue
> - * 1 - Created a queue, attributes in *result
> - */
> -static inline int test_queue_fail(struct mq_attr *attr, struct mq_attr *result)
> -{
> - int flags = O_RDWR | O_EXCL | O_CREAT;
> - int perms = DEFFILEMODE;
> -
> - if ((queue = mq_open(queue_path, flags, perms, attr)) == -1)
> - return 0;
> - if (mq_getattr(queue, result))
> - shutdown(1, "mq_getattr()", __LINE__);
> - if (mq_close(queue))
> - shutdown(1, "mq_close()", __LINE__);
> - queue = -1;
> - if (mq_unlink(queue_path))
> - shutdown(1, "mq_unlink()", __LINE__);
> - return 1;
> -}
> -
> -int main(int argc, char *argv[])
> -{
> - struct mq_attr attr, result;
> -
> - if (argc != 2) {
> - fprintf(stderr, "Must pass a valid queue name\n\n");
> - fprintf(stderr, usage, argv[0]);
> - exit(1);
> - }
> -
> - /*
> - * Although we can create a msg queue with a non-absolute path name,
> - * unlink will fail. So, if the name doesn't start with a /, add one
> - * when we save it.
> - */
> - if (*argv[1] == '/')
> - queue_path = strdup(argv[1]);
> - else {
> - queue_path = malloc(strlen(argv[1]) + 2);
> - if (!queue_path) {
> - perror("malloc()");
> - exit(1);
> - }
> - queue_path[0] = '/';
> - queue_path[1] = 0;
> - strcat(queue_path, argv[1]);
> - }
> -
> - if (getuid() != 0) {
> - fprintf(stderr, "Not running as root, but almost all tests "
> - "require root in order to modify\nsystem settings. "
> - "Exiting.\n");
> - exit(1);
> - }
> -
> - /* Find out what files there are for us to make tweaks in */
> - def_msgs = fopen(DEF_MSGS, "r+");
> - def_msgsize = fopen(DEF_MSGSIZE, "r+");
> - max_msgs = fopen(MAX_MSGS, "r+");
> - max_msgsize = fopen(MAX_MSGSIZE, "r+");
> -
> - if (!max_msgs)
> - shutdown(2, "Failed to open msg_max", __LINE__);
> - if (!max_msgsize)
> - shutdown(2, "Failed to open msgsize_max", __LINE__);
> - if (def_msgs || def_msgsize)
> - default_settings = 1;
> -
> - /* Load up the current system values for everything we can */
> - getr(RLIMIT_MSGQUEUE, &saved_limits);
> - cur_limits = saved_limits;
> - if (default_settings) {
> - saved_def_msgs = cur_def_msgs = get(def_msgs);
> - saved_def_msgsize = cur_def_msgsize = get(def_msgsize);
> - }
> - saved_max_msgs = cur_max_msgs = get(max_msgs);
> - saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
> -
> - /* Tell the user our initial state */
> - printf("\nInitial system state:\n");
> - printf("\tUsing queue path:\t\t%s\n", queue_path);
> - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n",
> - (long) saved_limits.rlim_cur);
> - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n",
> - (long) saved_limits.rlim_max);
> - printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize);
> - printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs);
> - if (default_settings) {
> - printf("\tDefault Message Size:\t\t%d\n", saved_def_msgsize);
> - printf("\tDefault Queue Size:\t\t%d\n", saved_def_msgs);
> - } else {
> - printf("\tDefault Message Size:\t\tNot Supported\n");
> - printf("\tDefault Queue Size:\t\tNot Supported\n");
> - }
> - printf("\n");
> -
> - validate_current_settings();
> -
> - printf("Adjusted system state for testing:\n");
> - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur);
> - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max);
> - printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize);
> - printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs);
> - if (default_settings) {
> - printf("\tDefault Message Size:\t\t%d\n", cur_def_msgsize);
> - printf("\tDefault Queue Size:\t\t%d\n", cur_def_msgs);
> - }
> -
> - printf("\n\nTest series 1, behavior when no attr struct "
> - "passed to mq_open:\n");
> - if (!default_settings) {
> - test_queue(NULL, &result);
> - printf("Given sane system settings, mq_open without an attr "
> - "struct succeeds:\tPASS\n");
> - if (result.mq_maxmsg != cur_max_msgs ||
> - result.mq_msgsize != cur_max_msgsize) {
> - printf("Kernel does not support setting the default "
> - "mq attributes,\nbut also doesn't tie the "
> - "defaults to the maximums:\t\t\tPASS\n");
> - } else {
> - set(max_msgs, ++cur_max_msgs);
> - set(max_msgsize, ++cur_max_msgsize);
> - test_queue(NULL, &result);
> - if (result.mq_maxmsg == cur_max_msgs &&
> - result.mq_msgsize == cur_max_msgsize)
> - printf("Kernel does not support setting the "
> - "default mq attributes and\n"
> - "also ties system wide defaults to "
> - "the system wide maximums:\t\t"
> - "FAIL\n");
> - else
> - printf("Kernel does not support setting the "
> - "default mq attributes,\n"
> - "but also doesn't tie the defaults to "
> - "the maximums:\t\t\tPASS\n");
> - }
> - } else {
> - printf("Kernel supports setting defaults separately from "
> - "maximums:\t\tPASS\n");
> - /*
> - * While we are here, go ahead and test that the kernel
> - * properly follows the default settings
> - */
> - test_queue(NULL, &result);
> - printf("Given sane values, mq_open without an attr struct "
> - "succeeds:\t\tPASS\n");
> - if (result.mq_maxmsg != cur_def_msgs ||
> - result.mq_msgsize != cur_def_msgsize)
> - printf("Kernel supports setting defaults, but does "
> - "not actually honor them:\tFAIL\n\n");
> - else {
> - set(def_msgs, ++cur_def_msgs);
> - set(def_msgsize, ++cur_def_msgsize);
> - /* In case max was the same as the default */
> - set(max_msgs, ++cur_max_msgs);
> - set(max_msgsize, ++cur_max_msgsize);
> - test_queue(NULL, &result);
> - if (result.mq_maxmsg != cur_def_msgs ||
> - result.mq_msgsize != cur_def_msgsize)
> - printf("Kernel supports setting defaults, but "
> - "does not actually honor them:\t"
> - "FAIL\n");
> - else
> - printf("Kernel properly honors default setting "
> - "knobs:\t\t\t\tPASS\n");
> - }
> - set(def_msgs, cur_max_msgs + 1);
> - cur_def_msgs = cur_max_msgs + 1;
> - set(def_msgsize, cur_max_msgsize + 1);
> - cur_def_msgsize = cur_max_msgsize + 1;
> - if (cur_def_msgs * (cur_def_msgsize + 2 * sizeof(void *)) >=
> - cur_limits.rlim_cur) {
> - cur_limits.rlim_cur = (cur_def_msgs + 2) *
> - (cur_def_msgsize + 2 * sizeof(void *));
> - cur_limits.rlim_max = 2 * cur_limits.rlim_cur;
> - setr(RLIMIT_MSGQUEUE, &cur_limits);
> - }
> - if (test_queue_fail(NULL, &result)) {
> - if (result.mq_maxmsg == cur_max_msgs &&
> - result.mq_msgsize == cur_max_msgsize)
> - printf("Kernel properly limits default values "
> - "to lesser of default/max:\t\tPASS\n");
> - else
> - printf("Kernel does not properly set default "
> - "queue parameters when\ndefaults > "
> - "max:\t\t\t\t\t\t\t\tFAIL\n");
> - } else
> - printf("Kernel fails to open mq because defaults are "
> - "greater than maximums:\tFAIL\n");
> - set(def_msgs, --cur_def_msgs);
> - set(def_msgsize, --cur_def_msgsize);
> - cur_limits.rlim_cur = cur_limits.rlim_max = cur_def_msgs *
> - cur_def_msgsize;
> - setr(RLIMIT_MSGQUEUE, &cur_limits);
> - if (test_queue_fail(NULL, &result))
> - printf("Kernel creates queue even though defaults "
> - "would exceed\nrlimit setting:"
> - "\t\t\t\t\t\t\t\tFAIL\n");
> - else
> - printf("Kernel properly fails to create queue when "
> - "defaults would\nexceed rlimit:"
> - "\t\t\t\t\t\t\t\tPASS\n");
> - }
> -
> - /*
> - * Test #2 - open with an attr struct that exceeds rlimit
> - */
> - printf("\n\nTest series 2, behavior when attr struct is "
> - "passed to mq_open:\n");
> - cur_max_msgs = 32;
> - cur_max_msgsize = cur_limits.rlim_max >> 4;
> - set(max_msgs, cur_max_msgs);
> - set(max_msgsize, cur_max_msgsize);
> - attr.mq_maxmsg = cur_max_msgs;
> - attr.mq_msgsize = cur_max_msgsize;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open in excess of rlimit max when euid = 0 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open in excess of rlimit max when euid = 0 "
> - "failed:\t\tPASS\n");
> - attr.mq_maxmsg = cur_max_msgs + 1;
> - attr.mq_msgsize = 10;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with mq_maxmsg > limit when euid = 0 "
> - "succeeded:\t\tPASS\n");
> - else
> - printf("Queue open with mq_maxmsg > limit when euid = 0 "
> - "failed:\t\tFAIL\n");
> - attr.mq_maxmsg = 1;
> - attr.mq_msgsize = cur_max_msgsize + 1;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with mq_msgsize > limit when euid = 0 "
> - "succeeded:\t\tPASS\n");
> - else
> - printf("Queue open with mq_msgsize > limit when euid = 0 "
> - "failed:\t\tFAIL\n");
> - attr.mq_maxmsg = 65536;
> - attr.mq_msgsize = 65536;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with total size > 2GB when euid = 0 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open with total size > 2GB when euid = 0 "
> - "failed:\t\t\tPASS\n");
> -
> - if (seteuid(99) == -1) {
> - perror("seteuid() failed");
> - exit(1);
> - }
> -
> - attr.mq_maxmsg = cur_max_msgs;
> - attr.mq_msgsize = cur_max_msgsize;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open in excess of rlimit max when euid = 99 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open in excess of rlimit max when euid = 99 "
> - "failed:\t\tPASS\n");
> - attr.mq_maxmsg = cur_max_msgs + 1;
> - attr.mq_msgsize = 10;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with mq_maxmsg > limit when euid = 99 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open with mq_maxmsg > limit when euid = 99 "
> - "failed:\t\tPASS\n");
> - attr.mq_maxmsg = 1;
> - attr.mq_msgsize = cur_max_msgsize + 1;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with mq_msgsize > limit when euid = 99 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open with mq_msgsize > limit when euid = 99 "
> - "failed:\t\tPASS\n");
> - attr.mq_maxmsg = 65536;
> - attr.mq_msgsize = 65536;
> - if (test_queue_fail(&attr, &result))
> - printf("Queue open with total size > 2GB when euid = 99 "
> - "succeeded:\t\tFAIL\n");
> - else
> - printf("Queue open with total size > 2GB when euid = 99 "
> - "failed:\t\t\tPASS\n");
> -
> - shutdown(0,"",0);
> -}
> diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
> deleted file mode 100644
> index 8519e9e..0000000
> --- a/tools/testing/selftests/mqueue/mq_perf_tests.c
> +++ /dev/null
> @@ -1,742 +0,0 @@
> -/*
> - * This application is Copyright 2012 Red Hat, Inc.
> - * Doug Ledford <dledford@redhat.com>
> - *
> - * mq_perf_tests is free software: you can redistribute it and/or modify
> - * it under the terms of the GNU General Public License as published by
> - * the Free Software Foundation, version 3.
> - *
> - * mq_perf_tests is distributed in the hope that it will be useful,
> - * but WITHOUT ANY WARRANTY; without even the implied warranty of
> - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> - * GNU General Public License for more details.
> - *
> - * For the full text of the license, see <http://www.gnu.org/licenses/>.
> - *
> - * mq_perf_tests.c
> - * Tests various types of message queue workloads, concentrating on those
> - * situations that invole large message sizes, large message queue depths,
> - * or both, and reports back useful metrics about kernel message queue
> - * performance.
> - *
> - */
> -#define _GNU_SOURCE
> -#include <stdio.h>
> -#include <stdlib.h>
> -#include <unistd.h>
> -#include <fcntl.h>
> -#include <string.h>
> -#include <limits.h>
> -#include <errno.h>
> -#include <signal.h>
> -#include <pthread.h>
> -#include <sched.h>
> -#include <sys/types.h>
> -#include <sys/time.h>
> -#include <sys/resource.h>
> -#include <sys/stat.h>
> -#include <mqueue.h>
> -#include <popt.h>
> -
> -static char *usage =
> -"Usage:\n"
> -" %s [-c #[,#..] -f] path\n"
> -"\n"
> -" -c # Skip most tests and go straight to a high queue depth test\n"
> -" and then run that test continuously (useful for running at\n"
> -" the same time as some other workload to see how much the\n"
> -" cache thrashing caused by adding messages to a very deep\n"
> -" queue impacts the performance of other programs). The number\n"
> -" indicates which CPU core we should bind the process to during\n"
> -" the run. If you have more than one physical CPU, then you\n"
> -" will need one copy per physical CPU package, and you should\n"
> -" specify the CPU cores to pin ourself to via a comma separated\n"
> -" list of CPU values.\n"
> -" -f Only usable with continuous mode. Pin ourself to the CPUs\n"
> -" as requested, then instead of looping doing a high mq\n"
> -" workload, just busy loop. This will allow us to lock up a\n"
> -" single CPU just like we normally would, but without actually\n"
> -" thrashing the CPU cache. This is to make it easier to get\n"
> -" comparable numbers from some other workload running on the\n"
> -" other CPUs. One set of numbers with # CPUs locked up running\n"
> -" an mq workload, and another set of numbers with those same\n"
> -" CPUs locked away from the test workload, but not doing\n"
> -" anything to trash the cache like the mq workload might.\n"
> -" path Path name of the message queue to create\n"
> -"\n"
> -" Note: this program must be run as root in order to enable all tests\n"
> -"\n";
> -
> -char *MAX_MSGS = "/proc/sys/fs/mqueue/msg_max";
> -char *MAX_MSGSIZE = "/proc/sys/fs/mqueue/msgsize_max";
> -
> -#define min(a, b) ((a) < (b) ? (a) : (b))
> -#define MAX_CPUS 64
> -char *cpu_option_string;
> -int cpus_to_pin[MAX_CPUS];
> -int num_cpus_to_pin;
> -pthread_t cpu_threads[MAX_CPUS];
> -pthread_t main_thread;
> -cpu_set_t *cpu_set;
> -int cpu_set_size;
> -int cpus_online;
> -
> -#define MSG_SIZE 16
> -#define TEST1_LOOPS 10000000
> -#define TEST2_LOOPS 100000
> -int continuous_mode;
> -int continuous_mode_fake;
> -
> -struct rlimit saved_limits, cur_limits;
> -int saved_max_msgs, saved_max_msgsize;
> -int cur_max_msgs, cur_max_msgsize;
> -FILE *max_msgs, *max_msgsize;
> -int cur_nice;
> -char *queue_path = "/mq_perf_tests";
> -mqd_t queue = -1;
> -struct mq_attr result;
> -int mq_prio_max;
> -
> -const struct poptOption options[] = {
> - {
> - .longName = "continuous",
> - .shortName = 'c',
> - .argInfo = POPT_ARG_STRING,
> - .arg = &cpu_option_string,
> - .val = 'c',
> - .descrip = "Run continuous tests at a high queue depth in "
> - "order to test the effects of cache thrashing on "
> - "other tasks on the system. This test is intended "
> - "to be run on one core of each physical CPU while "
> - "some other CPU intensive task is run on all the other "
> - "cores of that same physical CPU and the other task "
> - "is timed. It is assumed that the process of adding "
> - "messages to the message queue in a tight loop will "
> - "impact that other task to some degree. Once the "
> - "tests are performed in this way, you should then "
> - "re-run the tests using fake mode in order to check "
> - "the difference in time required to perform the CPU "
> - "intensive task",
> - .argDescrip = "cpu[,cpu]",
> - },
> - {
> - .longName = "fake",
> - .shortName = 'f',
> - .argInfo = POPT_ARG_NONE,
> - .arg = &continuous_mode_fake,
> - .val = 0,
> - .descrip = "Tie up the CPUs that we would normally tie up in"
> - "continuous mode, but don't actually do any mq stuff, "
> - "just keep the CPU busy so it can't be used to process "
> - "system level tasks as this would free up resources on "
> - "the other CPU cores and skew the comparison between "
> - "the no-mqueue work and mqueue work tests",
> - .argDescrip = NULL,
> - },
> - {
> - .longName = "path",
> - .shortName = 'p',
> - .argInfo = POPT_ARG_STRING | POPT_ARGFLAG_SHOW_DEFAULT,
> - .arg = &queue_path,
> - .val = 'p',
> - .descrip = "The name of the path to use in the mqueue "
> - "filesystem for our tests",
> - .argDescrip = "pathname",
> - },
> - POPT_AUTOHELP
> - POPT_TABLEEND
> -};
> -
> -static inline void __set(FILE *stream, int value, char *err_msg);
> -void shutdown(int exit_val, char *err_cause, int line_no);
> -void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context);
> -void sig_action(int signum, siginfo_t *info, void *context);
> -static inline int get(FILE *stream);
> -static inline void set(FILE *stream, int value);
> -static inline int try_set(FILE *stream, int value);
> -static inline void getr(int type, struct rlimit *rlim);
> -static inline void setr(int type, struct rlimit *rlim);
> -static inline void open_queue(struct mq_attr *attr);
> -void increase_limits(void);
> -
> -static inline void __set(FILE *stream, int value, char *err_msg)
> -{
> - rewind(stream);
> - if (fprintf(stream, "%d", value) < 0)
> - perror(err_msg);
> -}
> -
> -
> -void shutdown(int exit_val, char *err_cause, int line_no)
> -{
> - static int in_shutdown = 0;
> - int errno_at_shutdown = errno;
> - int i;
> -
> - /* In case we get called by multiple threads or from an sighandler */
> - if (in_shutdown++)
> - return;
> -
> - for (i = 0; i < num_cpus_to_pin; i++)
> - if (cpu_threads[i]) {
> - pthread_kill(cpu_threads[i], SIGUSR1);
> - pthread_join(cpu_threads[i], NULL);
> - }
> -
> - if (queue != -1)
> - if (mq_close(queue))
> - perror("mq_close() during shutdown");
> - if (queue_path)
> - /*
> - * Be silent if this fails, if we cleaned up already it's
> - * expected to fail
> - */
> - mq_unlink(queue_path);
> - if (saved_max_msgs)
> - __set(max_msgs, saved_max_msgs,
> - "failed to restore saved_max_msgs");
> - if (saved_max_msgsize)
> - __set(max_msgsize, saved_max_msgsize,
> - "failed to restore saved_max_msgsize");
> - if (exit_val)
> - error(exit_val, errno_at_shutdown, "%s at %d",
> - err_cause, line_no);
> - exit(0);
> -}
> -
> -void sig_action_SIGUSR1(int signum, siginfo_t *info, void *context)
> -{
> - if (pthread_self() != main_thread)
> - pthread_exit(0);
> - else {
> - fprintf(stderr, "Caught signal %d in SIGUSR1 handler, "
> - "exiting\n", signum);
> - shutdown(0, "", 0);
> - fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
> - exit(0);
> - }
> -}
> -
> -void sig_action(int signum, siginfo_t *info, void *context)
> -{
> - if (pthread_self() != main_thread)
> - pthread_kill(main_thread, signum);
> - else {
> - fprintf(stderr, "Caught signal %d, exiting\n", signum);
> - shutdown(0, "", 0);
> - fprintf(stderr, "\n\nReturned from shutdown?!?!\n\n");
> - exit(0);
> - }
> -}
> -
> -static inline int get(FILE *stream)
> -{
> - int value;
> - rewind(stream);
> - if (fscanf(stream, "%d", &value) != 1)
> - shutdown(4, "Error reading /proc entry", __LINE__);
> - return value;
> -}
> -
> -static inline void set(FILE *stream, int value)
> -{
> - int new_value;
> -
> - rewind(stream);
> - if (fprintf(stream, "%d", value) < 0)
> - return shutdown(5, "Failed writing to /proc file", __LINE__);
> - new_value = get(stream);
> - if (new_value != value)
> - return shutdown(5, "We didn't get what we wrote to /proc back",
> - __LINE__);
> -}
> -
> -static inline int try_set(FILE *stream, int value)
> -{
> - int new_value;
> -
> - rewind(stream);
> - fprintf(stream, "%d", value);
> - new_value = get(stream);
> - return new_value == value;
> -}
> -
> -static inline void getr(int type, struct rlimit *rlim)
> -{
> - if (getrlimit(type, rlim))
> - shutdown(6, "getrlimit()", __LINE__);
> -}
> -
> -static inline void setr(int type, struct rlimit *rlim)
> -{
> - if (setrlimit(type, rlim))
> - shutdown(7, "setrlimit()", __LINE__);
> -}
> -
> -/**
> - * open_queue - open the global queue for testing
> - * @attr - An attr struct specifying the desired queue traits
> - * @result - An attr struct that lists the actual traits the queue has
> - *
> - * This open is not allowed to fail, failure will result in an orderly
> - * shutdown of the program. The global queue_path is used to set what
> - * queue to open, the queue descriptor is saved in the global queue
> - * variable.
> - */
> -static inline void open_queue(struct mq_attr *attr)
> -{
> - int flags = O_RDWR | O_EXCL | O_CREAT | O_NONBLOCK;
> - int perms = DEFFILEMODE;
> -
> - queue = mq_open(queue_path, flags, perms, attr);
> - if (queue == -1)
> - shutdown(1, "mq_open()", __LINE__);
> - if (mq_getattr(queue, &result))
> - shutdown(1, "mq_getattr()", __LINE__);
> - printf("\n\tQueue %s created:\n", queue_path);
> - printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ?
> - "O_NONBLOCK" : "(null)");
> - printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg);
> - printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize);
> - printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs);
> -}
> -
> -void *fake_cont_thread(void *arg)
> -{
> - int i;
> -
> - for (i = 0; i < num_cpus_to_pin; i++)
> - if (cpu_threads[i] == pthread_self())
> - break;
> - printf("\tStarted fake continuous mode thread %d on CPU %d\n", i,
> - cpus_to_pin[i]);
> - while (1)
> - ;
> -}
> -
> -void *cont_thread(void *arg)
> -{
> - char buff[MSG_SIZE];
> - int i, priority;
> -
> - for (i = 0; i < num_cpus_to_pin; i++)
> - if (cpu_threads[i] == pthread_self())
> - break;
> - printf("\tStarted continuous mode thread %d on CPU %d\n", i,
> - cpus_to_pin[i]);
> - while (1) {
> - while (mq_send(queue, buff, sizeof(buff), 0) == 0)
> - ;
> - mq_receive(queue, buff, sizeof(buff), &priority);
> - }
> -}
> -
> -#define drain_queue() \
> - while (mq_receive(queue, buff, MSG_SIZE, &prio_in) == MSG_SIZE)
> -
> -#define do_untimed_send() \
> - do { \
> - if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
> - shutdown(3, "Test send failure", __LINE__); \
> - } while (0)
> -
> -#define do_send_recv() \
> - do { \
> - clock_gettime(clock, &start); \
> - if (mq_send(queue, buff, MSG_SIZE, prio_out)) \
> - shutdown(3, "Test send failure", __LINE__); \
> - clock_gettime(clock, &middle); \
> - if (mq_receive(queue, buff, MSG_SIZE, &prio_in) != MSG_SIZE) \
> - shutdown(3, "Test receive failure", __LINE__); \
> - clock_gettime(clock, &end); \
> - nsec = ((middle.tv_sec - start.tv_sec) * 1000000000) + \
> - (middle.tv_nsec - start.tv_nsec); \
> - send_total.tv_nsec += nsec; \
> - if (send_total.tv_nsec >= 1000000000) { \
> - send_total.tv_sec++; \
> - send_total.tv_nsec -= 1000000000; \
> - } \
> - nsec = ((end.tv_sec - middle.tv_sec) * 1000000000) + \
> - (end.tv_nsec - middle.tv_nsec); \
> - recv_total.tv_nsec += nsec; \
> - if (recv_total.tv_nsec >= 1000000000) { \
> - recv_total.tv_sec++; \
> - recv_total.tv_nsec -= 1000000000; \
> - } \
> - } while (0)
> -
> -struct test {
> - char *desc;
> - void (*func)(int *);
> -};
> -
> -void const_prio(int *prio)
> -{
> - return;
> -}
> -
> -void inc_prio(int *prio)
> -{
> - if (++*prio == mq_prio_max)
> - *prio = 0;
> -}
> -
> -void dec_prio(int *prio)
> -{
> - if (--*prio < 0)
> - *prio = mq_prio_max - 1;
> -}
> -
> -void random_prio(int *prio)
> -{
> - *prio = random() % mq_prio_max;
> -}
> -
> -struct test test2[] = {
> - {"\n\tTest #2a: Time send/recv message, queue full, constant prio\n",
> - const_prio},
> - {"\n\tTest #2b: Time send/recv message, queue full, increasing prio\n",
> - inc_prio},
> - {"\n\tTest #2c: Time send/recv message, queue full, decreasing prio\n",
> - dec_prio},
> - {"\n\tTest #2d: Time send/recv message, queue full, random prio\n",
> - random_prio},
> - {NULL, NULL}
> -};
> -
> -/**
> - * Tests to perform (all done with MSG_SIZE messages):
> - *
> - * 1) Time to add/remove message with 0 messages on queue
> - * 1a) with constant prio
> - * 2) Time to add/remove message when queue close to capacity:
> - * 2a) with constant prio
> - * 2b) with increasing prio
> - * 2c) with decreasing prio
> - * 2d) with random prio
> - * 3) Test limits of priorities honored (double check _SC_MQ_PRIO_MAX)
> - */
> -void *perf_test_thread(void *arg)
> -{
> - char buff[MSG_SIZE];
> - int prio_out, prio_in;
> - int i;
> - clockid_t clock;
> - pthread_t *t;
> - struct timespec res, start, middle, end, send_total, recv_total;
> - unsigned long long nsec;
> - struct test *cur_test;
> -
> - t = &cpu_threads[0];
> - printf("\n\tStarted mqueue performance test thread on CPU %d\n",
> - cpus_to_pin[0]);
> - mq_prio_max = sysconf(_SC_MQ_PRIO_MAX);
> - if (mq_prio_max == -1)
> - shutdown(2, "sysconf(_SC_MQ_PRIO_MAX)", __LINE__);
> - if (pthread_getcpuclockid(cpu_threads[0], &clock) != 0)
> - shutdown(2, "pthread_getcpuclockid", __LINE__);
> -
> - if (clock_getres(clock, &res))
> - shutdown(2, "clock_getres()", __LINE__);
> -
> - printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max);
> - printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec,
> - res.tv_nsec > 1 ? "s" : "");
> -
> -
> -
> - printf("\n\tTest #1: Time send/recv message, queue empty\n");
> - printf("\t\t(%d iterations)\n", TEST1_LOOPS);
> - prio_out = 0;
> - send_total.tv_sec = 0;
> - send_total.tv_nsec = 0;
> - recv_total.tv_sec = 0;
> - recv_total.tv_nsec = 0;
> - for (i = 0; i < TEST1_LOOPS; i++)
> - do_send_recv();
> - printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
> - send_total.tv_sec, send_total.tv_nsec);
> - nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
> - send_total.tv_nsec) / TEST1_LOOPS;
> - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> - printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
> - recv_total.tv_sec, recv_total.tv_nsec);
> - nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
> - recv_total.tv_nsec) / TEST1_LOOPS;
> - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> -
> -
> - for (cur_test = test2; cur_test->desc != NULL; cur_test++) {
> - printf("%s:\n", cur_test->desc);
> - printf("\t\t(%d iterations)\n", TEST2_LOOPS);
> - prio_out = 0;
> - send_total.tv_sec = 0;
> - send_total.tv_nsec = 0;
> - recv_total.tv_sec = 0;
> - recv_total.tv_nsec = 0;
> - printf("\t\tFilling queue...");
> - fflush(stdout);
> - clock_gettime(clock, &start);
> - for (i = 0; i < result.mq_maxmsg - 1; i++) {
> - do_untimed_send();
> - cur_test->func(&prio_out);
> - }
> - clock_gettime(clock, &end);
> - nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
> - 1000000000) + (end.tv_nsec - start.tv_nsec);
> - printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
> - nsec % 1000000000);
> - printf("\t\tTesting...");
> - fflush(stdout);
> - for (i = 0; i < TEST2_LOOPS; i++) {
> - do_send_recv();
> - cur_test->func(&prio_out);
> - }
> - printf("done.\n");
> - printf("\t\tSend msg:\t\t\t%ld.%lus total time\n",
> - send_total.tv_sec, send_total.tv_nsec);
> - nsec = ((unsigned long long)send_total.tv_sec * 1000000000 +
> - send_total.tv_nsec) / TEST2_LOOPS;
> - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> - printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n",
> - recv_total.tv_sec, recv_total.tv_nsec);
> - nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 +
> - recv_total.tv_nsec) / TEST2_LOOPS;
> - printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec);
> - printf("\t\tDraining queue...");
> - fflush(stdout);
> - clock_gettime(clock, &start);
> - drain_queue();
> - clock_gettime(clock, &end);
> - nsec = ((unsigned long long)(end.tv_sec - start.tv_sec) *
> - 1000000000) + (end.tv_nsec - start.tv_nsec);
> - printf("done.\t\t%lld.%llds\n", nsec / 1000000000,
> - nsec % 1000000000);
> - }
> - return 0;
> -}
> -
> -void increase_limits(void)
> -{
> - cur_limits.rlim_cur = RLIM_INFINITY;
> - cur_limits.rlim_max = RLIM_INFINITY;
> - setr(RLIMIT_MSGQUEUE, &cur_limits);
> - while (try_set(max_msgs, cur_max_msgs += 10))
> - ;
> - cur_max_msgs = get(max_msgs);
> - while (try_set(max_msgsize, cur_max_msgsize += 1024))
> - ;
> - cur_max_msgsize = get(max_msgsize);
> - if (setpriority(PRIO_PROCESS, 0, -20) != 0)
> - shutdown(2, "setpriority()", __LINE__);
> - cur_nice = -20;
> -}
> -
> -int main(int argc, char *argv[])
> -{
> - struct mq_attr attr;
> - char *option, *next_option;
> - int i, cpu, rc;
> - struct sigaction sa;
> - poptContext popt_context;
> - void *retval;
> -
> - main_thread = pthread_self();
> - num_cpus_to_pin = 0;
> -
> - if (sysconf(_SC_NPROCESSORS_ONLN) == -1) {
> - perror("sysconf(_SC_NPROCESSORS_ONLN)");
> - exit(1);
> - }
> - cpus_online = min(MAX_CPUS, sysconf(_SC_NPROCESSORS_ONLN));
> - cpu_set = CPU_ALLOC(cpus_online);
> - if (cpu_set == NULL) {
> - perror("CPU_ALLOC()");
> - exit(1);
> - }
> - cpu_set_size = CPU_ALLOC_SIZE(cpus_online);
> - CPU_ZERO_S(cpu_set_size, cpu_set);
> -
> - popt_context = poptGetContext(NULL, argc, (const char **)argv,
> - options, 0);
> -
> - while ((rc = poptGetNextOpt(popt_context)) > 0) {
> - switch (rc) {
> - case 'c':
> - continuous_mode = 1;
> - option = cpu_option_string;
> - do {
> - next_option = strchr(option, ',');
> - if (next_option)
> - *next_option = '\0';
> - cpu = atoi(option);
> - if (cpu >= cpus_online)
> - fprintf(stderr, "CPU %d exceeds "
> - "cpus online, ignoring.\n",
> - cpu);
> - else
> - cpus_to_pin[num_cpus_to_pin++] = cpu;
> - if (next_option)
> - option = ++next_option;
> - } while (next_option && num_cpus_to_pin < MAX_CPUS);
> - /* Double check that they didn't give us the same CPU
> - * more than once */
> - for (cpu = 0; cpu < num_cpus_to_pin; cpu++) {
> - if (CPU_ISSET_S(cpus_to_pin[cpu], cpu_set_size,
> - cpu_set)) {
> - fprintf(stderr, "Any given CPU may "
> - "only be given once.\n");
> - exit(1);
> - } else
> - CPU_SET_S(cpus_to_pin[cpu],
> - cpu_set_size, cpu_set);
> - }
> - break;
> - case 'p':
> - /*
> - * Although we can create a msg queue with a
> - * non-absolute path name, unlink will fail. So,
> - * if the name doesn't start with a /, add one
> - * when we save it.
> - */
> - option = queue_path;
> - if (*option != '/') {
> - queue_path = malloc(strlen(option) + 2);
> - if (!queue_path) {
> - perror("malloc()");
> - exit(1);
> - }
> - queue_path[0] = '/';
> - queue_path[1] = 0;
> - strcat(queue_path, option);
> - free(option);
> - }
> - break;
> - }
> - }
> -
> - if (continuous_mode && num_cpus_to_pin == 0) {
> - fprintf(stderr, "Must pass at least one CPU to continuous "
> - "mode.\n");
> - poptPrintUsage(popt_context, stderr, 0);
> - exit(1);
> - } else if (!continuous_mode) {
> - num_cpus_to_pin = 1;
> - cpus_to_pin[0] = cpus_online - 1;
> - }
> -
> - if (getuid() != 0) {
> - fprintf(stderr, "Not running as root, but almost all tests "
> - "require root in order to modify\nsystem settings. "
> - "Exiting.\n");
> - exit(1);
> - }
> -
> - max_msgs = fopen(MAX_MSGS, "r+");
> - max_msgsize = fopen(MAX_MSGSIZE, "r+");
> - if (!max_msgs)
> - shutdown(2, "Failed to open msg_max", __LINE__);
> - if (!max_msgsize)
> - shutdown(2, "Failed to open msgsize_max", __LINE__);
> -
> - /* Load up the current system values for everything we can */
> - getr(RLIMIT_MSGQUEUE, &saved_limits);
> - cur_limits = saved_limits;
> - saved_max_msgs = cur_max_msgs = get(max_msgs);
> - saved_max_msgsize = cur_max_msgsize = get(max_msgsize);
> - errno = 0;
> - cur_nice = getpriority(PRIO_PROCESS, 0);
> - if (errno)
> - shutdown(2, "getpriority()", __LINE__);
> -
> - /* Tell the user our initial state */
> - printf("\nInitial system state:\n");
> - printf("\tUsing queue path:\t\t\t%s\n", queue_path);
> - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
> - (long) saved_limits.rlim_cur);
> - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
> - (long) saved_limits.rlim_max);
> - printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize);
> - printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs);
> - printf("\tNice value:\t\t\t\t%d\n", cur_nice);
> - printf("\n");
> -
> - increase_limits();
> -
> - printf("Adjusted system state for testing:\n");
> - if (cur_limits.rlim_cur == RLIM_INFINITY) {
> - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n");
> - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n");
> - } else {
> - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n",
> - (long) cur_limits.rlim_cur);
> - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n",
> - (long) cur_limits.rlim_max);
> - }
> - printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize);
> - printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs);
> - printf("\tNice value:\t\t\t\t%d\n", cur_nice);
> - printf("\tContinuous mode:\t\t\t(%s)\n", continuous_mode ?
> - (continuous_mode_fake ? "fake mode" : "enabled") :
> - "disabled");
> - printf("\tCPUs to pin:\t\t\t\t%d", cpus_to_pin[0]);
> - for (cpu = 1; cpu < num_cpus_to_pin; cpu++)
> - printf(",%d", cpus_to_pin[cpu]);
> - printf("\n");
> -
> - sa.sa_sigaction = sig_action_SIGUSR1;
> - sigemptyset(&sa.sa_mask);
> - sigaddset(&sa.sa_mask, SIGHUP);
> - sigaddset(&sa.sa_mask, SIGINT);
> - sigaddset(&sa.sa_mask, SIGQUIT);
> - sigaddset(&sa.sa_mask, SIGTERM);
> - sa.sa_flags = SA_SIGINFO;
> - if (sigaction(SIGUSR1, &sa, NULL) == -1)
> - shutdown(1, "sigaction(SIGUSR1)", __LINE__);
> - sa.sa_sigaction = sig_action;
> - if (sigaction(SIGHUP, &sa, NULL) == -1)
> - shutdown(1, "sigaction(SIGHUP)", __LINE__);
> - if (sigaction(SIGINT, &sa, NULL) == -1)
> - shutdown(1, "sigaction(SIGINT)", __LINE__);
> - if (sigaction(SIGQUIT, &sa, NULL) == -1)
> - shutdown(1, "sigaction(SIGQUIT)", __LINE__);
> - if (sigaction(SIGTERM, &sa, NULL) == -1)
> - shutdown(1, "sigaction(SIGTERM)", __LINE__);
> -
> - if (!continuous_mode_fake) {
> - attr.mq_flags = O_NONBLOCK;
> - attr.mq_maxmsg = cur_max_msgs;
> - attr.mq_msgsize = MSG_SIZE;
> - open_queue(&attr);
> - }
> - for (i = 0; i < num_cpus_to_pin; i++) {
> - pthread_attr_t thread_attr;
> - void *thread_func;
> -
> - if (continuous_mode_fake)
> - thread_func = &fake_cont_thread;
> - else if (continuous_mode)
> - thread_func = &cont_thread;
> - else
> - thread_func = &perf_test_thread;
> -
> - CPU_ZERO_S(cpu_set_size, cpu_set);
> - CPU_SET_S(cpus_to_pin[i], cpu_set_size, cpu_set);
> - pthread_attr_init(&thread_attr);
> - pthread_attr_setaffinity_np(&thread_attr, cpu_set_size,
> - cpu_set);
> - if (pthread_create(&cpu_threads[i], &thread_attr, thread_func,
> - NULL))
> - shutdown(1, "pthread_create()", __LINE__);
> - pthread_attr_destroy(&thread_attr);
> - }
> -
> - if (!continuous_mode) {
> - pthread_join(cpu_threads[0], &retval);
> - shutdown((long)retval, "perf_test_thread()", __LINE__);
> - } else {
> - while (1)
> - sleep(1);
> - }
> - shutdown(0, "", 0);
> -}
>

--
Shuah Khan
Sr. Linux Kernel Developer
Open Source Innovation Group
Samsung Research America (Silicon Valley)
shuahkh@osg.samsung.com | (970) 217-8978