[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