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