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}