[LTP] [PATCH v2] Rewrite msgstress testing suite
Andrea Cervesato
andrea.cervesato@suse.com
Fri May 3 11:11:05 CEST 2024
Hi Cyril,
On 5/2/24 14:34, Cyril Hrubis wrote:
> Hi!
>> msgstress testing suite has been rewritten, taking in consideration
>> that old code was not working most of the times. The new algorithm
>> simply generates new SysV IPC messages, spawning a sender and a
>> receiver which will validate data.
>>
>> With the new algorithm we also reduce the amount of children which
>> we spawn, since we only have 2: sender and receiver. This permits to
>> increase the number of messages to send and to do not be depedent from
>> system overload.
>>
>> Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
>> ---
>> Add iteration option for messages
>>
>> runtest/syscalls | 6 +-
>> runtest/syscalls-ipc | 6 +-
>> .../kernel/syscalls/ipc/msgstress/.gitignore | 3 -
>> .../kernel/syscalls/ipc/msgstress/Makefile | 5 -
>> .../syscalls/ipc/msgstress/msgstress01.c | 455 ++++++++----------
>> .../syscalls/ipc/msgstress/msgstress02.c | 408 ----------------
>> .../syscalls/ipc/msgstress/msgstress03.c | 299 ------------
>> .../syscalls/ipc/msgstress/msgstress04.c | 444 -----------------
>> 8 files changed, 214 insertions(+), 1412 deletions(-)
>> delete mode 100644 testcases/kernel/syscalls/ipc/msgstress/msgstress02.c
>> delete mode 100644 testcases/kernel/syscalls/ipc/msgstress/msgstress03.c
>> delete mode 100644 testcases/kernel/syscalls/ipc/msgstress/msgstress04.c
>>
>> diff --git a/runtest/syscalls b/runtest/syscalls
>> index b9dd9fec6..fabb196be 100644
>> --- a/runtest/syscalls
>> +++ b/runtest/syscalls
>> @@ -864,12 +864,10 @@ msgctl03 msgctl03
>> msgctl04 msgctl04
>> msgctl05 msgctl05
>> msgctl06 msgctl06
>> -msgstress01 msgstress01
>> -msgstress02 msgstress02
>> -msgstress03 msgstress03
>> -msgstress04 msgstress04
>> msgctl12 msgctl12
>>
>> +msgstress01 msgstress01
>> +
>> msgget01 msgget01
>> msgget02 msgget02
>> msgget03 msgget03
>> diff --git a/runtest/syscalls-ipc b/runtest/syscalls-ipc
>> index 9860394de..8960c487c 100644
>> --- a/runtest/syscalls-ipc
>> +++ b/runtest/syscalls-ipc
>> @@ -4,12 +4,10 @@ msgctl03 msgctl03
>> msgctl04 msgctl04
>> msgctl05 msgctl05
>> msgctl06 msgctl06
>> -msgstress01 msgstress01
>> -msgstress02 msgstress02
>> -msgstress03 msgstress03
>> -msgstress04 msgstress04
>> msgctl12 msgctl12
>>
>> +msgstress01 msgstress01
>> +
>> msgget01 msgget01
>> msgget02 msgget02
>> msgget03 msgget03
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/.gitignore b/testcases/kernel/syscalls/ipc/msgstress/.gitignore
>> index a8f675399..fe9780693 100644
>> --- a/testcases/kernel/syscalls/ipc/msgstress/.gitignore
>> +++ b/testcases/kernel/syscalls/ipc/msgstress/.gitignore
>> @@ -1,4 +1 @@
>> /msgstress01
>> -/msgstress02
>> -/msgstress03
>> -/msgstress04
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/Makefile b/testcases/kernel/syscalls/ipc/msgstress/Makefile
>> index b821bda01..442eb87d5 100644
>> --- a/testcases/kernel/syscalls/ipc/msgstress/Makefile
>> +++ b/testcases/kernel/syscalls/ipc/msgstress/Makefile
>> @@ -3,10 +3,5 @@
>>
>> top_srcdir ?= ../../../../..
>>
>> -LTPLIBS = ltpipc
>> -
>> include $(top_srcdir)/include/mk/testcases.mk
>> -
>> -LTPLDLIBS += -lltpipc
>> -
>> include $(top_srcdir)/include/mk/generic_leaf_target.mk
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c
>> index 84e338437..b1bcdf44c 100644
>> --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c
>> +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c
>> @@ -1,301 +1,266 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> /*
>> - * Copyright (c) International Business Machines Corp., 2002
>> - *
>> - * This program 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; either version 2 of the License, or
>> - * (at your option) any later version.
>> - *
>> - * This program 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.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> - *
>> - * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> - * 11/06/2002 Port to LTP dbarrera@us.ibm.com
>> + * Copyright (c) International Business Machines Corp., 2002
>> + * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> + * 11/11/2002 Port to LTP dbarrera@us.ibm.com
>> + * Copyright (C) 2024 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
>> */
>>
>> /*
>> - * Get and manipulate a message queue.
>> + * [Description]
>> + *
>> + * Stress test for SysV IPC. We send multiple messages at the same time,
>> + * checking that we are not loosing any byte once we receive the messages
>> + * from multiple children.
>> + *
>> + * The number of messages to send is determined by the free slots available
>> + * in SysV IPC and the available number of children which can be spawned by
>> + * the process. Each sender will spawn multiple messages at the same time and
>> + * each receiver will read them one by one.
>> */
>>
>> -#define _XOPEN_SOURCE 500
>> -#include <signal.h>
>> -#include <errno.h>
>> -#include <string.h>
>> -#include <fcntl.h>
>> #include <stdlib.h>
>> -#include <stdio.h>
>> -#include <unistd.h>
>> -#include <values.h>
>> -#include <sys/types.h>
>> -#include <sys/wait.h>
>> -#include <sys/stat.h>
>> -#include <sys/ipc.h>
>> -#include <sys/msg.h>
>> -#include "test.h"
>> -#include "ipcmsg.h"
>> -#include "libmsgctl.h"
>> -
>> -char *TCID = "msgstress01";
>> -int TST_TOTAL = 1;
>> -
>> -#ifndef CONFIG_COLDFIRE
>> -#define MAXNPROCS 1000000 /* This value is set to an arbitrary high limit. */
>> -#else
>> -#define MAXNPROCS 100000 /* Coldfire can't deal with 1000000 */
>> -#endif
>> -#define MAXNREPS 100000
>> -
>> -static key_t keyarray[MAXNPROCS];
>> -static int pidarray[MAXNPROCS];
>> -static int tid;
>> -static int MSGMNI, nprocs, nreps;
>> -static int procstat;
>> -static int mykid;
>> -
>> -void setup(void);
>> -void cleanup(void);
>> -
>> -static int dotest(key_t key, int child_process);
>> -static void sig_handler();
>> -
>> -static char *opt_nprocs;
>> -static char *opt_nreps;
>> -
>> -static option_t options[] = {
>> - {"n:", NULL, &opt_nprocs},
>> - {"l:", NULL, &opt_nreps},
>> - {NULL, NULL, NULL},
>> +#include "tst_safe_sysv_ipc.h"
>> +#include "tst_safe_stdio.h"
>> +#include "tst_test.h"
>> +
>> +#define SYSVIPC_TOTAL "/proc/sys/kernel/msgmni"
>> +#define SYSVIPC_USED "/proc/sysvipc/msg"
>> +#define KEY_VAL0 154326L
>> +#define MSGTYPE 10
>> +#define MAXNREPS 100000
>> +
>> +struct sysv_msg {
>> + long type;
>> + struct {
>> + char len;
>> + char pbytes[99];
>> + } data;
>> +};
>> +
>> +struct sysv_data {
>> + int id;
>> + struct sysv_msg msg;
>> };
>>
>> -static void usage(void)
>> +static struct sysv_data *ipc_data;
>> +static int ipc_data_len;
>> +
>> +static char *str_num_messages;
>> +static char *str_num_iterations;
>> +static int num_messages = 1000;
>> +static int num_iterations = MAXNREPS;
>> +static int *failure;
>> +
>> +static int get_used_sysvipc(void)
>> +{
>> + FILE *fp;
>> + int used = -1;
>> + char buf[BUFSIZ];
>> +
>> + fp = SAFE_FOPEN(SYSVIPC_USED, "r");
>> +
>> + while (fgets(buf, BUFSIZ, fp) != NULL)
>> + used++;
>> +
>> + SAFE_FCLOSE(fp);
>> +
>> + if (used < 0)
>> + tst_brk(TBROK, "Can't read %s to get used sysvipc resource", SYSVIPC_USED);
>> +
>> + return used;
>> +}
>> +
>> +static void reset_messages(void)
>> {
>> - printf(" -n Number of processes\n");
>> - printf(" -l Number of iterations\n");
>> + ipc_data_len = 0;
>> + memset(ipc_data, 0, sizeof(struct sysv_data) * num_messages);
>> +
>> + for (int i = 0; i < num_messages; i++)
>> + ipc_data[i].id = -1;
>> }
>>
>> -int main(int argc, char **argv)
>> +static int create_message(const int id)
>> {
>> - int i, j, ok, pid;
>> - int count, status;
>> - struct sigaction act;
>> + int pos = ipc_data_len;
>> + struct sysv_data *buff = ipc_data + pos;
>>
>> - tst_parse_opts(argc, argv, options, usage);
>> + buff->id = id;
>> + buff->msg.type = MSGTYPE;
>> + buff->msg.data.len = (rand() % 99) + 1;
>>
>> - setup();
>> + for (int i = 0; i < buff->msg.data.len; i++)
>> + buff->msg.data.pbytes[i] = rand() % 255;
>>
>> - nreps = MAXNREPS;
>> - nprocs = MSGMNI;
>> + ipc_data_len++;
>>
>> - if (opt_nreps) {
>> - nreps = atoi(opt_nreps);
>> - if (nreps > MAXNREPS) {
>> - tst_resm(TINFO,
>> - "Requested number of iterations too large, "
>> - "setting to Max. of %d", MAXNREPS);
>> - nreps = MAXNREPS;
>> - }
>> - }
>> + return pos;
>> +}
>>
>> - if (opt_nprocs) {
>> - nprocs = atoi(opt_nprocs);
>> - if (nprocs > MSGMNI) {
>> - tst_resm(TINFO,
>> - "Requested number of processes too large, "
>> - "setting to Max. of %d", MSGMNI);
>> - nprocs = MSGMNI;
>> +static void writer(const int id, const int pos)
>> +{
>> + struct sysv_data *buff = &ipc_data[pos];
>> + int iter = num_iterations;
>> +
>> + while (--iter >= 0 && !(*failure))
>> + SAFE_MSGSND(id, &buff->msg, 100, 0);
>> +}
>> +
>> +static void reader(const int id)
>> +{
>> + int size;
>> + int iter = num_iterations;
>> + struct sysv_msg msg_recv;
>> + struct sysv_data *buff = NULL;
>> +
>> + for (int i = 0; i < ipc_data_len; i++) {
>> + if (ipc_data[i].id == id) {
>> + buff = ipc_data + i;
>> + break;
>> }
>> }
>>
>> - srand(getpid());
>> - tid = -1;
>> + if (!buff)
>> + tst_brk(TBROK, "Can't find original message. This is a test issue!");
> Why don't we pass the pos to the reader as well. There is no need to
> lookup anything as long as we pass it there too, right?
>
>> - /* Setup signal handling routine */
>> - memset(&act, 0, sizeof(act));
>> - act.sa_handler = sig_handler;
>> - sigemptyset(&act.sa_mask);
>> - sigaddset(&act.sa_mask, SIGTERM);
>> - if (sigaction(SIGTERM, &act, NULL) < 0) {
>> - tst_brkm(TFAIL, NULL, "Sigset SIGTERM failed");
>> - }
>> - /* Set up array of unique keys for use in allocating message
>> - * queues
>> - */
>> - for (i = 0; i < nprocs; i++) {
>> - ok = 1;
>> - do {
>> - /* Get random key */
>> - keyarray[i] = (key_t) rand();
>> - /* Make sure key is unique and not private */
>> - if (keyarray[i] == IPC_PRIVATE) {
>> - ok = 0;
>> - continue;
>> - }
>> - for (j = 0; j < i; j++) {
>> - if (keyarray[j] == keyarray[i]) {
>> - ok = 0;
>> - break;
>> - }
>> - ok = 1;
>> - }
>> - } while (ok == 0);
>> - }
>> + while (--iter >= 0 && !(*failure)) {
>> + memset(&msg_recv, 0, sizeof(struct sysv_msg));
>>
>> - /* Fork a number of processes, each of which will
>> - * create a message queue with one reader/writer
>> - * pair which will read and write a number (iterations)
>> - * of random length messages with specific values.
>> - */
>> + size = SAFE_MSGRCV(id, &msg_recv, 100, MSGTYPE, 0);
>> +
>> + if (msg_recv.type != buff->msg.type) {
>> + tst_res(TFAIL, "Received the wrong message type");
>>
>> - for (i = 0; i < nprocs; i++) {
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "\tFork failed (may be OK if under stress)");
>> + *failure = 1;
>> + return;
>> }
>> - /* Child does this */
>> - if (pid == 0) {
>> - procstat = 1;
>> - exit(dotest(keyarray[i], i));
>> +
>> + if (msg_recv.data.len != buff->msg.data.len) {
>> + tst_res(TFAIL, "Received the wrong message data length");
>> +
>> + *failure = 1;
>> + return;
>> }
>> - pidarray[i] = pid;
>> - }
>>
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != 0) {
>> - tst_brkm(TFAIL, NULL,
>> - "Child exit status = %d",
>> - status >> 8);
>> - }
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> + for (int i = 0; i < size; i++) {
>> + if (msg_recv.data.pbytes[i] != buff->msg.data.pbytes[i]) {
>> + tst_res(TFAIL, "Received wrong data at index %d: %x != %x", i,
>> + msg_recv.data.pbytes[i],
>> + buff->msg.data.pbytes[i]);
>> +
>> + *failure = 1;
>> + return;
>> }
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Signal detected during wait");
>> -#endif
>> }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != nprocs) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "Wrong number of children exited, Saw %d, Expected %d",
>> - count, nprocs);
>> - }
>>
>> - tst_resm(TPASS, "Test ran successfully!");
>> + tst_res(TDEBUG, "Received correct data");
>> + tst_res(TDEBUG, "msg_recv.type = %ld", msg_recv.type);
>> + tst_res(TDEBUG, "msg_recv.data.len = %d", msg_recv.data.len);
>> + }
>>
>> - cleanup();
>> - tst_exit();
>> + buff->id = -1;
>> }
>>
>> -static int dotest(key_t key, int child_process)
>> +static void run(void)
>> {
>> - int id, pid;
>> - int ret, status;
>> + int id, pos;
>>
>> - sighold(SIGTERM);
>> - TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR));
>> - if (TEST_RETURN < 0) {
>> - printf("msgget() error in child %d: %s\n",
>> - child_process, strerror(TEST_ERRNO));
>> + reset_messages();
>>
>> - return FAIL;
>> - }
>> - tid = id = TEST_RETURN;
>> - sigrelse(SIGTERM);
>> -
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("\tFork failed (may be OK if under stress)\n");
>> - TEST(msgctl(tid, IPC_RMID, 0));
>> - if (TEST_RETURN < 0) {
>> - printf("mscgtl() error in cleanup: %s\n",
>> - strerror(TEST_ERRNO));
>> + for (int i = 0; i < num_messages; i++) {
>> + id = SAFE_MSGGET(KEY_VAL0 + i, IPC_CREAT | 0600);
> ^
> It may be better to pass IPC_PRIVATE
> to let the kernel pick an unique key
>
>> + pos = create_message(id);
>> +
>> + if (!SAFE_FORK()) {
>> + writer(id, pos);
>> + return;
>> }
>> - return FAIL;
>> - }
>> - /* Child does this */
>> - if (pid == 0)
>> - exit(doreader(key, id, 1, child_process, nreps));
>> - /* Parent does this */
>> - mykid = pid;
>> - procstat = 2;
>> - ret = dowriter(key, id, 1, child_process, nreps);
>> - wait(&status);
>> -
>> - if (ret != PASS)
>> - exit(FAIL);
>> -
>> - if ((!WIFEXITED(status) || (WEXITSTATUS(status) != PASS)))
>> - exit(FAIL);
>> -
>> - TEST(msgctl(id, IPC_RMID, 0));
>> - if (TEST_RETURN < 0) {
>> - printf("msgctl() errno %d: %s\n",
>> - TEST_ERRNO, strerror(TEST_ERRNO));
>> -
>> - return FAIL;
>> +
>> + if (!SAFE_FORK()) {
>> + reader(id);
>> + return;
>> + }
>> +
>> + if (*failure)
>> + break;
>> }
>> - return PASS;
>> -}
>>
>> -static void sig_handler(void)
>> -{
>> + if (!(*failure))
>> + tst_res(TPASS, "Test passed. All messages have been received");
> This does not work at all. We have to wait for all the children to
> finish before we look at the failure flag.
>
>> }
>>
>> -void setup(void)
>> +static void setup(void)
>> {
>> - int nr_msgqs;
>> + int total_msg;
>> + int avail_msg;
>> + int free_msgs;
>> + int free_pids;
>>
>> - tst_tmpdir();
>> + srand(time(0));
>>
>> - tst_sig(FORK, DEF_HANDLER, cleanup);
>> + SAFE_FILE_SCANF(SYSVIPC_TOTAL, "%i", &total_msg);
>>
>> - TEST_PAUSE;
>> + free_msgs = total_msg - get_used_sysvipc();
>>
>> - nr_msgqs = get_max_msgqueues();
>> - if (nr_msgqs < 0)
>> - cleanup();
>> + /* We remove 10% of free pids, just to be sure
>> + * we won't saturate the sysyem with processes.
> ^
> t
>> + */
>> + free_pids = tst_get_free_pids() / 2.1;
>>
>> - nr_msgqs -= get_used_msgqueues();
>> - if (nr_msgqs <= 0) {
>> - tst_resm(TBROK,
>> - "Max number of message queues already used, cannot create more.");
>> - cleanup();
>> - }
>> + avail_msg = MIN(free_msgs, free_pids);
>> + if (!avail_msg)
>> + tst_brk(TCONF, "Unavailable messages slots");
>>
>> - /*
>> - * Since msgmni scales to the memory size, it may reach huge values
>> - * that are not necessary for this test.
>> - * That's why we define NR_MSGQUEUES as a high boundary for it.
>> - */
>> - MSGMNI = MIN(nr_msgqs, NR_MSGQUEUES);
>> + tst_res(TINFO, "Available messages slots: %d", avail_msg);
>> +
>> + if (tst_parse_int(str_num_messages, &num_messages, 1, avail_msg))
>> + tst_brk(TBROK, "Invalid number of messages '%s'", str_num_messages);
>> +
>> + if (tst_parse_int(str_num_iterations, &num_iterations, 1, MAXNREPS))
>> + tst_brk(TBROK, "Invalid number of messages iterations '%s'", str_num_iterations);
>> +
>> + ipc_data = SAFE_MMAP(
>> + NULL,
>> + sizeof(struct sysv_data) * num_messages,
>> + PROT_READ | PROT_WRITE,
>> + MAP_SHARED | MAP_ANONYMOUS,
>> + -1, 0);
>> +
>> + failure = SAFE_MMAP(
>> + NULL,
>> + sizeof(int),
>> + PROT_READ | PROT_WRITE,
>> + MAP_SHARED | MAP_ANONYMOUS,
>> + -1, 0);
> Maybe it would be better named stop or something that defines better the
> purpose of the flag.
>
> Also the variable should be declared volatile to make sure that the
> compiler will not mis-compile the access, since it's modified from a
> different thread than read.
The variable is inside a shared memory and mmap() doesn't allow to
create "volatile void*".
>> + reset_messages();
>> }
>>
>> -void cleanup(void)
>> +static void cleanup(void)
>> {
>> - int status;
>> + if (!ipc_data)
>> + return;
>>
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Removing the message queue");
>> -#endif
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) {
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
>> + for (int pos = 0; pos < num_messages; pos++) {
>> + struct sysv_data *buff = &ipc_data[pos];
>>
>> + if (buff->id != -1)
>> + SAFE_MSGCTL(buff->id, IPC_RMID, NULL);
>> }
>>
>> - tst_rmdir();
>> + SAFE_MUNMAP(ipc_data, sizeof(struct sysv_data) * num_messages);
>> + SAFE_MUNMAP(failure, sizeof(int));
>> }
>> +
>> +static struct tst_test test = {
>> + .test_all = run,
>> + .setup = setup,
>> + .cleanup = cleanup,
>> + .forks_child = 1,
>> + .max_runtime = 180,
>> + .options = (struct tst_option[]) {
>> + {"n:", &str_num_messages, "Number of messages to send (default: 1000)"},
>> + {"l:", &str_num_iterations, "Number iterations per message (default: 10000)"},
>> + {},
>> + },
>> +};
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c
>> deleted file mode 100644
>> index a0f894b05..000000000
>> --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c
>> +++ /dev/null
>> @@ -1,408 +0,0 @@
>> -/*
>> - * Copyright (c) International Business Machines Corp., 2002
>> - *
>> - * This program 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; either version 2 of the License, or
>> - * (at your option) any later version.
>> - *
>> - * This program 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.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> - *
>> - * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> - * 11/11/2002 Port to LTP dbarrera@us.ibm.com
>> - */
>> -
>> -/*
>> - * Get and manipulate a message queue.
>> - */
>> -
>> -#define _XOPEN_SOURCE 500
>> -#include <sys/stat.h>
>> -#include <sys/types.h>
>> -#include <sys/ipc.h>
>> -#include <sys/msg.h>
>> -#include <sys/wait.h>
>> -#include <signal.h>
>> -#include <errno.h>
>> -#include <stdio.h>
>> -#include <string.h>
>> -#include <stdlib.h>
>> -#include <unistd.h>
>> -#include "test.h"
>> -#include "ipcmsg.h"
>> -#include "libmsgctl.h"
>> -
>> -char *TCID = "msgstress02";
>> -int TST_TOTAL = 1;
>> -
>> -#define MAXNREPS 1000
>> -#ifndef CONFIG_COLDFIRE
>> -#define MAXNPROCS 1000000 /* This value is set to an arbitrary high limit. */
>> -#else
>> -#define MAXNPROCS 100000 /* Coldfire can't deal with 1000000 */
>> -#endif
>> -#define MAXNKIDS 10
>> -
>> -static key_t keyarray[MAXNPROCS];
>> -static int pidarray[MAXNPROCS];
>> -static int rkidarray[MAXNKIDS];
>> -static int wkidarray[MAXNKIDS];
>> -static int tid;
>> -static int nprocs, nreps, nkids, MSGMNI;
>> -static int procstat;
>> -
>> -void setup(void);
>> -void cleanup(void);
>> -
>> -static void term(int);
>> -static int dotest(key_t, int);
>> -static void cleanup_msgqueue(int i, int tid);
>> -
>> -static char *opt_nprocs;
>> -static char *opt_nkids;
>> -static char *opt_nreps;
>> -
>> -static option_t options[] = {
>> - {"n:", NULL, &opt_nprocs},
>> - {"c:", NULL, &opt_nkids},
>> - {"l:", NULL, &opt_nreps},
>> - {NULL, NULL, NULL},
>> -};
>> -
>> -static void usage(void)
>> -{
>> - printf(" -n Number of processes\n");
>> - printf(" -c Number of read/write child pairs\n");
>> - printf(" -l Number of iterations\n");
>> -}
>> -
>> -int main(int argc, char **argv)
>> -{
>> - int i, j, ok, pid;
>> - int count, status;
>> -
>> - tst_parse_opts(argc, argv, options, usage);
>> -
>> - setup();
>> -
>> - nreps = MAXNREPS;
>> - nprocs = MSGMNI;
>> - nkids = MAXNKIDS;
>> -
>> - if (opt_nreps) {
>> - nreps = atoi(opt_nreps);
>> - if (nreps > MAXNREPS) {
>> - tst_resm(TINFO,
>> - "Requested number of iterations too large, "
>> - "setting to Max. of %d", MAXNREPS);
>> - nreps = MAXNREPS;
>> - }
>> - }
>> -
>> - if (opt_nprocs) {
>> - nprocs = atoi(opt_nprocs);
>> - if (nprocs > MSGMNI) {
>> - tst_resm(TINFO,
>> - "Requested number of processes too large, "
>> - "setting to Max. of %d", MSGMNI);
>> - nprocs = MSGMNI;
>> - }
>> - }
>> -
>> - if (opt_nkids) {
>> - nkids = atoi(opt_nkids);
>> - if (nkids > MAXNKIDS) {
>> - tst_resm(TINFO,
>> - "Requested number of read/write pairs too "
>> - "large, setting to Max. of %d", MAXNKIDS);
>> - nkids = MAXNKIDS;
>> - }
>> - }
>> -
>> - procstat = 0;
>> - srand48((unsigned)getpid() + (unsigned)(getppid() << 16));
>> - tid = -1;
>> -
>> - /* Setup signal handleing routine */
>> - if (sigset(SIGTERM, term) == SIG_ERR) {
>> - tst_brkm(TFAIL, NULL, "Sigset SIGTERM failed");
>> - }
>> - /* Set up array of unique keys for use in allocating message
>> - * queues
>> - */
>> - for (i = 0; i < nprocs; i++) {
>> - ok = 1;
>> - do {
>> - /* Get random key */
>> - keyarray[i] = (key_t) lrand48();
>> - /* Make sure key is unique and not private */
>> - if (keyarray[i] == IPC_PRIVATE) {
>> - ok = 0;
>> - continue;
>> - }
>> - for (j = 0; j < i; j++) {
>> - if (keyarray[j] == keyarray[i]) {
>> - ok = 0;
>> - break;
>> - }
>> - ok = 1;
>> - }
>> - } while (ok == 0);
>> - }
>> - /* Fork a number of processes (nprocs), each of which will
>> - * create a message queue with several (nkids) reader/writer
>> - * pairs which will read and write a number (iterations)
>> - * of random length messages with specific values (keys).
>> - */
>> -
>> - for (i = 0; i < nprocs; i++) {
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "\tFork failed (may be OK if under stress)");
>> - }
>> - /* Child does this */
>> - if (pid == 0) {
>> - procstat = 1;
>> - exit(dotest(keyarray[i], i));
>> - }
>> - pidarray[i] = pid;
>> - }
>> -
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != PASS) {
>> - tst_brkm(TFAIL, NULL,
>> - "Child exit status = %d",
>> - status >> 8);
>> - }
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> - }
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Signal detected during wait");
>> -#endif
>> - }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != nprocs) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "Wrong number of children exited, Saw %d, Expected %d",
>> - count, nprocs);
>> - }
>> -
>> - tst_resm(TPASS, "Test ran successfully!");
>> -
>> - cleanup();
>> - tst_exit();
>> -}
>> -
>> -static void cleanup_msgqueue(int i, int tid)
>> -{
>> - /*
>> - * Decrease the value of i by 1 because it
>> - * is getting incremented even if the fork
>> - * is failing.
>> - */
>> -
>> - i--;
>> - /*
>> - * Kill all children & free message queue.
>> - */
>> - for (; i >= 0; i--) {
>> - (void)kill(rkidarray[i], SIGKILL);
>> - (void)kill(wkidarray[i], SIGKILL);
>> - }
>> -
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - tst_brkm(TFAIL | TERRNO, NULL, "Msgctl error in cleanup");
>> - }
>> -}
>> -
>> -static int dotest(key_t key, int child_process)
>> -{
>> - int id, pid;
>> - int i, count, status, exit_status;
>> -
>> - sighold(SIGTERM);
>> - if ((id = msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR)) < 0) {
>> - printf("msgget() error in child %d: %s\n",
>> - child_process, strerror(errno));
>> - return FAIL;
>> - }
>> - tid = id;
>> - sigrelse(SIGTERM);
>> -
>> - exit_status = PASS;
>> -
>> - for (i = 0; i < nkids; i++) {
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("Fork failure in the first child of child group %d\n",
>> - child_process);
>> - cleanup_msgqueue(i, tid);
>> - return FAIL;
>> - }
>> - /* First child does this */
>> - if (pid == 0) {
>> - procstat = 2;
>> - exit(doreader(key, tid, getpid(),
>> - child_process, nreps));
>> - }
>> - rkidarray[i] = pid;
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("Fork failure in the second child of child group %d\n",
>> - child_process);
>> - /*
>> - * Kill the reader child process
>> - */
>> - (void)kill(rkidarray[i], SIGKILL);
>> -
>> - cleanup_msgqueue(i, tid);
>> - return FAIL;
>> - }
>> - /* Second child does this */
>> - if (pid == 0) {
>> - procstat = 2;
>> - exit(dowriter(key, tid, rkidarray[i],
>> - child_process, nreps));
>> - }
>> - wkidarray[i] = pid;
>> - }
>> - /* Parent does this */
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != PASS) {
>> - printf("Child exit status = %d from child group %d\n",
>> - status >> 8, child_process);
>> - for (i = 0; i < nkids; i++) {
>> - kill(rkidarray[i], SIGTERM);
>> - kill(wkidarray[i], SIGTERM);
>> - }
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - printf("msgctl() error: %s\n",
>> - strerror(errno));
>> - }
>> - return FAIL;
>> - }
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> - }
>> - }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != (nkids * 2)) {
>> - printf("Wrong number of children exited in child group %d, saw %d, expected %d\n",
>> - child_process, count, (nkids * 2));
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - printf("msgctl() error: %s\n", strerror(errno));
>> - }
>> - return FAIL;
>> - }
>> - if (msgctl(id, IPC_RMID, 0) < 0) {
>> - printf("msgctl() failure in child group %d: %s\n",
>> - child_process, strerror(errno));
>> - return FAIL;
>> - }
>> - return exit_status;
>> -}
>> -
>> -static void term(int sig LTP_ATTRIBUTE_UNUSED)
>> -{
>> - int i;
>> -
>> - if (procstat == 0) {
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "SIGTERM signal received, test killing kids");
>> -#endif
>> - for (i = 0; i < nprocs; i++) {
>> - if (pidarray[i] > 0) {
>> - if (kill(pidarray[i], SIGTERM) < 0) {
>> - printf("Kill failed to kill child %d",
>> - i);
>> - exit(FAIL);
>> - }
>> - }
>> - }
>> - return;
>> - }
>> -
>> - if (procstat == 2) {
>> - fflush(stdout);
>> - exit(PASS);
>> - }
>> -
>> - if (tid == -1) {
>> - exit(FAIL);
>> - }
>> - for (i = 0; i < nkids; i++) {
>> - if (rkidarray[i] > 0)
>> - kill(rkidarray[i], SIGTERM);
>> - if (wkidarray[i] > 0)
>> - kill(wkidarray[i], SIGTERM);
>> - }
>> -}
>> -
>> -void setup(void)
>> -{
>> - int nr_msgqs;
>> -
>> - tst_tmpdir();
>> -
>> - tst_sig(FORK, DEF_HANDLER, cleanup);
>> -
>> - TEST_PAUSE;
>> -
>> - nr_msgqs = get_max_msgqueues();
>> - if (nr_msgqs < 0)
>> - cleanup();
>> -
>> - nr_msgqs -= get_used_msgqueues();
>> - if (nr_msgqs <= 0) {
>> - tst_resm(TBROK,
>> - "Max number of message queues already used, cannot create more.");
>> - cleanup();
>> - }
>> -
>> - /*
>> - * Since msgmni scales to the memory size, it may reach huge values
>> - * that are not necessary for this test.
>> - * That's why we define NR_MSGQUEUES as a high boundary for it.
>> - */
>> - MSGMNI = MIN(nr_msgqs, NR_MSGQUEUES);
>> -}
>> -
>> -void cleanup(void)
>> -{
>> - int status;
>> -
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Removing the message queue");
>> -#endif
>> - fflush(stdout);
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) {
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
>> -
>> - }
>> -
>> - fflush(stdout);
>> - tst_rmdir();
>> -}
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c
>> deleted file mode 100644
>> index aa37d9058..000000000
>> --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c
>> +++ /dev/null
>> @@ -1,299 +0,0 @@
>> -/*
>> - * Copyright (c) International Business Machines Corp., 2002
>> - *
>> - * This program 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; either version 2 of the License, or
>> - * (at your option) any later version.
>> - *
>> - * This program 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.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> - *
>> - * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> - * 11/06/2002 Port to LTP dbarrera@us.ibm.com
>> - */
>> -
>> -/*
>> - * Get and manipulate a message queue.
>> - * Same as msgstress01 but gets the actual msgmni value under procfs.
>> - */
>> -
>> -#define _XOPEN_SOURCE 500
>> -#include <signal.h>
>> -#include <errno.h>
>> -#include <string.h>
>> -#include <fcntl.h>
>> -#include <stdlib.h>
>> -#include <stdio.h>
>> -#include <unistd.h>
>> -#include <values.h>
>> -#include <sys/types.h>
>> -#include <sys/wait.h>
>> -#include <sys/stat.h>
>> -#include <sys/ipc.h>
>> -#include <sys/msg.h>
>> -#include "test.h"
>> -#include "ipcmsg.h"
>> -#include "libmsgctl.h"
>> -
>> -char *TCID = "msgstress03";
>> -int TST_TOTAL = 1;
>> -
>> -#define MAXNPROCS 10000 /*These should be sufficient */
>> -#define MAXNREPS 10000 /*Else they srewup the system un-necessarily */
>> -
>> -static key_t keyarray[MAXNPROCS];
>> -static int pidarray[MAXNPROCS];
>> -static int tid;
>> -static int MSGMNI, nprocs, nreps;
>> -static int procstat;
>> -static int mykid;
>> -
>> -void setup(void);
>> -void cleanup(void);
>> -
>> -static int dotest(key_t key, int child_process);
>> -static void sig_handler(int signo);
>> -
>> -static char *opt_nprocs;
>> -static char *opt_nreps;
>> -
>> -static option_t options[] = {
>> - {"n:", NULL, &opt_nprocs},
>> - {"l:", NULL, &opt_nreps},
>> - {NULL, NULL, NULL},
>> -};
>> -
>> -static void usage(void)
>> -{
>> - printf(" -n Number of processes\n");
>> - printf(" -l Number of iterations\n");
>> -}
>> -
>> -int main(int argc, char **argv)
>> -{
>> - int i, j, ok, pid, free_pids;
>> - int count, status;
>> - struct sigaction act;
>> -
>> - tst_parse_opts(argc, argv, options, usage);
>> -
>> - setup();
>> -
>> - nreps = MAXNREPS;
>> - nprocs = MSGMNI;
>> -
>> - if (opt_nreps) {
>> - nreps = atoi(opt_nreps);
>> - if (nreps > MAXNREPS) {
>> - tst_resm(TINFO,
>> - "Requested number of iterations too large, "
>> - "setting to Max. of %d", MAXNREPS);
>> - nreps = MAXNREPS;
>> - }
>> - }
>> -
>> - if (opt_nprocs) {
>> - nprocs = atoi(opt_nprocs);
>> - if (nprocs > MSGMNI) {
>> - tst_resm(TINFO,
>> - "Requested number of processes too large, "
>> - "setting to Max. of %d", MSGMNI);
>> - nprocs = MSGMNI;
>> - }
>> - }
>> -
>> - free_pids = tst_get_free_pids(cleanup);
>> - /* Each forked child forks once, take it into account here. */
>> - if (nprocs * 2 >= free_pids) {
>> - tst_resm(TINFO,
>> - "Requested number of processes higher than limit (%d > %d), "
>> - "setting to %d", nprocs * 2, free_pids, free_pids);
>> - nprocs = free_pids / 2;
>> - }
>> -
>> - srand(getpid());
>> - tid = -1;
>> -
>> - /* Setup signal handling routine */
>> - memset(&act, 0, sizeof(act));
>> - act.sa_handler = sig_handler;
>> - sigemptyset(&act.sa_mask);
>> - sigaddset(&act.sa_mask, SIGTERM);
>> - if (sigaction(SIGTERM, &act, NULL) < 0) {
>> - tst_brkm(TFAIL, NULL, "Sigset SIGTERM failed");
>> - }
>> - /* Set up array of unique keys for use in allocating message
>> - * queues
>> - */
>> - for (i = 0; i < nprocs; i++) {
>> - ok = 1;
>> - do {
>> - /* Get random key */
>> - keyarray[i] = (key_t) rand();
>> - /* Make sure key is unique and not private */
>> - if (keyarray[i] == IPC_PRIVATE) {
>> - ok = 0;
>> - continue;
>> - }
>> - for (j = 0; j < i; j++) {
>> - if (keyarray[j] == keyarray[i]) {
>> - ok = 0;
>> - break;
>> - }
>> - ok = 1;
>> - }
>> - } while (ok == 0);
>> - }
>> -
>> - /* Fork a number of processes, each of which will
>> - * create a message queue with one reader/writer
>> - * pair which will read and write a number (iterations)
>> - * of random length messages with specific values.
>> - */
>> -
>> - for (i = 0; i < nprocs; i++) {
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "\tFork failed (may be OK if under stress)");
>> - }
>> - /* Child does this */
>> - if (pid == 0) {
>> - procstat = 1;
>> - exit(dotest(keyarray[i], i));
>> - }
>> - pidarray[i] = pid;
>> - }
>> -
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != 0) {
>> - tst_brkm(TFAIL, NULL,
>> - "Child exit status = %d",
>> - status >> 8);
>> - }
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> - }
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Signal detected during wait");
>> -#endif
>> - }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != nprocs) {
>> - tst_brkm(TFAIL,
>> - NULL,
>> - "Wrong number of children exited, Saw %d, Expected %d",
>> - count, nprocs);
>> - }
>> -
>> - tst_resm(TPASS, "Test ran successfully!");
>> -
>> - cleanup();
>> - tst_exit();
>> -}
>> -
>> -static int dotest(key_t key, int child_process)
>> -{
>> - int id, pid;
>> - int ret, status;
>> -
>> - sighold(SIGTERM);
>> - TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR));
>> - if (TEST_RETURN < 0) {
>> - printf("msgget() error in child %d: %s\n",
>> - child_process, strerror(TEST_ERRNO));
>> - return FAIL;
>> - }
>> - tid = id = TEST_RETURN;
>> - sigrelse(SIGTERM);
>> -
>> - fflush(stdout);
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("Fork failed (may be OK if under stress)\n");
>> - TEST(msgctl(tid, IPC_RMID, 0));
>> - if (TEST_RETURN < 0) {
>> - printf("msgctl() error in cleanup: %s\n",
>> - strerror(TEST_ERRNO));
>> - }
>> - return FAIL;
>> - }
>> - if (pid == 0)
>> - exit(doreader(key, id, 1, child_process, nreps));
>> -
>> - mykid = pid;
>> - procstat = 2;
>> - ret = dowriter(key, id, 1, child_process, nreps);
>> - wait(&status);
>> -
>> - if (ret != PASS)
>> - exit(FAIL);
>> -
>> - if ((!WIFEXITED(status) || (WEXITSTATUS(status) != PASS)))
>> - exit(FAIL);
>> -
>> - TEST(msgctl(id, IPC_RMID, 0));
>> - if (TEST_RETURN < 0) {
>> - printf("msgctl() failed: %s\n",
>> - strerror(TEST_ERRNO));
>> - return FAIL;
>> - }
>> - return PASS;
>> -}
>> -
>> -static void sig_handler(int signo LTP_ATTRIBUTE_UNUSED)
>> -{
>> -}
>> -
>> -void setup(void)
>> -{
>> - int nr_msgqs;
>> -
>> - tst_tmpdir();
>> -
>> - tst_sig(FORK, DEF_HANDLER, cleanup);
>> -
>> - TEST_PAUSE;
>> -
>> - nr_msgqs = get_max_msgqueues();
>> - if (nr_msgqs < 0)
>> - cleanup();
>> -
>> - MSGMNI = nr_msgqs - get_used_msgqueues();
>> - if (MSGMNI > MAXNPROCS)
>> - MSGMNI = MAXNPROCS;
>> - if (MSGMNI <= 0) {
>> - tst_resm(TBROK,
>> - "Max number of message queues already used, cannot create more.");
>> - cleanup();
>> - }
>> -}
>> -
>> -void cleanup(void)
>> -{
>> - int status;
>> -
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Removing the message queue");
>> -#endif
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) {
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
>> -
>> - }
>> -
>> - tst_rmdir();
>> -}
>> diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress04.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress04.c
>> deleted file mode 100644
>> index b9ebf9035..000000000
>> --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress04.c
>> +++ /dev/null
>> @@ -1,444 +0,0 @@
>> -/*
>> - * Copyright (c) International Business Machines Corp., 2002
>> - *
>> - * This program 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; either version 2 of the License, or
>> - * (at your option) any later version.
>> - *
>> - * This program 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.
>> - *
>> - * You should have received a copy of the GNU General Public License
>> - * along with this program; if not, write to the Free Software
>> - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>> - *
>> - * 06/30/2001 Port to Linux nsharoff@us.ibm.com
>> - * 11/11/2002 Port to LTP dbarrera@us.ibm.com
>> - */
>> -
>> -/*
>> - * Get and manipulate a message queue.
>> - * Same as msgstress02 but gets the actual msgmni value under procfs.
>> - */
>> -
>> -#define _XOPEN_SOURCE 500
>> -#include <sys/stat.h>
>> -#include <sys/types.h>
>> -#include <sys/ipc.h>
>> -#include <sys/msg.h>
>> -#include <sys/wait.h>
>> -#include <signal.h>
>> -#include <errno.h>
>> -#include <stdio.h>
>> -#include <string.h>
>> -#include <stdlib.h>
>> -#include <unistd.h>
>> -#include "test.h"
>> -#include "ipcmsg.h"
>> -#include "libmsgctl.h"
>> -
>> -char *TCID = "msgstress04";
>> -int TST_TOTAL = 1;
>> -
>> -#define MAXNREPS 1000
>> -#ifndef CONFIG_COLDFIRE
>> -#define MAXNPROCS 1000000 /* This value is set to an arbitrary high limit. */
>> -#else
>> -#define MAXNPROCS 100000 /* Coldfire can't deal with 1000000 */
>> -#endif
>> -#define MAXNKIDS 10
>> -#define DEFNKIDS 2
>> -
>> -static int maxnkids = MAXNKIDS; /* Used if pid_max is exceeded */
>> -static key_t keyarray[MAXNPROCS];
>> -static int pidarray[MAXNPROCS];
>> -static int rkidarray[MAXNKIDS];
>> -static int wkidarray[MAXNKIDS];
>> -static int tid;
>> -static int nprocs, nreps, nkids, MSGMNI;
>> -static int maxnprocs;
>> -static int procstat;
>> -
>> -void setup(void);
>> -void cleanup(void);
>> -
>> -static void term(int);
>> -static int dotest(key_t, int);
>> -static void dotest_iteration(int off);
>> -static void cleanup_msgqueue(int i, int tid);
>> -
>> -static char *opt_maxnprocs;
>> -static char *opt_nkids;
>> -static char *opt_nreps;
>> -
>> -static option_t options[] = {
>> - {"n:", NULL, &opt_maxnprocs},
>> - {"c:", NULL, &opt_nkids},
>> - {"l:", NULL, &opt_nreps},
>> - {NULL, NULL, NULL},
>> -};
>> -
>> -static void usage(void)
>> -{
>> - printf(" -n Number of processes\n");
>> - printf(" -c Number of read/write child pairs\n");
>> - printf(" -l Number of iterations\n");
>> -}
>> -
>> -
>> -int main(int argc, char **argv)
>> -{
>> - int i, j, ok;
>> -
>> - tst_parse_opts(argc, argv, options, usage);
>> -
>> - setup();
>> -
>> - nreps = MAXNREPS;
>> - nkids = MAXNKIDS;
>> -
>> - if (opt_nreps) {
>> - nreps = atoi(opt_nreps);
>> - if (nreps > MAXNREPS) {
>> - tst_resm(TINFO,
>> - "Requested number of iterations too large, "
>> - "setting to Max. of %d", MAXNREPS);
>> - nreps = MAXNREPS;
>> - }
>> - }
>> -
>> - if (opt_nkids) {
>> - nkids = atoi(opt_nkids);
>> - if (nkids > MAXNKIDS) {
>> - tst_resm(TINFO,
>> - "Requested number of read/write pairs too "
>> - "large, setting to Max. of %d", MAXNKIDS);
>> - nkids = MAXNKIDS;
>> - }
>> - }
>> -
>> -
>> - if (opt_maxnprocs) {
>> - if (atoi(opt_maxnprocs) > maxnprocs) {
>> - tst_resm(TINFO,
>> - "Requested number of processes too large, "
>> - "setting to Max. of %d", MSGMNI);
>> - } else {
>> - maxnprocs = atoi(opt_maxnprocs);
>> - }
>> - }
>> -
>> - procstat = 0;
>> - srand48((unsigned)getpid() + (unsigned)(getppid() << 16));
>> - tid = -1;
>> -
>> - /* Setup signal handling routine */
>> - if (sigset(SIGTERM, term) == SIG_ERR)
>> - tst_brkm(TFAIL, cleanup, "Sigset SIGTERM failed");
>> -
>> - /* Set up array of unique keys for use in allocating message
>> - * queues
>> - */
>> - for (i = 0; i < MSGMNI; i++) {
>> - ok = 1;
>> - do {
>> - /* Get random key */
>> - keyarray[i] = (key_t) lrand48();
>> - /* Make sure key is unique and not private */
>> - if (keyarray[i] == IPC_PRIVATE) {
>> - ok = 0;
>> - continue;
>> - }
>> - for (j = 0; j < i; j++) {
>> - if (keyarray[j] == keyarray[i]) {
>> - ok = 0;
>> - break;
>> - }
>> - ok = 1;
>> - }
>> - } while (ok == 0);
>> - }
>> - /* Fork a number of processes, each of which will
>> - * create a message queue with several (nkids) reader/writer
>> - * pairs which will read and write a number (iterations)
>> - * of random length messages with specific values (keys).
>> - *
>> - * We do not fork more than maxnprocs at a time and
>> - * we fork until all the message queues get used.
>> - */
>> -
>> - if (MSGMNI <= maxnprocs) {
>> - nprocs = MSGMNI;
>> - dotest_iteration(0);
>> - } else {
>> - for (i = 0; i < (MSGMNI / maxnprocs); i++) {
>> - nprocs = maxnprocs;
>> - dotest_iteration(i * maxnprocs);
>> - }
>> -
>> - nprocs = MSGMNI % maxnprocs;
>> - dotest_iteration(i * maxnprocs);
>> - }
>> -
>> - tst_resm(TPASS, "Test ran successfully!");
>> -
>> - cleanup();
>> - tst_exit();
>> -}
>> -
>> -static void dotest_iteration(int off)
>> -{
>> - key_t key;
>> - int i, count, status;
>> - pid_t pid;
>> -
>> - memset(pidarray, 0, sizeof(pidarray));
>> -
>> - for (i = 0; i < nprocs; i++) {
>> - key = keyarray[off + i];
>> -
>> - if ((pid = FORK_OR_VFORK()) < 0)
>> - tst_brkm(TFAIL, cleanup,
>> - "Fork failed (may be OK if under stress)");
>> -
>> - /* Child does this */
>> - if (pid == 0) {
>> - procstat = 1;
>> - exit(dotest(key, i));
>> - }
>> - pidarray[i] = pid;
>> - }
>> -
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != PASS)
>> - tst_brkm(TFAIL, cleanup,
>> - "Child exit status = %d", status >> 8);
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> - }
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Signal detected during wait");
>> -#endif
>> - }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != nprocs)
>> - tst_brkm(TFAIL, cleanup,
>> - "Wrong number of children exited, Saw %d, Expected %d",
>> - count, nprocs);
>> -}
>> -
>> -static void cleanup_msgqueue(int i, int tid)
>> -{
>> - /*
>> - * Decrease the value of i by 1 because it
>> - * is getting incremented even if the fork
>> - * is failing.
>> - */
>> -
>> - i--;
>> - /*
>> - * Kill all children & free message queue.
>> - */
>> - for (; i >= 0; i--) {
>> - (void)kill(rkidarray[i], SIGKILL);
>> - (void)kill(wkidarray[i], SIGKILL);
>> - }
>> -
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - printf("Msgctl error in cleanup_msgqueue %d\n", errno);
>> - exit(FAIL);
>> - }
>> -}
>> -
>> -static int dotest(key_t key, int child_process)
>> -{
>> - int id, pid;
>> - int i, count, status, exit_status;
>> -
>> - sighold(SIGTERM);
>> - if ((id = msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR)) < 0) {
>> - printf("msgget() error in child %d: %s\n",
>> - child_process, strerror(errno));
>> - return FAIL;
>> - }
>> - tid = id;
>> - sigrelse(SIGTERM);
>> -
>> - exit_status = PASS;
>> -
>> - for (i = 0; i < nkids; i++) {
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("Fork failure in the first child of child group %d\n",
>> - child_process);
>> - cleanup_msgqueue(i, tid);
>> - return FAIL;
>> - }
>> - /* First child does this */
>> - if (pid == 0) {
>> - procstat = 2;
>> - exit(doreader(key, tid, getpid(),
>> - child_process, nreps));
>> - }
>> - rkidarray[i] = pid;
>> - if ((pid = FORK_OR_VFORK()) < 0) {
>> - printf("Fork failure in the second child of child group %d\n",
>> - child_process);
>> - /*
>> - * Kill the reader child process
>> - */
>> - (void)kill(rkidarray[i], SIGKILL);
>> -
>> - cleanup_msgqueue(i, tid);
>> - return FAIL;
>> - }
>> - /* Second child does this */
>> - if (pid == 0) {
>> - procstat = 2;
>> - exit(dowriter(key, tid, rkidarray[i],
>> - child_process, nreps));
>> - }
>> - wkidarray[i] = pid;
>> - }
>> - /* Parent does this */
>> - count = 0;
>> - while (1) {
>> - if ((wait(&status)) > 0) {
>> - if (status >> 8 != PASS) {
>> - printf("Child exit status = %d from child group %d\n",
>> - status >> 8, child_process);
>> - for (i = 0; i < nkids; i++) {
>> - kill(rkidarray[i], SIGTERM);
>> - kill(wkidarray[i], SIGTERM);
>> - }
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - printf("msgctl() error: %s\n",
>> - strerror(errno));
>> - }
>> - return FAIL;
>> - }
>> - count++;
>> - } else {
>> - if (errno != EINTR) {
>> - break;
>> - }
>> - }
>> - }
>> - /* Make sure proper number of children exited */
>> - if (count != (nkids * 2)) {
>> - printf("Wrong number of children exited in child group %d, saw %d, expected %d\n",
>> - child_process, count, (nkids * 2));
>> - if (msgctl(tid, IPC_RMID, 0) < 0) {
>> - printf("msgctl() error: %s\n", strerror(errno));
>> - }
>> - return FAIL;
>> - }
>> - if (msgctl(id, IPC_RMID, 0) < 0) {
>> - printf("msgctl() failure in child group %d: %s\n",
>> - child_process, strerror(errno));
>> - return FAIL;
>> - }
>> - return exit_status;
>> -}
>> -
>> -/* ARGSUSED */
>> -static void term(int sig LTP_ATTRIBUTE_UNUSED)
>> -{
>> - int i;
>> -
>> - if (procstat == 0) {
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "SIGTERM signal received, test killing kids");
>> -#endif
>> - for (i = 0; i < nprocs; i++) {
>> - if (pidarray[i] > 0) {
>> - if (kill(pidarray[i], SIGTERM) < 0) {
>> - tst_resm(TBROK,
>> - "Kill failed to kill child %d",
>> - i);
>> - exit(FAIL);
>> - }
>> - }
>> - }
>> - return;
>> - }
>> -
>> - if (procstat == 2) {
>> - exit(PASS);
>> - }
>> -
>> - if (tid == -1) {
>> - exit(FAIL);
>> - }
>> - for (i = 0; i < nkids; i++) {
>> - if (rkidarray[i] > 0)
>> - kill(rkidarray[i], SIGTERM);
>> - if (wkidarray[i] > 0)
>> - kill(wkidarray[i], SIGTERM);
>> - }
>> -}
>> -
>> -void setup(void)
>> -{
>> - int nr_msgqs, free_pids;
>> -
>> - tst_tmpdir();
>> - /* You will want to enable some signal handling so you can capture
>> - * unexpected signals like SIGSEGV.
>> - */
>> - tst_sig(FORK, DEF_HANDLER, cleanup);
>> -
>> - /* One cavet that hasn't been fixed yet. TEST_PAUSE contains the code to
>> - * fork the test with the -c option. You want to make sure you do this
>> - * before you create your temporary directory.
>> - */
>> - TEST_PAUSE;
>> -
>> - nr_msgqs = get_max_msgqueues();
>> - if (nr_msgqs < 0)
>> - tst_brkm(TBROK, cleanup, "get_max_msgqueues() failed");
>> -
>> - MSGMNI = nr_msgqs - get_used_msgqueues();
>> - if (MSGMNI <= 0)
>> - tst_brkm(TBROK, cleanup,
>> - "Max number of message queues already used, cannot create more.");
>> -
>> - tst_resm(TINFO, "Found %d available message queues", MSGMNI);
>> -
>> - free_pids = tst_get_free_pids(cleanup);
>> - /* We don't use more than a half of available pids.
>> - * For each child we fork up to 2*maxnkids grandchildren. */
>> - maxnprocs = (free_pids / 2) / (1 + 2 * maxnkids);
>> -
>> - if (!maxnprocs)
>> - tst_brkm(TBROK, cleanup, "Not enough free pids");
>> -
>> - tst_resm(TINFO, "Using upto %d pids", free_pids / 2);
>> -}
>> -
>> -void cleanup(void)
>> -{
>> - int status;
>> -
>> - /*
>> - * Remove the message queue from the system
>> - */
>> -#ifdef DEBUG
>> - tst_resm(TINFO, "Removing the message queue");
>> -#endif
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) {
>> - (void)msgctl(tid, IPC_RMID, NULL);
>> - tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
>> -
>> - }
>> -
>> - tst_rmdir();
>> -}
>> --
>> 2.35.3
>>
>>
>> --
>> Mailing list info: https://lists.linux.it/listinfo/ltp
Andrea
More information about the ltp
mailing list