• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************/
2 /* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd		*/
3 /*	  Author(s): Takahiro Yasui <takahiro.yasui.mp@hitachi.com>,	      */
4 /*		       Yumiko Sugita <yumiko.sugita.yf@hitachi.com>, 	      */
5 /*		       Satoshi Fujiwara <sa-fuji@sdl.hitachi.co.jp>	      */
6 /*								  	      */
7 /* This program is free software;  you can redistribute it and/or modify      */
8 /* it under the terms of the GNU General Public License as published by       */
9 /* the Free Software Foundation; either version 2 of the License, or	  */
10 /* (at your option) any later version.					*/
11 /*									    */
12 /* This program is distributed in the hope that it will be useful,	    */
13 /* but WITHOUT ANY WARRANTY;  without even the implied warranty of	    */
14 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See		  */
15 /* the GNU General Public License for more details.			   */
16 /*									    */
17 /* You should have received a copy of the GNU General Public License	  */
18 /* along with this program;  if not, write to the Free Software	       */
19 /* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA    */
20 /*									    */
21 /******************************************************************************/
22 /******************************************************************************/
23 /*									    */
24 /* File:	mq_timedreceive01.c					   */
25 /*									    */
26 /* Description: This tests the mq_timedreceive() syscall		      */
27 /*									      */
28 /* 									      */
29 /*									      */
30 /*									      */
31 /*									      */
32 /*									    */
33 /* Usage:  <for command-line>						 */
34 /* mq_timedreceive01 [-c n] [-e][-i n] [-I x] [-p x] [-t]		     */
35 /*      where,  -c n : Run n copies concurrently.			     */
36 /*	      -e   : Turn on errno logging.				 */
37 /*	      -i n : Execute test n times.				  */
38 /*	      -I x : Execute test for x seconds.			    */
39 /*	      -P x : Pause for x seconds between iterations.		*/
40 /*	      -t   : Turn on syscall timing.				*/
41 /*									    */
42 /* Total Tests: 1							     */
43 /*									    */
44 /* Test Name:   mq_timedreceive01					     */
45 /* History:     Porting from Crackerjack to LTP is done by		    */
46 /*	      Manas Kumar Nayak maknayak@in.ibm.com>			*/
47 /******************************************************************************/
48 #define _XOPEN_SOURCE 600
49 #include <sys/syscall.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <getopt.h>
54 #include <libgen.h>
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <stdio.h>
58 #include <unistd.h>
59 #include <string.h>
60 #include <mqueue.h>
61 #include <time.h>
62 #include <signal.h>
63 #include <limits.h>
64 
65 #include "../utils/include_j_h.h"
66 #include "../utils/common_j_h.c"
67 
68 #include "test.h"
69 #include "linux_syscall_numbers.h"
70 
71 char *TCID = "mq_timedreceive01";
72 int testno;
73 int TST_TOTAL = 1;
74 struct sigaction act;
75 
76 /*
77  * sighandler()
78  */
sighandler(int sig)79 void sighandler(int sig)
80 {
81 	if (sig == SIGINT)
82 		return;
83 
84 	return;
85 }
86 
87 /* Extern Global Functions */
88 /******************************************************************************/
89 /*									    */
90 /* Function:    cleanup						       */
91 /*									    */
92 /* Description: Performs all one time clean up for this test on successful    */
93 /*	      completion,  premature exit or  failure. Closes all temporary */
94 /*	      files, removes all temporary directories exits the test with  */
95 /*	      appropriate return code by calling tst_exit() function.       */
96 /*									    */
97 /* Input:       None.							 */
98 /*									    */
99 /* Output:      None.							 */
100 /*									    */
101 /* Return:      On failure - Exits calling tst_exit(). Non '0' return code.   */
102 /*	      On success - Exits calling tst_exit(). With '0' return code.  */
103 /*									    */
104 /******************************************************************************/
cleanup(void)105 void cleanup(void)
106 {
107 
108 	tst_rmdir();
109 
110 }
111 
112 /* Local  Functions */
113 /******************************************************************************/
114 /*									    */
115 /* Function:    setup							 */
116 /*									    */
117 /* Description: Performs all one time setup for this test. This function is   */
118 /*	      typically used to capture signals, create temporary dirs      */
119 /*	      and temporary files that may be used in the course of this    */
120 /*	      test.							 */
121 /*									    */
122 /* Input:       None.							 */
123 /*									    */
124 /* Output:      None.							 */
125 /*									    */
126 /* Return:      On failure - Exits by calling cleanup().		      */
127 /*	      On success - returns 0.				       */
128 /*									    */
129 /******************************************************************************/
setup(void)130 void setup(void)
131 {
132 	/* Capture signals if any */
133 	act.sa_handler = sighandler;
134 	sigfillset(&act.sa_mask);
135 	sigaction(SIGINT, &act, NULL);
136 	/* Create temporary directories */
137 	TEST_PAUSE;
138 	tst_tmpdir();
139 }
140 
141 /*
142  * Macros
143  */
144 #define SYSCALL_NAME    "mq_timedreceive"
145 
146 enum test_type {
147 	NORMAL,
148 	FD_NONE,
149 	FD_NOT_EXIST,
150 	FD_FILE,
151 	INVALID_MSG_LEN,
152 	EMPTY_QUEUE,
153 	SEND_SIGINT,
154 };
155 
156 /*
157  * Data Structure
158  */
159 struct test_case {
160 	int ttype;
161 	int non_block;
162 	int len;
163 	unsigned prio;
164 	time_t sec;
165 	long nsec;
166 	int ret;
167 	int err;
168 };
169 
170 #define MAX_MSG	 10
171 #define MAX_MSGSIZE     8192
172 
173 /* Test cases
174  *
175  *   test status of errors on man page
176  *
177  *   EAGAIN	     v (would block)
178  *   EBADF	      v (not a valid descriptor)
179  *   EINTR	      v (interrupted by a signal)
180  *   EINVAL	     v (invalid timeout value)
181  *   ETIMEDOUT	  v (not block and timeout occured)
182  *   EMSGSIZE	   v ('msg_len' is less than the message size of the queue)
183  *   EBADMSG	    can't check because this error never occur
184  */
185 static struct test_case tcase[] = {
186 	{			// case00
187 	 .ttype = NORMAL,
188 	 .len = 0,		// also success when size equals zero
189 	 .ret = 0,
190 	 .err = 0,
191 	 },
192 	{			// case01
193 	 .ttype = NORMAL,
194 	 .len = 1,
195 	 .ret = 0,
196 	 .err = 0,
197 	 },
198 	{			// case02
199 	 .ttype = NORMAL,
200 	 .len = MAX_MSGSIZE,
201 	 .ret = 0,
202 	 .err = 0,
203 	 },
204 	{			// case03
205 	 .ttype = NORMAL,
206 	 .len = 1,
207 	 .prio = 32767,		// max priority
208 	 .ret = 0,
209 	 .err = 0,
210 	 },
211 	{			// case04
212 	 .ttype = INVALID_MSG_LEN,
213 	 .len = 0,
214 	 .ret = -1,
215 	 .err = EMSGSIZE,
216 	 },
217 	{			// case05
218 	 .ttype = FD_NONE,
219 	 .len = 0,
220 	 .ret = -1,
221 	 .err = EBADF,
222 	 },
223 	{			// case06
224 	 .ttype = FD_NOT_EXIST,
225 	 .len = 0,
226 	 .ret = -1,
227 	 .err = EBADF,
228 	 },
229 	{			// case07
230 	 .ttype = FD_FILE,
231 	 .len = 0,
232 	 .ret = -1,
233 	 .err = EBADF,
234 	 },
235 	{			// case08
236 	 .ttype = EMPTY_QUEUE,
237 	 .non_block = 1,
238 	 .len = 16,
239 	 .ret = -1,
240 	 .err = EAGAIN,
241 	 },
242 	{			// case09
243 	 .ttype = EMPTY_QUEUE,
244 	 .len = 16,
245 	 .sec = -1,
246 	 .nsec = 0,
247 	 .ret = -1,
248 	 .err = EINVAL,
249 	 },
250 	{			// case10
251 	 .ttype = EMPTY_QUEUE,
252 	 .len = 16,
253 	 .sec = 0,
254 	 .nsec = -1,
255 	 .ret = -1,
256 	 .err = EINVAL,
257 	 },
258 	{			// case11
259 	 .ttype = EMPTY_QUEUE,
260 	 .len = 16,
261 	 .sec = 0,
262 	 .nsec = 1000000000,
263 	 .ret = -1,
264 	 .err = EINVAL,
265 	 },
266 	{			// case12
267 	 .ttype = EMPTY_QUEUE,
268 	 .len = 16,
269 	 .sec = 0,
270 	 .nsec = 999999999,
271 	 .ret = -1,
272 	 .err = ETIMEDOUT,
273 	 },
274 	{			// case13
275 	 .ttype = SEND_SIGINT,
276 	 .len = 16,
277 	 .sec = 3,
278 	 .nsec = 0,
279 	 .ret = -1,
280 	 .err = EINTR,
281 	 },
282 };
283 
284 #define MEM_LENGTH	      (4 * 1024 * 1024)
285 /*
286  * do_test()
287  *
288  *   Input  : TestCase Data
289  *   Return : RESULT_OK(0), RESULT_NG(1)
290  *
291  */
292 
do_test(struct test_case * tc)293 static int do_test(struct test_case *tc)
294 {
295 	int sys_ret;
296 	int sys_errno;
297 	int result = RESULT_OK;
298 	int oflag;
299 	int i, rc, cmp_ok = 1, fd = -1;
300 	char smsg[MAX_MSGSIZE], rmsg[MAX_MSGSIZE];
301 	struct timespec ts = { 0, 0 };
302 	pid_t pid = 0;
303 	unsigned prio;
304 	size_t msg_len;
305 
306 	/*
307 	 * When test ended with SIGTERM etc, mq discriptor is left remains.
308 	 * So we delete it first.
309 	 */
310 	TEST(mq_unlink(QUEUE_NAME));
311 
312 	switch (tc->ttype) {
313 	case FD_NOT_EXIST:
314 		fd = INT_MAX - 1;
315 		/* fallthrough */
316 	case FD_NONE:
317 		break;
318 	case FD_FILE:
319 		TEST(fd = open("/", O_RDONLY));
320 		if (TEST_RETURN < 0) {
321 			tst_resm(TFAIL | TTERRNO, "can't open \"/\".");
322 			result = 1;
323 			goto EXIT;
324 		}
325 		break;
326 	default:
327 		/*
328 		 * Open message queue
329 		 */
330 		oflag = O_CREAT | O_EXCL | O_RDWR;
331 		if (tc->non_block)
332 			oflag |= O_NONBLOCK;
333 
334 		TEST(fd = mq_open(QUEUE_NAME, oflag, S_IRWXU, NULL));
335 		if (TEST_RETURN < 0) {
336 			tst_resm(TFAIL | TTERRNO, "mq_open failed");
337 			result = 1;
338 			goto EXIT;
339 		}
340 
341 		if (tc->ttype == SEND_SIGINT) {
342 			pid = create_sig_proc(200000, SIGINT, UINT_MAX);
343 			if (pid < 0) {
344 				result = 1;
345 				goto EXIT;
346 			}
347 		}
348 		break;
349 	}
350 
351 	/*
352 	 * Prepare send message
353 	 */
354 	for (i = 0; i < tc->len; i++)
355 		smsg[i] = i;
356 
357 	/*
358 	 * Send message
359 	 */
360 	switch (tc->ttype) {
361 	case EMPTY_QUEUE:
362 	case SEND_SIGINT:
363 	case FD_NONE:
364 	case FD_NOT_EXIST:
365 	case FD_FILE:
366 		break;
367 	default:
368 		TEST(rc = mq_timedsend(fd, smsg, tc->len, tc->prio, &ts));
369 		if (TEST_RETURN < 0) {
370 			tst_resm(TFAIL | TTERRNO, "mq_timedsend failed");
371 			result = 1;
372 			goto EXIT;
373 		}
374 		break;
375 	}
376 
377 	/*
378 	 * Set the message length and timeout value
379 	 */
380 	msg_len = MAX_MSGSIZE;
381 	if (tc->ttype == INVALID_MSG_LEN)
382 		msg_len -= 1;
383 	ts.tv_sec = tc->sec;
384 	ts.tv_nsec = tc->nsec;
385 	if (tc->sec >= 0 || tc->nsec != 0)
386 		ts.tv_sec += time(NULL);
387 
388 	/*
389 	 * Execute system call
390 	 */
391 	errno = 0;
392 	TEST(sys_ret = mq_timedreceive(fd, rmsg, msg_len, &prio, &ts));
393 	sys_errno = errno;
394 	if (sys_ret < 0)
395 		goto TEST_END;
396 
397 	/*
398 	 * Compare received message
399 	 */
400 	if (sys_ret != tc->len || tc->prio != prio)
401 		cmp_ok = 0;
402 	else {
403 		for (i = 0; i < tc->len; i++)
404 			if (rmsg[i] != smsg[i]) {
405 				cmp_ok = 0;
406 				break;
407 			}
408 	}
409 
410 TEST_END:
411 	/*
412 	 * Check results
413 	 */
414 	result |= (sys_errno != tc->err) || !cmp_ok;
415 	PRINT_RESULT_CMP(0, tc->ret == 0 ? tc->len : tc->ret, tc->err, sys_ret,
416 			 sys_errno, cmp_ok);
417 
418 EXIT:
419 	if (fd >= 0) {
420 		TEST(close(fd));
421 		TEST(mq_unlink(QUEUE_NAME));
422 	}
423 	if (pid > 0) {
424 		int st;
425 		TEST(kill(pid, SIGTERM));
426 		TEST(wait(&st));
427 	}
428 	return result;
429 }
430 
431 /*
432  * main()
433  */
434 
main(int ac,char ** av)435 int main(int ac, char **av)
436 {
437 	int result = RESULT_OK;
438 	int i;
439 	int lc;
440 
441 	tst_parse_opts(ac, av, NULL, NULL);
442 
443 	setup();
444 
445 	for (lc = 0; TEST_LOOPING(lc); ++lc) {
446 		tst_count = 0;
447 		for (testno = 0; testno < TST_TOTAL; ++testno) {
448 
449 			/*
450 			 * Execute test
451 			 */
452 			for (i = 0; i < (int)ARRAY_SIZE(tcase); i++) {
453 				int ret;
454 				tst_resm(TINFO, "(case%02d) START", i);
455 				ret = do_test(&tcase[i]);
456 				tst_resm(TINFO, "(case%02d) END => %s",
457 					 i, (ret == 0) ? "OK" : "NG");
458 				result |= ret;
459 			}
460 
461 			/*
462 			 * Check results
463 			 */
464 			switch (result) {
465 			case RESULT_OK:
466 				tst_resm(TPASS,
467 					 "mq_timedreceive call succeeded");
468 				break;
469 
470 			default:
471 				tst_brkm(TFAIL | TTERRNO, cleanup,
472 					 "mq_timedreceive failed");
473 			}
474 		}
475 	}
476 	cleanup();
477 	tst_exit();
478 }
479