1
- // SPDX-License-Identifier: GPL-2.0-or-later
2
1
/*
3
2
* 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
5
17
*
6
18
* 06/30/2001 Port to Linux [email protected]
7
19
* 11/06/2002 Port to LTP [email protected]
8
- * 10/21/2020 Convert to new api [email protected]
9
- *
20
+ */
21
+
22
+ /*
10
23
* Get and manipulate a message queue.
11
24
*/
12
25
18
31
#include <stdlib.h>
19
32
#include <stdio.h>
20
33
#include <unistd.h>
34
+ #include <values.h>
21
35
#include <sys/types.h>
22
36
#include <sys/wait.h>
23
37
#include <sys/stat.h>
24
38
#include <sys/ipc.h>
25
39
#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"
30
43
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
32
52
#define MAXNREPS 100000
33
53
34
54
static key_t keyarray [MAXNPROCS ];
55
+ static int pidarray [MAXNPROCS ];
35
56
static int tid ;
36
57
static 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
+
37
67
static char * opt_nprocs ;
38
68
static char * opt_nreps ;
39
- static void cleanup (void );
40
69
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 },
45
74
};
46
75
47
- static void dotest ( key_t key , int child_process )
76
+ static void usage ( void )
48
77
{
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" );
62
80
}
63
81
64
- static void verify_msgstress ( void )
82
+ int main ( int argc , char * * argv )
65
83
{
66
84
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
+ }
68
114
69
115
srand (getpid ());
70
116
tid = -1 ;
71
117
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
+ */
73
129
for (i = 0 ; i < nprocs ; i ++ ) {
74
130
ok = 1 ;
75
131
do {
132
+ /* Get random key */
76
133
keyarray [i ] = (key_t ) rand ();
77
134
/* Make sure key is unique and not private */
78
135
if (keyarray [i ] == IPC_PRIVATE ) {
@@ -89,83 +146,156 @@ static void verify_msgstress(void)
89
146
} while (ok == 0 );
90
147
}
91
148
92
- /*
93
- * Fork a number of processes, each of which will
149
+ /* Fork a number of processes, each of which will
94
150
* create a message queue with one reader/writer
95
151
* pair which will read and write a number (iterations)
96
152
* of random length messages with specific values.
97
153
*/
154
+
98
155
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 */
100
163
if (pid == 0 ) {
101
- dotest ( keyarray [ i ], i ) ;
102
- exit (0 );
164
+ procstat = 1 ;
165
+ exit (dotest ( keyarray [ i ], i ) );
103
166
}
167
+ pidarray [i ] = pid ;
104
168
}
105
169
106
170
count = 0 ;
107
-
108
171
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
+ }
110
178
count ++ ;
111
179
} else {
112
- if (errno != EINTR )
180
+ if (errno != EINTR ) {
113
181
break ;
182
+ }
183
+ #ifdef DEBUG
184
+ tst_resm (TINFO , "Signal detected during wait" );
185
+ #endif
114
186
}
115
187
}
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
+ }
116
195
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!" );
120
197
121
- tst_res (TPASS , "Test ran successfully!" );
122
198
cleanup ();
199
+ tst_exit ();
123
200
}
124
201
125
- static void setup ( void )
202
+ static int dotest ( key_t key , int child_process )
126
203
{
127
- int nr_msgqs ;
204
+ int id , pid ;
205
+ int ret , status ;
128
206
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 ));
130
212
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 );
135
217
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 );
137
236
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 ;
143
249
}
250
+ return PASS ;
251
+ }
144
252
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 ();
151
276
}
152
277
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 );
156
284
}
157
285
158
286
void cleanup (void )
159
287
{
160
- if (tid >= 0 )
161
- SAFE_MSGCTL (tid , IPC_RMID , NULL );
162
- }
288
+ int status ;
163
289
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