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/* 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#include "test.h" 67#include "linux_syscall_numbers.h" 68 69char *TCID = "mq_timedsend01"; 70int testno; 71int TST_TOTAL = 1; 72struct sigaction act; 73 74/* 75 * sighandler() 76 */ 77void 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/******************************************************************************/ 102void 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/******************************************************************************/ 126void 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 144enum 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 */ 156struct 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 183static 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 297static 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 } 413TEST_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 421EXIT: 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 438int 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