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