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