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