1- // SPDX-License-Identifier: GPL-2.0-or-later
21/*
32 * Copyright (c) International Business Machines Corp., 2002
4- * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved.
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
517 *
618 * 06/30/2001 Port to Linux nsharoff@us.ibm.com
719 * 11/06/2002 Port to LTP dbarrera@us.ibm.com
8- * 10/21/2020 Convert to new api xuyang2018.jy@cn.fujitsu.com
9- *
20+ */
21+
22+ /*
1023 * Get and manipulate a message queue.
1124 */
1225
1831#include <stdlib.h>
1932#include <stdio.h>
2033#include <unistd.h>
34+ #include <values.h>
2135#include <sys/types.h>
2236#include <sys/wait.h>
2337#include <sys/stat.h>
2438#include <sys/ipc.h>
2539#include <sys/msg.h>
26- #include "tst_test.h"
27- #include "libnewipc.h"
28- #include "tst_safe_sysv_ipc.h"
29- #include "msgstress_common.h"
40+ #include "test.h"
41+ #include "ipcmsg.h"
42+ #include "libmsgctl.h"
3043
31- #define MAXNPROCS 1000000
44+ char * TCID = "msgstress01" ;
45+ int TST_TOTAL = 1 ;
46+
47+ #ifndef CONFIG_COLDFIRE
48+ #define MAXNPROCS 1000000 /* This value is set to an arbitrary high limit. */
49+ #else
50+ #define MAXNPROCS 100000 /* Coldfire can't deal with 1000000 */
51+ #endif
3252#define MAXNREPS 100000
3353
3454static key_t keyarray [MAXNPROCS ];
55+ static int pidarray [MAXNPROCS ];
3556static int tid ;
3657static int MSGMNI , nprocs , nreps ;
58+ static int procstat ;
59+ static int mykid ;
60+
61+ void setup (void );
62+ void cleanup (void );
63+
64+ static int dotest (key_t key , int child_process );
65+ static void sig_handler ();
66+
3767static char * opt_nprocs ;
3868static char * opt_nreps ;
39- static void cleanup (void );
4069
41- static struct tst_option options [] = {
42- {"n:" , & opt_nprocs , "-n N Number of processes" },
43- {"l:" , & opt_nreps , "-l N Number of iterations" },
44- {NULL , NULL , NULL }
70+ static option_t options [] = {
71+ {"n:" , NULL , & opt_nprocs },
72+ {"l:" , NULL , & opt_nreps },
73+ {NULL , NULL , NULL },
4574};
4675
47- static void dotest ( key_t key , int child_process )
76+ static void usage ( void )
4877{
49- int pid ;
50-
51- tid = SAFE_MSGGET (key , IPC_CREAT | S_IRUSR | S_IWUSR );
52-
53- pid = SAFE_FORK ();
54- if (pid == 0 ) {
55- do_reader (key , tid , 1 , child_process , nreps );
56- exit (0 );
57- }
58-
59- do_writer (key , tid , 1 , child_process , nreps );
60- SAFE_WAIT (NULL );
61- SAFE_MSGCTL (tid , IPC_RMID , NULL );
78+ printf (" -n Number of processes\n" );
79+ printf (" -l Number of iterations\n" );
6280}
6381
64- static void verify_msgstress ( void )
82+ int main ( int argc , char * * argv )
6583{
6684 int i , j , ok , pid ;
67- int count ;
85+ int count , status ;
86+ struct sigaction act ;
87+
88+ tst_parse_opts (argc , argv , options , usage );
89+
90+ setup ();
91+
92+ nreps = MAXNREPS ;
93+ nprocs = MSGMNI ;
94+
95+ if (opt_nreps ) {
96+ nreps = atoi (opt_nreps );
97+ if (nreps > MAXNREPS ) {
98+ tst_resm (TINFO ,
99+ "Requested number of iterations too large, "
100+ "setting to Max. of %d" , MAXNREPS );
101+ nreps = MAXNREPS ;
102+ }
103+ }
104+
105+ if (opt_nprocs ) {
106+ nprocs = atoi (opt_nprocs );
107+ if (nprocs > MSGMNI ) {
108+ tst_resm (TINFO ,
109+ "Requested number of processes too large, "
110+ "setting to Max. of %d" , MSGMNI );
111+ nprocs = MSGMNI ;
112+ }
113+ }
68114
69115 srand (getpid ());
70116 tid = -1 ;
71117
72- /* Set up array of unique keys for use in allocating message queues */
118+ /* Setup signal handling routine */
119+ memset (& act , 0 , sizeof (act ));
120+ act .sa_handler = sig_handler ;
121+ sigemptyset (& act .sa_mask );
122+ sigaddset (& act .sa_mask , SIGTERM );
123+ if (sigaction (SIGTERM , & act , NULL ) < 0 ) {
124+ tst_brkm (TFAIL , NULL , "Sigset SIGTERM failed" );
125+ }
126+ /* Set up array of unique keys for use in allocating message
127+ * queues
128+ */
73129 for (i = 0 ; i < nprocs ; i ++ ) {
74130 ok = 1 ;
75131 do {
132+ /* Get random key */
76133 keyarray [i ] = (key_t ) rand ();
77134 /* Make sure key is unique and not private */
78135 if (keyarray [i ] == IPC_PRIVATE ) {
@@ -89,83 +146,156 @@ static void verify_msgstress(void)
89146 } while (ok == 0 );
90147 }
91148
92- /*
93- * Fork a number of processes, each of which will
149+ /* Fork a number of processes, each of which will
94150 * create a message queue with one reader/writer
95151 * pair which will read and write a number (iterations)
96152 * of random length messages with specific values.
97153 */
154+
98155 for (i = 0 ; i < nprocs ; i ++ ) {
99- pid = SAFE_FORK ();
156+ fflush (stdout );
157+ if ((pid = FORK_OR_VFORK ()) < 0 ) {
158+ tst_brkm (TFAIL ,
159+ NULL ,
160+ "\tFork failed (may be OK if under stress)" );
161+ }
162+ /* Child does this */
100163 if (pid == 0 ) {
101- dotest ( keyarray [ i ], i ) ;
102- exit (0 );
164+ procstat = 1 ;
165+ exit (dotest ( keyarray [ i ], i ) );
103166 }
167+ pidarray [i ] = pid ;
104168 }
105169
106170 count = 0 ;
107-
108171 while (1 ) {
109- if (wait (NULL ) > 0 ) {
172+ if ((wait (& status )) > 0 ) {
173+ if (status >> 8 != 0 ) {
174+ tst_brkm (TFAIL , NULL ,
175+ "Child exit status = %d" ,
176+ status >> 8 );
177+ }
110178 count ++ ;
111179 } else {
112- if (errno != EINTR )
180+ if (errno != EINTR ) {
113181 break ;
182+ }
183+ #ifdef DEBUG
184+ tst_resm (TINFO , "Signal detected during wait" );
185+ #endif
114186 }
115187 }
188+ /* Make sure proper number of children exited */
189+ if (count != nprocs ) {
190+ tst_brkm (TFAIL ,
191+ NULL ,
192+ "Wrong number of children exited, Saw %d, Expected %d" ,
193+ count , nprocs );
194+ }
116195
117- if (count != nprocs )
118- tst_brk (TFAIL , "Wrong number of children exited, Saw %d, Expected %d" ,
119- count , nprocs );
196+ tst_resm (TPASS , "Test ran successfully!" );
120197
121- tst_res (TPASS , "Test ran successfully!" );
122198 cleanup ();
199+ tst_exit ();
123200}
124201
125- static void setup ( void )
202+ static int dotest ( key_t key , int child_process )
126203{
127- int nr_msgqs ;
204+ int id , pid ;
205+ int ret , status ;
128206
129- SAFE_FILE_SCANF ("/proc/sys/kernel/msgmni" , "%d" , & nr_msgqs );
207+ sighold (SIGTERM );
208+ TEST (msgget (key , IPC_CREAT | S_IRUSR | S_IWUSR ));
209+ if (TEST_RETURN < 0 ) {
210+ printf ("msgget() error in child %d: %s\n" ,
211+ child_process , strerror (TEST_ERRNO ));
130212
131- nr_msgqs -= GET_USED_QUEUES () ;
132- if ( nr_msgqs <= 0 )
133- tst_brk ( TCONF , "Max number of message queues already used, "
134- "cannot create more." );
213+ return FAIL ;
214+ }
215+ tid = id = TEST_RETURN ;
216+ sigrelse ( SIGTERM );
135217
136- MSGMNI = min (nr_msgqs , NR_MSGQUEUES );
218+ fflush (stdout );
219+ if ((pid = FORK_OR_VFORK ()) < 0 ) {
220+ printf ("\tFork failed (may be OK if under stress)\n" );
221+ TEST (msgctl (tid , IPC_RMID , 0 ));
222+ if (TEST_RETURN < 0 ) {
223+ printf ("mscgtl() error in cleanup: %s\n" ,
224+ strerror (TEST_ERRNO ));
225+ }
226+ return FAIL ;
227+ }
228+ /* Child does this */
229+ if (pid == 0 )
230+ exit (doreader (key , id , 1 , child_process , nreps ));
231+ /* Parent does this */
232+ mykid = pid ;
233+ procstat = 2 ;
234+ ret = dowriter (key , id , 1 , child_process , nreps );
235+ wait (& status );
137236
138- if (opt_nreps ) {
139- nreps = SAFE_STRTOL (opt_nreps , 1 , INT_MAX );
140- nreps = min (nreps , MAXNREPS );
141- } else {
142- nreps = MAXNREPS ;
237+ if (ret != PASS )
238+ exit (FAIL );
239+
240+ if ((!WIFEXITED (status ) || (WEXITSTATUS (status ) != PASS )))
241+ exit (FAIL );
242+
243+ TEST (msgctl (id , IPC_RMID , 0 ));
244+ if (TEST_RETURN < 0 ) {
245+ printf ("msgctl() errno %d: %s\n" ,
246+ TEST_ERRNO , strerror (TEST_ERRNO ));
247+
248+ return FAIL ;
143249 }
250+ return PASS ;
251+ }
144252
145- if (opt_nprocs ) {
146- nprocs = SAFE_STRTOL (opt_nprocs , 1 , INT_MAX );
147- nprocs = min (nprocs , MAXNPROCS );
148- nprocs = min (nprocs , MSGMNI );
149- } else {
150- nprocs = MSGMNI ;
253+ static void sig_handler (void )
254+ {
255+ }
256+
257+ void setup (void )
258+ {
259+ int nr_msgqs ;
260+
261+ tst_tmpdir ();
262+
263+ tst_sig (FORK , DEF_HANDLER , cleanup );
264+
265+ TEST_PAUSE ;
266+
267+ nr_msgqs = get_max_msgqueues ();
268+ if (nr_msgqs < 0 )
269+ cleanup ();
270+
271+ nr_msgqs -= get_used_msgqueues ();
272+ if (nr_msgqs <= 0 ) {
273+ tst_resm (TBROK ,
274+ "Max number of message queues already used, cannot create more." );
275+ cleanup ();
151276 }
152277
153- SAFE_SIGNAL (SIGTERM , SIG_IGN );
154- tst_res (TINFO , "Number of message queues is %d, process is %d, "
155- "iterations is %d" , MSGMNI , nprocs , nreps );
278+ /*
279+ * Since msgmni scales to the memory size, it may reach huge values
280+ * that are not necessary for this test.
281+ * That's why we define NR_MSGQUEUES as a high boundary for it.
282+ */
283+ MSGMNI = min (nr_msgqs , NR_MSGQUEUES );
156284}
157285
158286void cleanup (void )
159287{
160- if (tid >= 0 )
161- SAFE_MSGCTL (tid , IPC_RMID , NULL );
162- }
288+ int status ;
163289
164- static struct tst_test test = {
165- .needs_tmpdir = 1 ,
166- .options = options ,
167- .setup = setup ,
168- .cleanup = cleanup ,
169- .forks_child = 1 ,
170- .test_all = verify_msgstress ,
171- };
290+ #ifdef DEBUG
291+ tst_resm (TINFO , "Removing the message queue" );
292+ #endif
293+ (void )msgctl (tid , IPC_RMID , NULL );
294+ if ((status = msgctl (tid , IPC_STAT , NULL )) != -1 ) {
295+ (void )msgctl (tid , IPC_RMID , NULL );
296+ tst_resm (TFAIL , "msgctl(tid, IPC_RMID) failed" );
297+
298+ }
299+
300+ tst_rmdir ();
301+ }
0 commit comments