mq_timedreceive01.c revision ba18bec6ea5b3a5d57e39cd8f9b27914ed43df64
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 71char *TCID = "mq_timedreceive01"; 72int testno; 73int TST_TOTAL = 1; 74struct sigaction act; 75 76/* 77 * sighandler() 78 */ 79void 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/******************************************************************************/ 105void 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/******************************************************************************/ 130void 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 146enum 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 */ 159struct 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 */ 185static 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 293static 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 descriptor 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 410TEST_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 418EXIT: 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 435int 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