mq_timedreceive01.c revision 60fa8014af7534eaefa901200c8df4b74ce422e6
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 <stdlib.h> 55#include <errno.h> 56#include <stdio.h> 57#include <unistd.h> 58#include <string.h> 59#include <mqueue.h> 60#include <time.h> 61#include <signal.h> 62#include <limits.h> 63 64 65#include "../utils/include_j_h.h" 66#include "../utils/common_j_h.c" 67 68/* Harness Specific Include Files. */ 69#include "test.h" 70#include "usctest.h" 71#include "linux_syscall_numbers.h" 72 73/* Extern Global Variables */ 74extern int Tst_count; /* counter for tst_xxx routines. */ 75extern char *TESTDIR; /* temporary dir created by tst_tmpdir() */ 76 77/* Global Variables */ 78char *TCID = "mq_timedreceive01"; /* Test program identifier.*/ 79int testno; 80int TST_TOTAL = 1; /* total number of tests in this file. */ 81struct sigaction act; 82 83/* 84 * sighandler() 85 */ 86void sighandler(int sig) 87{ 88 if (sig == SIGINT) 89 return; 90 // NOTREACHED 91 return; 92} 93 94/* Extern Global Functions */ 95/******************************************************************************/ 96/* */ 97/* Function: cleanup */ 98/* */ 99/* Description: Performs all one time clean up for this test on successful */ 100/* completion, premature exit or failure. Closes all temporary */ 101/* files, removes all temporary directories exits the test with */ 102/* appropriate return code by calling tst_exit() function. */ 103/* */ 104/* Input: None. */ 105/* */ 106/* Output: None. */ 107/* */ 108/* Return: On failure - Exits calling tst_exit(). Non '0' return code. */ 109/* On success - Exits calling tst_exit(). With '0' return code. */ 110/* */ 111/******************************************************************************/ 112extern void cleanup() { 113 /* Remove tmp dir and all files in it */ 114 TEST_CLEANUP; 115 tst_rmdir(); 116 117 /* Exit with appropriate return code. */ 118 tst_exit(); 119} 120 121 122/* Local Functions */ 123/******************************************************************************/ 124/* */ 125/* Function: setup */ 126/* */ 127/* Description: Performs all one time setup for this test. This function is */ 128/* typically used to capture signals, create temporary dirs */ 129/* and temporary files that may be used in the course of this */ 130/* test. */ 131/* */ 132/* Input: None. */ 133/* */ 134/* Output: None. */ 135/* */ 136/* Return: On failure - Exits by calling cleanup(). */ 137/* On success - returns 0. */ 138/* */ 139/******************************************************************************/ 140void setup() { 141 /* Capture signals if any */ 142 act.sa_handler = sighandler; 143 sigfillset(&act.sa_mask); 144 sigaction(SIGINT, &act, NULL); 145 /* Create temporary directories */ 146 TEST_PAUSE; 147 tst_tmpdir(); 148} 149 150 151/* 152 * Macros 153 */ 154#define SYSCALL_NAME "mq_timedreceive" 155 156 157/* 158 * Global variables 159 */ 160static int opt_debug; 161static char *progname; 162 163enum test_type { 164 NORMAL, 165 FD_NONE, 166 FD_NOT_EXIST, 167 FD_FILE, 168 INVALID_MSG_LEN, 169 EMPTY_QUEUE, 170 SEND_SIGINT, 171}; 172 173 174/* 175 * Data Structure 176 */ 177struct test_case { 178 int ttype; 179 int non_block; 180 int len; 181 unsigned prio; 182 time_t sec; 183 long nsec; 184 int ret; 185 int err; 186}; 187 188#define MAX_MSG 10 189#define MAX_MSGSIZE 8192 190 191/* Test cases 192 * 193 * test status of errors on man page 194 * 195 * EAGAIN v (would block) 196 * EBADF v (not a valid descriptor) 197 * EINTR v (interrupted by a signal) 198 * EINVAL v (invalid timeout value) 199 * ETIMEDOUT v (not block and timeout occured) 200 * EMSGSIZE v ('msg_len' is less than the message size of the queue) 201 * EBADMSG can't check because this error never occur 202 */ 203static struct test_case tcase[] = { 204 { // case00 205 .ttype = NORMAL, 206 .len = 0, // also success when size equals zero 207 .ret = 0, 208 .err = 0, 209 }, 210 { // case01 211 .ttype = NORMAL, 212 .len = 1, 213 .ret = 0, 214 .err = 0, 215 }, 216 { // case02 217 .ttype = NORMAL, 218 .len = MAX_MSGSIZE, 219 .ret = 0, 220 .err = 0, 221 }, 222 { // case03 223 .ttype = NORMAL, 224 .len = 1, 225 .prio = 32767, // max priority 226 .ret = 0, 227 .err = 0, 228 }, 229 { // case04 230 .ttype = INVALID_MSG_LEN, 231 .len = 0, 232 .ret = -1, 233 .err = EMSGSIZE, 234 }, 235 { // case05 236 .ttype = FD_NONE, 237 .len = 0, 238 .ret = -1, 239 .err = EBADF, 240 }, 241 { // case06 242 .ttype = FD_NOT_EXIST, 243 .len = 0, 244 .ret = -1, 245 .err = EBADF, 246 }, 247 { // case07 248 .ttype = FD_FILE, 249 .len = 0, 250 .ret = -1, 251 .err = EBADF, 252 }, 253 { // case08 254 .ttype = EMPTY_QUEUE, 255 .non_block = 1, 256 .len = 16, 257 .ret = -1, 258 .err = EAGAIN, 259 }, 260 { // case09 261 .ttype = EMPTY_QUEUE, 262 .len = 16, 263 .sec = -1, 264 .nsec = 0, 265 .ret = -1, 266 .err = EINVAL, 267 }, 268 { // case10 269 .ttype = EMPTY_QUEUE, 270 .len = 16, 271 .sec = 0, 272 .nsec = -1, 273 .ret = -1, 274 .err = EINVAL, 275 }, 276 { // case11 277 .ttype = EMPTY_QUEUE, 278 .len = 16, 279 .sec = 0, 280 .nsec = 1000000000, 281 .ret = -1, 282 .err = EINVAL, 283 }, 284 { // case12 285 .ttype = EMPTY_QUEUE, 286 .len = 16, 287 .sec = 0, 288 .nsec = 999999999, 289 .ret = -1, 290 .err = ETIMEDOUT, 291 }, 292 { // case13 293 .ttype = SEND_SIGINT, 294 .len = 16, 295 .sec = 3, 296 .nsec = 0, 297 .ret = -1, 298 .err = EINTR, 299 }, 300}; 301 302 303 304 305#define MEM_LENGTH (4 * 1024 * 1024) 306/* 307 * do_test() 308 * 309 * Input : TestCase Data 310 * Return : RESULT_OK(0), RESULT_NG(1) 311 * 312 */ 313 314static int do_test(struct test_case *tc) 315{ 316 int sys_ret; 317 int sys_errno; 318 int result = RESULT_OK; 319 int oflag; 320 int i, rc, cmp_ok = 1, fd = -1; 321 char smsg[MAX_MSGSIZE], rmsg[MAX_MSGSIZE]; 322 struct timespec ts = {0,0}; 323 pid_t pid = 0; 324 unsigned prio; 325 size_t msg_len; 326 327 /* 328 * When test ended with SIGTERM etc, mq discriptor is left remains. 329 * So we delete it first. 330 */ 331 TEST(mq_unlink(QUEUE_NAME)); 332 333switch (tc->ttype) { 334 case FD_NOT_EXIST: 335 fd = INT_MAX - 1; 336 /* fallthrough */ 337 case FD_NONE: 338 break; 339 case FD_FILE: 340 TEST(fd = open("/", O_RDONLY)); 341 if (TEST_RETURN < 0) { 342 tst_resm(TFAIL, "can't open \"/\". - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO)); 343 result = 1; 344 goto EXIT; 345 } 346 break; 347 default: 348 /* 349 * Open message queue 350 */ 351 oflag = O_CREAT|O_EXCL|O_RDWR; 352 if (tc->non_block) 353 oflag |= O_NONBLOCK; 354 355 TEST(fd = mq_open(QUEUE_NAME, oflag, S_IRWXU, NULL)); 356 if (TEST_RETURN < 0) { 357 tst_resm(TFAIL, "mq_open failed - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO)); 358 result = 1; 359 goto EXIT; 360 } 361 362 if (tc->ttype == SEND_SIGINT) { 363 pid = create_sig_proc(200000, SIGINT, UINT_MAX); 364 if (pid < 0) { 365 result = 1; 366 goto EXIT; 367 } 368 } 369 break; 370 } 371 372 /* 373 * Prepare send message 374 */ 375 for (i = 0; i < tc->len; i++) 376 smsg[i] = i; 377 378 /* 379 * Send message 380 */ 381 switch (tc->ttype) { 382 case EMPTY_QUEUE: 383 case SEND_SIGINT: 384 case FD_NONE: 385 case FD_NOT_EXIST: 386 case FD_FILE: 387 break; 388 default: 389 TEST(rc = mq_timedsend(fd, smsg, tc->len, tc->prio, &ts)); 390 if (TEST_RETURN < 0) { 391 tst_resm(TFAIL, "mq_timedsend failed - errno = %d : %s",TEST_ERRNO, strerror(TEST_ERRNO)); 392 result = 1; 393 goto EXIT; 394 } 395 break; 396 } 397 398 /* 399 * Set the message length and timeout value 400 */ 401 msg_len = MAX_MSGSIZE; 402 if (tc->ttype == INVALID_MSG_LEN) 403 msg_len -= 1; 404 ts.tv_sec = tc->sec; 405 ts.tv_nsec = tc->nsec; 406 if (tc->sec >= 0 || tc->nsec != 0) 407 ts.tv_sec += time(NULL); 408 409 /* 410 * Execute system call 411 */ 412 errno = 0; 413 TEST(sys_ret = mq_timedreceive(fd, rmsg, msg_len, &prio, &ts)); 414 sys_errno = errno; 415 if (sys_ret < 0) 416 goto TEST_END; 417 418 /* 419 * Compare received message 420 */ 421 if (sys_ret != tc->len || tc->prio != prio) 422 cmp_ok = 0; 423 else { 424 for (i = 0; i < tc->len; i++) 425 if (rmsg[i] != smsg[i]) { 426 cmp_ok = 0; 427 break; 428 } 429 } 430 431 432 TEST_END: 433 /* 434 * Check results 435 */ 436 result |= (sys_errno != tc->err) || !cmp_ok; 437 PRINT_RESULT_CMP(0, tc->ret == 0 ? tc->len : tc->ret, tc->err,sys_ret, sys_errno, cmp_ok); 438 439EXIT: 440 if (fd >= 0) { 441 TEST(close(fd)); 442 TEST(mq_unlink(QUEUE_NAME)); 443 } 444 if (pid > 0) { 445 int st; 446 TEST(kill(pid, SIGTERM)); 447 TEST(wait(&st)); 448 } 449 return result; 450} 451 452 453 454/* 455 * usage() 456 */ 457 458static void usage(const char *progname) 459{ 460 tst_resm(TINFO,"usage: %s [options]", progname); 461 tst_resm(TINFO,"This is a regression test program of %s system call.",SYSCALL_NAME); 462 tst_resm(TINFO,"options:"); 463 tst_resm(TINFO," -d --debug Show debug messages"); 464 tst_resm(TINFO," -h --help Show this message"); 465 tst_resm(TINFO,"NG"); 466 exit(1); 467} 468 469 470/* 471 * main() 472 */ 473 474 475 476int main(int ac, char **av) { 477 int result = RESULT_OK; 478 int c; 479 int i; 480 int lc; /* loop counter */ 481 char *msg; /* message returned from parse_opts */ 482 483 struct option long_options[] = { 484 { "debug", no_argument, 0, 'd' }, 485 { "help", no_argument, 0, 'h' }, 486 { NULL, 0, NULL, 0 } 487 }; 488 489 progname = basename(argv[0]); 490 491 /* parse standard options */ 492 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) 493 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 494 495 setup(); 496 497 /* Check looping state if -i option given */ 498 for (lc = 0; TEST_LOOPING(lc); ++lc) { 499 Tst_count = 0; 500 for (testno = 0; testno < TST_TOTAL; ++testno) { 501 TEST(c = getopt_long(ac, av, "dh", long_options, NULL)); 502 while(TEST_RETURN != -1) { 503 switch (c) { 504 case 'd': 505 opt_debug = 1; 506 break; 507 default: 508 usage(progname); 509 } 510 } 511 512 513 if (ac != optind) { 514 tst_resm(TINFO,"Options are not match."); 515 usage(progname); 516 } 517 518 /* 519 * Execute test 520 */ 521 for (i = 0; i < (int)(sizeof(tcase) / sizeof(tcase[0])); i++) { 522 int ret; 523 tst_resm(TINFO,"(case%02d) START", i); 524 ret = do_test(&tcase[i]); 525 tst_resm(TINFO,"(case%02d) END => %s", i, (ret == 0) ? "OK" : "NG"); 526 result |= ret; 527 } 528 529 /* 530 * Check results 531 */ 532 switch(result) { 533 case RESULT_OK: 534 tst_resm(TPASS, "mq_timedreceive call succeeded"); 535 break; 536 537 default: 538 tst_resm(TFAIL, "%s failed - errno = %d : %s", TCID, TEST_ERRNO, strerror(TEST_ERRNO)); 539 tst_resm(TINFO,"NG"); 540 cleanup(); 541 tst_exit(); 542 break; 543 } 544 545 } 546 } 547 cleanup(); 548 tst_exit(); 549} 550 551