Home | History | Annotate | Download | only in msgctl
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2002
      3  *
      4  * This program is free software;  you can redistribute it and/or modify
      5  * it under the terms of the GNU General Public License as published by
      6  * the Free Software Foundation; either version 2 of the License, or
      7  * (at your option) any later version.
      8  *
      9  * This program is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     12  * the GNU General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU General Public License
     15  * along with this program;  if not, write to the Free Software
     16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     17  *
     18  * 06/30/2001   Port to Linux   nsharoff (at) us.ibm.com
     19  * 11/06/2002   Port to LTP     dbarrera (at) us.ibm.com
     20  */
     21 
     22 /*
     23  * Get and manipulate a message queue.
     24  * Same as msgctl08 but gets the actual msgmni value under procfs.
     25  */
     26 
     27 #define _XOPEN_SOURCE 500
     28 #include <signal.h>
     29 #include <errno.h>
     30 #include <string.h>
     31 #include <fcntl.h>
     32 #include <stdlib.h>
     33 #include <stdio.h>
     34 #include <unistd.h>
     35 #include <values.h>
     36 #include <sys/types.h>
     37 #include <sys/wait.h>
     38 #include <sys/stat.h>
     39 #include <sys/ipc.h>
     40 #include <sys/msg.h>
     41 #include "test.h"
     42 #include "ipcmsg.h"
     43 #include "../lib/libmsgctl.h"
     44 
     45 char *TCID = "msgctl10";
     46 int TST_TOTAL = 1;
     47 
     48 #define MAXNPROCS	10000	/*These should be sufficient */
     49 #define MAXNREPS	10000	/*Else they srewup the system un-necessarily */
     50 
     51 static key_t keyarray[MAXNPROCS];
     52 static int pidarray[MAXNPROCS];
     53 static int tid;
     54 static int MSGMNI, nprocs, nreps;
     55 static int procstat;
     56 static int mykid;
     57 
     58 void setup(void);
     59 void cleanup(void);
     60 
     61 static int dotest(key_t key, int child_process);
     62 static void sig_handler(int signo);
     63 
     64 static char *opt_nprocs;
     65 static char *opt_nreps;
     66 
     67 static option_t options[] = {
     68 	{"n:", NULL, &opt_nprocs},
     69 	{"l:", NULL, &opt_nreps},
     70 	{NULL, NULL, NULL},
     71 };
     72 
     73 static void usage(void)
     74 {
     75 	printf("  -n      Number of processes\n");
     76 	printf("  -l      Number of iterations\n");
     77 }
     78 
     79 int main(int argc, char **argv)
     80 {
     81 	int i, j, ok, pid;
     82 	int count, status;
     83 	struct sigaction act;
     84 
     85 	tst_parse_opts(argc, argv, options, usage);
     86 
     87 	setup();
     88 
     89 	nreps = MAXNREPS;
     90 	nprocs = MSGMNI;
     91 
     92 	if (opt_nreps) {
     93 		nreps = atoi(opt_nreps);
     94 		if (nreps > MAXNREPS) {
     95 			tst_resm(TINFO,
     96 				 "Requested number of iterations too large, "
     97 				 "setting to Max. of %d", MAXNREPS);
     98 			nreps = MAXNREPS;
     99 		}
    100 	}
    101 
    102 	if (opt_nprocs) {
    103 		nprocs = atoi(opt_nprocs);
    104 		if (nprocs > MSGMNI) {
    105 			tst_resm(TINFO,
    106 				 "Requested number of processes too large, "
    107 				 "setting to Max. of %d", MSGMNI);
    108 			nprocs = MSGMNI;
    109 		}
    110 	}
    111 
    112 	srand(getpid());
    113 	tid = -1;
    114 
    115 	/* Setup signal handling routine */
    116 	memset(&act, 0, sizeof(act));
    117 	act.sa_handler = sig_handler;
    118 	sigemptyset(&act.sa_mask);
    119 	sigaddset(&act.sa_mask, SIGTERM);
    120 	if (sigaction(SIGTERM, &act, NULL) < 0) {
    121 		tst_brkm(TFAIL, NULL, "Sigset SIGTERM failed");
    122 	}
    123 	/* Set up array of unique keys for use in allocating message
    124 	 * queues
    125 	 */
    126 	for (i = 0; i < nprocs; i++) {
    127 		ok = 1;
    128 		do {
    129 			/* Get random key */
    130 			keyarray[i] = (key_t) rand();
    131 			/* Make sure key is unique and not private */
    132 			if (keyarray[i] == IPC_PRIVATE) {
    133 				ok = 0;
    134 				continue;
    135 			}
    136 			for (j = 0; j < i; j++) {
    137 				if (keyarray[j] == keyarray[i]) {
    138 					ok = 0;
    139 					break;
    140 				}
    141 				ok = 1;
    142 			}
    143 		} while (ok == 0);
    144 	}
    145 
    146 	/* Fork a number of processes, each of which will
    147 	 * create a message queue with one reader/writer
    148 	 * pair which will read and write a number (iterations)
    149 	 * of random length messages with specific values.
    150 	 */
    151 
    152 	for (i = 0; i < nprocs; i++) {
    153 		fflush(stdout);
    154 		if ((pid = FORK_OR_VFORK()) < 0) {
    155 			tst_brkm(TFAIL,
    156 				 NULL,
    157 				 "\tFork failed (may be OK if under stress)");
    158 		}
    159 		/* Child does this */
    160 		if (pid == 0) {
    161 			procstat = 1;
    162 			exit(dotest(keyarray[i], i));
    163 		}
    164 		pidarray[i] = pid;
    165 	}
    166 
    167 	count = 0;
    168 	while (1) {
    169 		if ((wait(&status)) > 0) {
    170 			if (status >> 8 != 0) {
    171 				tst_brkm(TFAIL, NULL,
    172 					 "Child exit status = %d",
    173 					 status >> 8);
    174 			}
    175 			count++;
    176 		} else {
    177 			if (errno != EINTR) {
    178 				break;
    179 			}
    180 #ifdef DEBUG
    181 			tst_resm(TINFO, "Signal detected during wait");
    182 #endif
    183 		}
    184 	}
    185 	/* Make sure proper number of children exited */
    186 	if (count != nprocs) {
    187 		tst_brkm(TFAIL,
    188 			 NULL,
    189 			 "Wrong number of children exited, Saw %d, Expected %d",
    190 			 count, nprocs);
    191 	}
    192 
    193 	tst_resm(TPASS, "msgctl10 ran successfully!");
    194 
    195 	cleanup();
    196 	tst_exit();
    197 }
    198 
    199 static int dotest(key_t key, int child_process)
    200 {
    201 	int id, pid;
    202 	int ret, status;
    203 
    204 	sighold(SIGTERM);
    205 	TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR));
    206 	if (TEST_RETURN < 0) {
    207 		printf("msgget() error in child %d: %s\n",
    208 			child_process, strerror(TEST_ERRNO));
    209 		return FAIL;
    210 	}
    211 	tid = id = TEST_RETURN;
    212 	sigrelse(SIGTERM);
    213 
    214 	fflush(stdout);
    215 	if ((pid = FORK_OR_VFORK()) < 0) {
    216 		printf("Fork failed (may be OK if under stress)\n");
    217 		TEST(msgctl(tid, IPC_RMID, 0));
    218 		if (TEST_RETURN < 0) {
    219 			printf("msgctl() error in cleanup: %s\n",
    220 				strerror(TEST_ERRNO));
    221 		}
    222 		return FAIL;
    223 	}
    224 	if (pid == 0)
    225 		exit(doreader(key, id, 1, child_process, nreps));
    226 
    227 	mykid = pid;
    228 	procstat = 2;
    229 	ret = dowriter(key, id, 1, child_process, nreps);
    230 	wait(&status);
    231 
    232 	if (ret != PASS)
    233 		exit(FAIL);
    234 
    235 	if ((!WIFEXITED(status) || (WEXITSTATUS(status) != PASS)))
    236 		exit(FAIL);
    237 
    238 	TEST(msgctl(id, IPC_RMID, 0));
    239 	if (TEST_RETURN < 0) {
    240 		printf("msgctl() failed: %s\n",
    241 			strerror(TEST_ERRNO));
    242 		return FAIL;
    243 	}
    244 	return PASS;
    245 }
    246 
    247 static void sig_handler(int signo LTP_ATTRIBUTE_UNUSED)
    248 {
    249 }
    250 
    251 void setup(void)
    252 {
    253 	int nr_msgqs;
    254 
    255 	tst_tmpdir();
    256 
    257 	tst_sig(FORK, DEF_HANDLER, cleanup);
    258 
    259 	TEST_PAUSE;
    260 
    261 	nr_msgqs = get_max_msgqueues();
    262 	if (nr_msgqs < 0)
    263 		cleanup();
    264 
    265 	MSGMNI = nr_msgqs - get_used_msgqueues();
    266 	if (MSGMNI > MAXNPROCS)
    267 		MSGMNI = MAXNPROCS;
    268 	if (MSGMNI <= 0) {
    269 		tst_resm(TBROK,
    270 			 "Max number of message queues already used, cannot create more.");
    271 		cleanup();
    272 	}
    273 }
    274 
    275 void cleanup(void)
    276 {
    277 	int status;
    278 
    279 #ifdef DEBUG
    280 	tst_resm(TINFO, "Removing the message queue");
    281 #endif
    282 	(void)msgctl(tid, IPC_RMID, NULL);
    283 	if ((status = msgctl(tid, IPC_STAT, NULL)) != -1) {
    284 		(void)msgctl(tid, IPC_RMID, NULL);
    285 		tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed");
    286 
    287 	}
    288 
    289 	tst_rmdir();
    290 }
    291