Since msgmni now scales to the memory size, it may reach big values. To avoid forking 2*msgmni processes and create msgmni msg queues, take the min between the procfs value and MSGMNI (as found in linux/msg.h). Also fixed the Makefiles in ipc/lib and ipc/msgctl: there was no dependency on the lib/ipc*.h header files. Also integrated the following in libipc.a: . get_max_msgqueues() . get_used_msgqueues() Signed-off-by: Nadia Derbey --- testcases/kernel/syscalls/ipc/lib/Makefile | 3 testcases/kernel/syscalls/ipc/lib/ipcmsg.h | 7 testcases/kernel/syscalls/ipc/lib/libipc.c | 54 + testcases/kernel/syscalls/ipc/msgctl/Makefile | 3 testcases/kernel/syscalls/ipc/msgctl/msgctl08.c | 63 -- testcases/kernel/syscalls/ipc/msgctl/msgctl09.c | 62 -- testcases/kernel/syscalls/ipc/msgctl/msgctl10.c | 527 ++++++++++++++++++ testcases/kernel/syscalls/ipc/msgctl/msgctl11.c | 696 ++++++++++++++++++++++++ testcases/kernel/syscalls/ipc/msgget/Makefile | 3 testcases/kernel/syscalls/ipc/msgget/msgget03.c | 22 10 files changed, 1326 insertions(+), 114 deletions(-) Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/ipcmsg.h =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/lib/ipcmsg.h 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/ipcmsg.h 2008-02-21 14:09:00.000000000 +0100 @@ -41,6 +41,10 @@ void setup(void); #define MSGSIZE 1024 /* a resonable size for a message */ #define MSGTYPE 1 /* a type ID for a message */ +#define NR_MSGQUEUES 16 /* MSGMNI as defined in linux/msg.h */ + +#define min(a, b) (((a) < (b)) ? (a) : (b)) + typedef struct mbuf { /* a generic message structure */ long mtype; char mtext[MSGSIZE + 1]; /* add 1 here so the message can be 1024 */ @@ -59,4 +63,7 @@ void rm_queue(int); int getipckey(); int getuserid(char *); +int get_max_msgqueues(void); +int get_used_msgqueues(void); + #endif /* ipcmsg.h */ Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/libipc.c =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/lib/libipc.c 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/libipc.c 2008-02-21 13:35:41.000000000 +0100 @@ -201,3 +201,57 @@ rm_shm(int shm_id) tst_resm(TINFO, "id = %d", shm_id); } } + +#define BUFSIZE 512 + +/* + * Get the number of message queues already in use + */ +int +get_used_msgqueues() +{ + FILE *f; + int used_queues; + char buff[BUFSIZE]; + + f = popen("ipcs -q", "r"); + if (!f) { + tst_resm(TBROK, "Could not run 'ipcs' to calculate used " + "message queues"); + tst_exit(); + } + /* FIXME: Start at -4 because ipcs prints four lines of header */ + for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++) + ; + pclose(f); + if (used_queues < 0) { + tst_resm(TBROK, "Could not read output of 'ipcs' to " + "calculate used message queues"); + tst_exit(); + } + return used_queues; +} + +/* + * Get the max number of message queues allowed on system + */ +int +get_max_msgqueues() +{ + FILE *f; + char buff[BUFSIZE]; + + /* Get the max number of message queues allowed on system */ + f = fopen("/proc/sys/kernel/msgmni", "r"); + if (!f) { + tst_resm(TBROK, "Could not open /proc/sys/kernel/msgmni"); + return -1; + } + if (!fgets(buff, BUFSIZE, f)) { + fclose(f); + tst_resm(TBROK, "Could not read /proc/sys/kernel/msgmni"); + return -1; + } + fclose(f); + return atoi(buff); +} Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl08.c =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/msgctl/msgctl08.c 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl08.c 2008-02-21 14:18:23.000000000 +0100 @@ -50,6 +50,7 @@ #include #include "test.h" #include "usctest.h" +#include "ipcmsg.h" void setup(); void cleanup(); @@ -454,57 +455,14 @@ sig_handler() { } -#define BUFSIZE 512 - -/** Get the number of message queues already in use */ -static int get_used_msgqueues() -{ - FILE *f; - int used_queues; - char buff[BUFSIZE]; - - f = popen("ipcs -q", "r"); - if (!f) { - tst_resm(TBROK,"Could not run 'ipcs' to calculate used message queues"); - tst_exit(); - } - /* FIXME: Start at -4 because ipcs prints four lines of header */ - for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++) - ; - pclose(f); - if (used_queues < 0) { - tst_resm(TBROK,"Could not read output of 'ipcs' to calculate used message queues"); - tst_exit(); - } - return used_queues; -} - -/** Get the max number of message queues allowed on system */ -static int get_max_msgqueues() -{ - FILE *f; - char buff[BUFSIZE]; - - /* Get the max number of message queues allowed on system */ - f = fopen("/proc/sys/kernel/msgmni", "r"); - if (!f){ - tst_resm(TBROK,"Could not open /proc/sys/kernel/msgmni"); - tst_exit(); - } - if (!fgets(buff, BUFSIZE, f)) { - tst_resm(TBROK,"Could not read /proc/sys/kernel/msgmni"); - tst_exit(); - } - fclose(f); - return atoi(buff); -} - /*************************************************************** * setup() - performs all ONE TIME setup for this test. *****************************************************************/ void setup() { + int nr_msgqs; + tst_tmpdir(); /* You will want to enable some signal handling so you can capture @@ -520,11 +478,22 @@ setup() */ TEST_PAUSE; - MSGMNI = get_max_msgqueues() - get_used_msgqueues(); - if (MSGMNI <= 0){ + 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); } Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl09.c =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/msgctl/msgctl09.c 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl09.c 2008-02-21 13:38:42.000000000 +0100 @@ -49,6 +49,7 @@ #include #include "test.h" #include "usctest.h" +#include "ipcmsg.h" #define MAXNREPS 1000 #ifndef CONFIG_COLDFIRE @@ -624,57 +625,14 @@ term(int sig) } } -#define BUFSIZE 512 - -/** Get the number of message queues already in use */ -static int get_used_msgqueues() -{ - FILE *f; - int used_queues; - char buff[BUFSIZE]; - - f = popen("ipcs -q", "r"); - if (!f) { - tst_resm(TBROK,"Could not run 'ipcs' to calculate used message queues"); - tst_exit(); - } - /* FIXME: Start at -4 because ipcs prints four lines of header */ - for (used_queues = -4; fgets(buff, BUFSIZE, f); used_queues++) - ; - pclose(f); - if (used_queues < 0) { - tst_resm(TBROK,"Could not read output of 'ipcs' to calculate used message queues"); - tst_exit(); - } - return used_queues; -} - -/** Get the max number of message queues allowed on system */ -static int get_max_msgqueues() -{ - FILE *f; - char buff[BUFSIZE]; - - /* Get the max number of message queues allowed on system */ - f = fopen("/proc/sys/kernel/msgmni", "r"); - if (!f){ - tst_resm(TBROK,"Could not open /proc/sys/kernel/msgmni"); - tst_exit(); - } - if (!fgets(buff, BUFSIZE, f)) { - tst_resm(TBROK,"Could not read /proc/sys/kernel/msgmni"); - tst_exit(); - } - fclose(f); - return atoi(buff); -} - /*************************************************************** * setup() - performs all ONE TIME setup for this test. *****************************************************************/ void setup() { + int nr_msgqs; + tst_tmpdir(); /* You will want to enable some signal handling so you can capture * unexpected signals like SIGSEGV. @@ -689,12 +647,22 @@ setup() */ TEST_PAUSE; - MSGMNI = get_max_msgqueues() - get_used_msgqueues(); - if (MSGMNI <= 0){ + 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); } Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgget/msgget03.c =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/msgget/msgget03.c 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgget/msgget03.c 2008-02-21 12:10:25.000000000 +0100 @@ -68,8 +68,6 @@ int exp_enos[] = {ENOSPC, 0}; /* 0 termi int *msg_q_arr = NULL; /* hold the id's that we create */ int num_queue = 0; /* count the queues created */ -static int get_max_msgqueues(); - int main(int ac, char **av) { int lc; /* loop counter */ @@ -121,24 +119,6 @@ int main(int ac, char **av) return(0); } -/** Get the max number of message queues allowed on system */ -int get_max_msgqueues() -{ - FILE *f; - char buff[512]; - - /* Get the max number of message queues allowed on system */ - f = fopen("/proc/sys/kernel/msgmni", "r"); - if (!f){ - tst_brkm(TBROK, cleanup, "Could not open /proc/sys/kernel/msgmni"); - } - if (!fgets(buff, 512, f)) { - tst_brkm(TBROK, cleanup, "Could not read /proc/sys/kernel/msgmni"); - } - fclose(f); - return atoi(buff); -} - /* * setup() - performs all the ONE TIME setup for this test. */ @@ -166,6 +146,8 @@ setup(void) msgkey = getipckey(); maxmsgs = get_max_msgqueues(); + if (maxmsgs < 0) + tst_brkm(TBROK, cleanup, ""); msg_q_arr = (int *)calloc(maxmsgs, sizeof (int)); if (msg_q_arr == NULL) { Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/Makefile =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/lib/Makefile 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/lib/Makefile 2008-02-21 12:14:39.000000000 +0100 @@ -19,6 +19,7 @@ SRCS = libipc.c OBJS = $(SRCS:.c=.o) LIBIPC = ../libipc.a +LIBIPC_HEADERS = ipcmsg.h ipcsem.h CFLAGS += -I../../../../../include -Wall @@ -27,6 +28,8 @@ all: $(LIBIPC) $(LIBIPC): $(OBJS) $(AR) -rc $@ $(OBJS) +$(OBJS): $(LIBIPC_HEADERS) + install: clean: Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/Makefile =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/msgctl/Makefile 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/Makefile 2008-02-21 14:11:46.000000000 +0100 @@ -18,12 +18,15 @@ CFLAGS += -I../lib -I../../../../../include -Wall LDLIBS += -L../../../../../lib -lltp -L.. -lipc +LIBIPC_HEADERS = ../lib/ipcmsg.h SRCS = $(wildcard *.c) TARGETS = $(patsubst %.c,%,$(SRCS)) all: $(TARGETS) +$(TARGETS): $(LIBIPC_HEADERS) + install: @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl10.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl10.c 2008-02-21 13:56:10.000000000 +0100 @@ -0,0 +1,527 @@ +/* + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ +/* 11/06/2002 Port to LTP dbarrera@us.ibm.com */ + +/* + * NAME + * msgctl10 + * + * CALLS + * msgget(2) msgctl(2) + * + * ALGORITHM + * Get and manipulate a message queue. + * Same as msgctl08 but gets the actual msgmni value under procfs. + * + * RESTRICTIONS + * + */ + +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" +#include "usctest.h" +#include "ipcmsg.h" + +void setup(); +void cleanup(); +/* + * * * * These globals must be defined in the test. + * * * */ + + +char *TCID="msgctl10"; /* Test program identifier. */ +int TST_TOTAL=1; /* Total number of test cases. */ +extern int Tst_count; /* Test Case counter for tst_* routines */ + +int exp_enos[]={0}; /* List must end with 0 */ + +#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 +#define FAIL 1 +#define PASS 0 + +key_t keyarray[MAXNPROCS]; + +struct { + long type; + struct { + char len; + char pbytes[99]; + } data; + } buffer; + +int pidarray[MAXNPROCS]; +int tid; +int MSGMNI,nprocs, nreps; +int procstat; +int dotest(key_t key, int child_process); +int doreader(int id, long key, int child); +int dowriter(int id,long key, int child); +int fill_buffer(register char *buf, char val, register int size); +int verify(register char *buf,char val, register int size,int child); +void sig_handler(); /* signal catching function */ +int mykid; +#ifdef UCLINUX +static char *argv0; + +void do_child_1_uclinux(); +static key_t key_uclinux; +static int i_uclinux; + +void do_child_2_uclinux(); +static int id_uclinux; +static int child_process_uclinux; +#endif + +/*-----------------------------------------------------------------*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + register int i, j, ok, pid; + int count, status; + struct sigaction act; + +#ifdef UCLINUX + char *msg; /* message returned from parse_opts */ + + argv0 = argv[0]; + + /* parse standard options */ + if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL) + { + tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); + } + + maybe_run_child(&do_child_1_uclinux, "ndd", 1, &key_uclinux, &i_uclinux); + maybe_run_child(&do_child_2_uclinux, "nddd", 2, &id_uclinux, &key_uclinux, + &child_process_uclinux); +#endif + + setup(); + + if (argc == 1 ) + { + /* Set default parameters */ + nreps = MAXNREPS; + nprocs = MSGMNI; + } + else if (argc == 3 ) + { + if ( atoi(argv[1]) > MAXNREPS ) + { + tst_resm(TCONF,"Requested number of iterations too large, setting to Max. of %d", MAXNREPS); + nreps = MAXNREPS; + } + else + { + nreps = atoi(argv[1]); + } + if (atoi(argv[2]) > MSGMNI ) + { + tst_resm(TCONF,"Requested number of processes too large, setting to Max. of %d", MSGMNI); + nprocs = MSGMNI; + } + else + { + nprocs = atoi(argv[2]); + } + } + else + { + tst_resm(TCONF," Usage: %s [ number of iterations number of processes ]", argv[0]); + tst_exit(); + } + + srand(getpid()); + tid = -1; + + /* Setup signal handleing 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_resm(TFAIL, "Sigset SIGTERM failed"); + tst_exit(); + } + /* 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_resm(TFAIL, "\tFork failed (may be OK if under stress)"); + tst_exit(); + } + /* Child does this */ + if (pid == 0) + { +#ifdef UCLINUX + if (self_exec(argv[0], "ndd", 1, keyarray[i], i) < 0) + { + tst_resm(TFAIL, "\tself_exec failed"); + tst_exit(); + } +#else + procstat = 1; + exit( dotest(keyarray[i], i) ); +#endif + } + pidarray[i] = pid; + } + + count = 0; + while(1) + { + if (( wait(&status)) > 0) + { + if (status>>8 != 0 ) + { + tst_resm(TFAIL, "Child exit status = %d", status>>8); + tst_exit(); + } + 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_resm(TFAIL, "Wrong number of children exited, Saw %d, Expected %d", count, nprocs); + tst_exit(); + } + + tst_resm(TPASS,"msgctl10 ran successfully!"); + + cleanup(); + return (0); + +} +/*--------------------------------------------------------------------*/ + +#ifdef UCLINUX +void +do_child_1_uclinux() +{ + procstat = 1; + exit(dotest(key_uclinux, i_uclinux)); +} + +void +do_child_2_uclinux() +{ + exit(doreader(id_uclinux, key_uclinux % 255, child_process_uclinux)); +} +#endif + +int dotest(key, child_process) +key_t key; +int child_process; +{ + int id, pid; + + sighold(SIGTERM); + TEST(msgget(key, IPC_CREAT | S_IRUSR | S_IWUSR)); + if (TEST_RETURN < 0) + { + tst_resm(TFAIL, "Msgget error in child %d, errno = %d", child_process, TEST_ERRNO); + tst_exit(); + } + tid = id = TEST_RETURN; + sigrelse(SIGTERM); + + fflush(stdout); + if ((pid = FORK_OR_VFORK()) < 0) + { + tst_resm(TWARN, "\tFork failed (may be OK if under stress)"); + TEST(msgctl(tid, IPC_RMID, 0)); + if (TEST_RETURN < 0) + { + tst_resm(TFAIL, "Msgctl error in cleanup, errno = %d", errno); + } + tst_exit(); + } + /* Child does this */ + if (pid == 0) + { +#ifdef UCLINUX + if (self_exec(argv0, "nddd", 2, id, key, child_process) < 0) { + tst_resm(TWARN, "self_exec failed"); + TEST(msgctl(tid, IPC_RMID, 0)); + if (TEST_RETURN < 0) + { + tst_resm(TFAIL, "\tMsgctl error in cleanup, " + "errno = %d\n", errno); + } + tst_exit(); + } +#else + exit( doreader(id, key % 255, child_process) ); +#endif + } + /* Parent does this */ + mykid = pid; + procstat = 2; + dowriter(id, key % 255, child_process); + wait(0); + TEST(msgctl(id, IPC_RMID, 0)); + if (TEST_RETURN < 0) + { + tst_resm(TFAIL, "msgctl errno %d", TEST_ERRNO); + tst_exit(); + } + exit(PASS); +} + +int doreader(id, key, child) +int id, child; +long key; +{ + int i, size; + + for (i = 0; i < nreps; i++) + { + if ((size = msgrcv(id, &buffer, 100, 0, 0)) < 0) + { + tst_brkm(TBROK, cleanup, "Msgrcv error in child %d, read # = %d, errno = %d", (i + 1), child, errno); + tst_exit(); + } + if (buffer.data.len + 1 != size) + { + tst_resm(TFAIL, "Size mismatch in child %d, read # = %d", child, (i + 1)); + tst_resm(TFAIL, "for message size got %d expected %d %s",size ,buffer.data.len); + tst_exit(); + } + if ( verify(buffer.data.pbytes, key, size - 1, child) ) + { + tst_resm(TFAIL, "in read # = %d,key = %x", (i + 1), child, key); + tst_exit(); + } + key++; + } + return (0); +} + +int dowriter(id, key, child) +int id,child; +long key; +{ + int i, size; + + for (i = 0; i < nreps; i++) + { + do + { + size = (rand() % 99); + } while (size == 0); + fill_buffer(buffer.data.pbytes, key, size); + buffer.data.len = size; + buffer.type = 1; + TEST(msgsnd(id, &buffer, size + 1, 0)); + if (TEST_RETURN < 0) + { + tst_brkm(TBROK, cleanup, "Msgsnd error in child %d, key = %x errno = %d", child, key, TEST_ERRNO); + } + key++; + } + return (0); +} + +int fill_buffer(buf, val, size) +register char *buf; +char val; +register int size; +{ + register int i; + + for(i = 0; i < size; i++) + { + buf[i] = val; + } + + return (0); +} + + +/* + * verify() + * Check a buffer for correct values. + */ + +int verify(buf, val, size, child) + register char *buf; + char val; + register int size; + int child; +{ + while(size-- > 0) + { + if (*buf++ != val) + { + tst_resm(TWARN, "Verify error in child %d, *buf = %x, val = %x, size = %d", child, *buf, val, size); + return(FAIL); + } + } + return(PASS); +} + +/* + * * void + * * sig_handler() - signal catching function for 'SIGUSR1' signal. + * * + * * This is a null function and used only to catch the above signal + * * generated in parent process. + * */ +void +sig_handler() +{ +} + +/*************************************************************** + * setup() - performs all ONE TIME setup for this test. + *****************************************************************/ +void +setup() +{ + int nr_msgqs; + + tst_tmpdir(); + + /* You will want to enable some signal handling so you can capture + * unexpected signals like SIGSEGV. + */ + tst_sig(FORK, DEF_HANDLER, cleanup); + + + /* Pause if that option was specified */ + /* 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) + cleanup(); + + MSGMNI = nr_msgqs - get_used_msgqueues(); + if (MSGMNI <= 0){ + tst_resm(TBROK,"Max number of message queues already used, cannot create more."); + cleanup(); + } +} + + +/*************************************************************** + * cleanup() - performs all ONE TIME cleanup for this test at + * completion or premature exit. + ****************************************************************/ +void +cleanup() +{ + int status; + /* + * Remove the message queue from the system + */ +#ifdef DEBUG + tst_resm(TINFO,"Removing the message queue"); +#endif + fflush (stdout); + (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL); + if ((status = msgctl(tid, IPC_STAT, (struct msqid_ds *)NULL)) != -1) + { + (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL); + tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed"); + tst_exit(); + } + + fflush (stdout); + /* + * print timing stats if that option was specified. + * print errno log if that option was specified. + */ + TEST_CLEANUP; + tst_rmdir(); + /* exit with return code appropriate for results */ + tst_exit(); +} + Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgget/Makefile =================================================================== --- ltp-full-20080131.orig/testcases/kernel/syscalls/ipc/msgget/Makefile 2008-02-21 10:45:36.000000000 +0100 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgget/Makefile 2008-02-21 12:22:43.000000000 +0100 @@ -21,9 +21,12 @@ LDLIBS += -L../../../../../lib -lltp -L. SRCS = $(wildcard *.c) TARGETS = $(patsubst %.c,%,$(SRCS)) +LIBIPC_HEADERS = ../lib/ipcmsg.h all: $(TARGETS) +$(TARGETS): $(LIBIPC_HEADERS) + install: @set -e; for i in $(TARGETS); do ln -f $$i ../../../../bin/$$i ; done Index: ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl11.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ ltp-full-20080131/testcases/kernel/syscalls/ipc/msgctl/msgctl11.c 2008-02-21 14:04:14.000000000 +0100 @@ -0,0 +1,696 @@ +/* + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ +/* 11/11/2002 Port to LTP dbarrera@us.ibm.com */ + + +/* + * NAME + * msgctl11 + * + * CALLS + * msgget(2) msgctl(2) msgop(2) + * + * ALGORITHM + * Get and manipulate a message queue. + * Same as msgctl09 but gets the actual msgmni value under procfs. + * + * RESTRICTIONS + * + */ + +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" +#include "usctest.h" +#include "ipcmsg.h" + +#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 FAIL 1 +#define PASS 0 + +int dotest(key_t,int); +int doreader(long,int,int); +int dowriter(long,int,int); +int fill_buffer(char*,char,int); +int verify(char*,char,int,int); +void setup(); +void cleanup(); + +/* + * These globals must be defined in the test. + * */ + + +char *TCID="msgctl11"; /* Test program identifier. */ +int TST_TOTAL=1; /* Total number of test cases. */ +extern int Tst_count; /* Test Case counter for tst_* routines */ + +int exp_enos[]={0}; /* List must end with 0 */ + + +key_t keyarray[MAXNPROCS]; + +struct { + long type; + struct { + char len; + char pbytes[99]; + } data; + } buffer; + +int pidarray[MAXNPROCS]; +int rkidarray[MAXNKIDS]; +int wkidarray[MAXNKIDS]; +int tid; +int nprocs, nreps, nkids, MSGMNI; +int procstat; +void term(int); +#ifdef UCLINUX +static char *argv0; + +void do_child_1_uclinux(); +static key_t key_uclinux; +static int i_uclinux; + +void do_child_2_uclinux(); +static int pid_uclinux; +static int child_process_uclinux; + +void do_child_3_uclinux(); +static int rkid_uclinux; +#endif +void cleanup_msgqueue(int i, int tid); + +/*-----------------------------------------------------------------*/ +int main(argc, argv) +int argc; +char *argv[]; +{ + register int i, j, ok, pid; + int count, status; + +#ifdef UCLINUX + char *msg; /* message returned from parse_opts */ + + argv0 = argv[0]; + + /* parse standard options */ + if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) != (char *)NULL) + { + tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg); + } + + maybe_run_child(&do_child_1_uclinux, "ndd", 1, &key_uclinux, &i_uclinux); + maybe_run_child(&do_child_2_uclinux, "nddd", 2, &key_uclinux, + &pid_uclinux, &child_process_uclinux); + maybe_run_child(&do_child_3_uclinux, "nddd", 3, &key_uclinux, + &rkid_uclinux, &child_process_uclinux); +#endif + + setup(); + + if (argc == 1 ) + { + /* Set default parameters */ + nreps = MAXNREPS; + nprocs = MSGMNI; + nkids = MAXNKIDS; + } + else if (argc == 4 ) + { + if ( atoi(argv[1]) > MAXNREPS ) + { + tst_resm(TCONF,"Requested number of iterations too large, setting to Max. of %d", MAXNREPS); + nreps = MAXNREPS; + } + else + { + nreps = atoi(argv[1]); + } + if (atoi(argv[2]) > MSGMNI ) + { + tst_resm(TCONF,"Requested number of processes too large, setting to Max. of %d", MSGMNI); + nprocs = MSGMNI; + } + else + { + nprocs = atoi(argv[2]); + } + if (atoi(argv[3]) > MAXNKIDS ) + { + tst_resm(TCONF,"Requested number of read/write pairs too large; setting to Max. of %d", MAXNKIDS); + nkids = MAXNKIDS; + } + else + { + nkids = atoi(argv[3]); + } + } + else + { + tst_resm(TCONF," Usage: %s [ number of iterations number of processes number of read/write pairs ]", argv[0]); + tst_exit(); + } + + procstat = 0; + srand48((unsigned)getpid() + (unsigned)(getppid() << 16)); + tid = -1; + + /* Setup signal handleing routine */ + if (sigset(SIGTERM, term) == SIG_ERR) + { + tst_resm(TFAIL, "Sigset SIGTERM failed"); + tst_exit(); + } + /* 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_resm(TFAIL, "\tFork failed (may be OK if under stress)"); + tst_exit(); + } + /* Child does this */ + if (pid == 0) + { +#ifdef UCLINUX + if (self_exec(argv[0], "ndd", 1, keyarray[i], i) < 0) + { + tst_resm(TFAIL, "\tself_exec failed"); + tst_exit(); + } +#else + procstat = 1; + exit( dotest(keyarray[i], i) ); +#endif + } + pidarray[i] = pid; + } + + count = 0; + while(1) + { + if (( wait(&status)) > 0) + { + if (status>>8 != PASS ) + { + tst_resm(TFAIL, "Child exit status = %d", status>>8); + tst_exit(); + } + 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_resm(TFAIL, "Wrong number of children exited, Saw %d, Expected %d", count, nprocs); + tst_exit(); + } + + tst_resm(TPASS,"msgctl11 ran successfully!"); + + cleanup(); + + return (0); + + + +} +/*--------------------------------------------------------------------*/ + +#ifdef UCLINUX +void +do_child_1_uclinux() +{ + procstat = 1; + exit(dotest(key_uclinux, i_uclinux)); +} + +void +do_child_2_uclinux() +{ + procstat = 2; + exit(doreader(key_uclinux, pid_uclinux, child_process_uclinux)); +} + +void +do_child_3_uclinux() +{ + procstat = 2; + exit(dowriter(key_uclinux, rkid_uclinux, child_process_uclinux)); +} +#endif + +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_resm(TFAIL, "Msgctl error in cleanup, errno = %d", errno); + tst_exit(); + } +} + +int dotest(key, child_process) +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) + { + tst_resm(TFAIL, "Msgget error in child %d, errno = %d", child_process, errno); + tst_exit(); + } + tid = id; + sigrelse(SIGTERM); + + exit_status = PASS; + + for (i=0; i < nkids; i++) + { + fflush(stdout); + if ((pid = FORK_OR_VFORK()) < 0) + { + tst_resm(TWARN, "Fork failure in first child of child group %d", child_process); + cleanup_msgqueue(i, tid); + tst_exit(); + } + /* First child does this */ + if (pid == 0) + { +#ifdef UCLINUX + if (self_exec(argv0, "nddd", 2, key, getpid(), + child_process) < 0) { + tst_resm(TWARN, "self_exec failed"); + cleanup_msgqueue(i, tid); + tst_exit(); + } +#else + procstat = 2; + exit( doreader( key, getpid(), child_process) ); +#endif + } + rkidarray[i] = pid; + fflush(stdout); + if ((pid = FORK_OR_VFORK()) < 0) + { + tst_resm(TWARN, "Fork failure in first child of child group %d", child_process); + /* + * Kill the reader child process + */ + (void)kill(rkidarray[i], SIGKILL); + + cleanup_msgqueue(i, tid); + tst_exit(); + } + /* Second child does this */ + if (pid == 0) + { +#ifdef UCLINUX + if (self_exec(argv0, "nddd", 3, key, rkidarray[i], + child_process) < 0) { + tst_resm(TWARN, "\tFork failure in first child " + "of child group %d \n", child_process); + /* + * Kill the reader child process + */ + (void)kill(rkidarray[i], SIGKILL); + + cleanup_msgqueue(i, tid); + tst_exit(); + } +#else + procstat = 2; + exit( dowriter( key, rkidarray[i], child_process) ); +#endif + } + wkidarray[i] = pid; + } + /* Parent does this */ + count = 0; + while(1) + { + if (( wait(&status)) > 0) + { + if (status>>8 != PASS ) + { + tst_resm(TFAIL, "Child exit status = %d from child group %d", 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) { + tst_resm(TFAIL, "Msgctl error, errno = %d", errno); + } + tst_exit(); + } + count++; + } + else + { + if (errno != EINTR) + { + break; + } + } + } + /* Make sure proper number of children exited */ + if (count != (nkids * 2)) + { + tst_resm(TFAIL, "Wrong number of children exited in child group %d, Saw %d Expected %d", child_process, count, (nkids * 2)); + if (msgctl(tid, IPC_RMID, 0) < 0) { + tst_resm(TFAIL, "Msgctl error, errno = %d", errno); + } + tst_exit(); + } + if (msgctl(id, IPC_RMID, 0) < 0) + { + tst_resm(TFAIL, "Msgctl failure in child group %d, errno %d", child_process, errno); + tst_exit(); + } + exit(exit_status); +} + +int doreader( key, type, child) +int type, child; +long key; +{ + int i, size; + int id; + + if ((id = msgget(key, 0)) < 0) + { + tst_resm(TFAIL, "Msgget error in reader of child group %d, errno = %d", child, errno); + tst_exit(); + } + if (id != tid) + { + tst_resm(TFAIL, "Message queue mismatch in reader of child group %d for message queue id %d", child, id); + tst_exit(); + } + for (i = 0; i < nreps; i++) + { + if ((size = msgrcv(id, &buffer, 100, type, 0)) < 0) + { + tst_resm(TFAIL, "Msgrcv error in child %d, read # = %d, errno = %d", (i + 1), child, errno); + tst_exit(); + } + if (buffer.type != type) + { + tst_resm(TFAIL, "Size mismatch in child %d, read # = %d", child, (i + 1)); + tst_resm(TFAIL, "\tfor message size got %d expected %d %s",size ,buffer.data.len); + tst_exit(); + } + if (buffer.data.len + 1 != size) + { + tst_resm(TFAIL, "Size mismatch in child %d, read # = %d, size = %d, expected = %d", child, (i + 1), buffer.data.len, size); + tst_exit(); + } + if ( verify(buffer.data.pbytes, (key % 255), size - 1, child) ) + { + tst_resm(TFAIL, "in read # = %d,key = %x", (i + 1), child, key); + tst_exit(); + } + key++; + } + exit(PASS); +} + +int dowriter( key, type, child) +int type,child; +long key; +{ + int i, size; + int id; + + if ((id = msgget(key, 0)) < 0) + { + tst_resm(TFAIL, "Msgget error in writer of child group %d, errno = %d", child, errno); + tst_exit(); + } + if (id != tid) + { + tst_resm(TFAIL, "Message queue mismatch in writer of child group %d", child); + tst_resm(TFAIL, "\tfor message queue id %d expected %d",id, tid); + tst_exit(); + } + + for (i = 0; i < nreps; i++) + { + do + { + size = (lrand48() % 99); + } while (size == 0); + fill_buffer(buffer.data.pbytes, (key % 255), size); + buffer.data.len = size; + buffer.type = type; + if (msgsnd(id, &buffer, size + 1, 0) < 0) + { + tst_resm(TFAIL, "Msgsnd error in child %d, key = %x errno = %d", child, key, errno); + tst_exit(); + } + key++; + } + exit(PASS); +} + +int fill_buffer(buf, val, size) +register char *buf; +char val; +register int size; +{ + register int i; + + for(i = 0; i < size; i++) + buf[i] = val; + return(0); +} + + +/* + * verify() + * Check a buffer for correct values. + */ + +int verify(buf, val, size, child) + register char *buf; + char val; + register int size; + int child; +{ + while(size-- > 0) + if (*buf++ != val) + { + tst_resm(TWARN, "Verify error in child %d, *buf = %x, val = %x, size = %d", child, *buf, val, size); + return(FAIL); + } + return(PASS); +} + +/* ARGSUSED */ +void +term(int sig) +{ + 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) + { + 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); + } +} + +/*************************************************************** + * setup() - performs all ONE TIME setup for this test. + *****************************************************************/ +void +setup() +{ + int nr_msgqs; + + tst_tmpdir(); + /* You will want to enable some signal handling so you can capture + * unexpected signals like SIGSEGV. + */ + tst_sig(FORK, DEF_HANDLER, cleanup); + + + /* Pause if that option was specified */ + /* 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) + cleanup(); + + MSGMNI = nr_msgqs - get_used_msgqueues(); + if (MSGMNI <= 0){ + tst_resm(TBROK,"Max number of message queues already used, cannot create more."); + cleanup(); + } +} + + +/*************************************************************** + * cleanup() - performs all ONE TIME cleanup for this test at + * completion or premature exit. + ****************************************************************/ +void +cleanup() +{ + int status; + /* + * print timing stats if that option was specified. + * print errno log if that option was specified. + */ + TEST_CLEANUP; + + /* + * Remove the message queue from the system + */ +#ifdef DEBUG + tst_resm(TINFO,"Removing the message queue"); +#endif + fflush (stdout); + (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL); + if ((status = msgctl(tid, IPC_STAT, (struct msqid_ds *)NULL)) != -1) { + (void) msgctl(tid, IPC_RMID, (struct msqid_ds *)NULL); + tst_resm(TFAIL, "msgctl(tid, IPC_RMID) failed"); + tst_exit(); + } + + fflush (stdout); + tst_rmdir(); + /* exit with return code appropriate for results */ + tst_exit(); +} +