Home | History | Annotate | Download | only in mq_timedsend
      1 /********************************************************************************/
      2 /* Copyright (c) Crackerjack Project., 2007-2008 ,Hitachi, Ltd			*/
      3 /*	  Author(s): Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com>,		*/
      4 /*		       Yumiko Sugita <yumiko.sugita.yf (at) hitachi.com>,		*/
      5 /*		       Satoshi Fujiwara <sa-fuji (at) 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 (at) 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  */
     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 /******************************************************************************/
    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 /******************************************************************************/
    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 
    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 
    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