arm, uclibc: testcase mq_timedsend is no return

Xishi Qiu qiuxishi at huawei.com
Sat Sep 20 10:52:24 UTC 2014


Hi,

I test this case, and find "case14" is no return, (use arm32 platform and uclibc).

It is this function "mq_timedsend", and program keeps watting for the return.
"sys_ret = mq_timedsend(fd, smsg, tc->len, tc->prio, p_ts);" please see the following code.

Is this a test code's problem or uclibc's problem?

Thanks,
Xishi Qiu


Here is the test code:

/*
 * Crackerjack Project
 *
 * Copyright (C) 2007-2008, Hitachi, Ltd.
 * Author(s): Takahiro Yasui <takahiro.yasui.mp at hitachi.com>,
 *            Yumiko Sugita <yumiko.sugita.yf at hitachi.com>,
 *            Satoshi Fujiwara <sa-fuji at sdl.hitachi.co.jp>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * $Id:$
 *
 */

#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <getopt.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <mqueue.h>
#include <time.h>
#include <signal.h>
#include <limits.h>

#include "../../common.j.h/include_j_h.h"

/*
 * Macros
 */
#define SYSCALL_NAME	"mq_timedsend"


/*
 * Global variables
 */
static int opt_debug;
static char *progname;


/*
 * Data Structure
 */
struct test_case {
	int ttype;
	int non_block;
	int len;
	unsigned prio;
	time_t sec;
	long nsec;
	int ret;
	int err;
};


enum test_type {
	NORMAL,
	FD_NONE,
	FD_NOT_EXIST,
	FD_FILE,
	FULL_QUEUE,
	SEND_SIGINT,
};
#define MAX_MSG		10
#define MAX_MSGSIZE	8192


/* Test cases
 *
 *   test status of errors on man page
 *
 *   EAGAIN		v (would block)
 *   EBADF		v (not a valid descriptor)
 *   EINTR		v (interrupted by a signal)
 *   EINVAL		v (1. invalid 'msg_prio' or
 *                         2. would block but timeout exists)
 *   EMSGSIZE		v ('msg_len' exceeds the message size of the queue)
 *   ETIMEDOUT		v (not block and timeout occured)
 */
static struct test_case tcase[] = {
	{ // case00
		.ttype		= NORMAL,
		.len		= 0,	// also success when size equals zero
		.ret		= 0,
		.err		= 0,
	},
	{ // case01
		.ttype		= NORMAL,
		.len		= 1,
		.ret		= 0,
		.err		= 0,
	},
	{ // case02
		.ttype		= NORMAL,
		.len		= MAX_MSGSIZE,
		.ret		= 0,
		.err		= 0,
	},
	{ // case03
		.ttype		= NORMAL,
		.len		= 1,
		.prio		= 32767, // max priority
		.ret		= 0,
		.err		= 0,
	},
	{ // case04
		.ttype		= NORMAL,
		.len		= MAX_MSGSIZE + 1,
		.ret		= -1,
		.err		= EMSGSIZE,
	},
	{ // case05
		.ttype		= FD_NONE,
		.len		= 0,
		.ret		= -1,
		.err		= EBADF,
	},
	{ // case06
		.ttype		= FD_NOT_EXIST,
		.len		= 0,
		.ret		= -1,
		.err		= EBADF,
	},
	{ // case07
		.ttype		= FD_FILE,
		.len		= 0,
		.ret		= -1,
		.err		= EBADF,
	},
	{ // case08
		.ttype		= FULL_QUEUE,
		.non_block	= 1,
		.len		= 16,
		.ret		= -1,
		.err		= EAGAIN,
	},
	{ // case09
		.ttype		= NORMAL,
		.len		= 1,
		.prio		= 32768, // max priority + 1
		.ret		= -1,
		.err		= EINVAL,
	},
	{ // case10
		.ttype		= FULL_QUEUE,
		.len		= 16,
		.sec		= -1,
		.nsec		= 0,
		.ret		= -1,
		.err		= EINVAL,
	},
	{ // case11
		.ttype		= FULL_QUEUE,
		.len		= 16,
		.sec		= 0,
		.nsec		= -1,
		.ret		= -1,
		.err		= EINVAL,
	},
	{ // case12
		.ttype		= FULL_QUEUE,
		.len		= 16,
		.sec		= 0,
		.nsec		= 1000000000,
		.ret		= -1,
		.err		= EINVAL,
	},
	{ // case13
		.ttype		= FULL_QUEUE,
		.len		= 16,
		.sec		= 0,
		.nsec		= 999999999,
		.ret		= -1,
		.err		= ETIMEDOUT,
	},
	{ // case14
		.ttype		= SEND_SIGINT,
		.len		= 16,
		.ret		= -1,
		.err		= EINTR,
	},
};


/*
 * do_test()
 *
 *   Input  : TestCase Data
 *   Return : RESULT_OK(0), RESULT_NG(1)
 *
 */
static int do_test(struct test_case *tc)
{
	int sys_ret;
	int sys_errno;
	int result = RESULT_OK;
	int oflag;
	int i, rc, cmp_ok = 1, fd = -1;
	char smsg[MAX_MSGSIZE], rmsg[MAX_MSGSIZE];
	struct timespec ts, *p_ts;
	pid_t pid = 0;
	unsigned prio;

	/*
	 * When test ended with SIGTERM etc, mq discriptor is left remains.
	 * So we delete it first.
	 */
	mq_unlink(QUEUE_NAME);

	switch (tc->ttype) {
	case FD_NOT_EXIST:
		fd = INT_MAX - 1;
		/* fallthrough */
	case FD_NONE:
		break;
	case FD_FILE:
		fd = open("/", O_RDONLY);
		if (fd < 0) {
			EPRINTF("can't open \"/\".\n");
			result = 1;
			goto EXIT;
		}
		break;
	default:
		/*
		 * Open message queue
		 */
		oflag = O_CREAT|O_EXCL|O_RDWR;
		if (tc->non_block)
			oflag |= O_NONBLOCK;

		fd = mq_open(QUEUE_NAME, oflag, S_IRWXU, NULL);
		if (fd < 0) {
			EPRINTF("mq_open failed. %d %d\n", fd, errno);
			result = 1;
			goto EXIT;
		}
		if (tc->ttype == FULL_QUEUE || tc->ttype == SEND_SIGINT) {
			for (i = 0; i < MAX_MSG; i++) {
				rc = mq_timedsend(fd, smsg, tc->len, 0, NULL);
				if (rc < 0) {
					EPRINTF("mq_timedsend failed.\n");
					result = 1;
					goto EXIT;
				}
			}
			if (tc->ttype == SEND_SIGINT) {
				pid = create_sig_proc(200000, SIGINT);
				if (pid < 0) {
					result = 1;
					goto EXIT;
				}
			}
		}
		break;
	}

	/*
	 * Prepare send message
	 */
	for (i = 0; i < tc->len; i++)
		smsg[i] = i;

	/*
	 * Set the timeout value
	 */
	ts.tv_sec = tc->sec;
	ts.tv_nsec = tc->nsec;
	p_ts = &ts;
	if (tc->sec == 0 && tc->nsec == 0)
		p_ts = NULL;

	/*
	 * Execute system call
	 */
	errno = 0;
	sys_ret = mq_timedsend(fd, smsg, tc->len, tc->prio, p_ts);  ————> // Here is no return
	sys_errno = errno;
	if (sys_ret < 0)
		goto TEST_END;

	/*
	 * Receive echoed message and compare
	 */
	rc = mq_timedreceive(fd, rmsg, MAX_MSGSIZE, &prio, NULL);
	if (rc < 0) {
		EPRINTF("mq_timedreceive failed.\n");
		result = 1;
		goto EXIT;
	}
	if (rc != tc->len || tc->prio != prio)
		cmp_ok = 0;
	else {
		for (i = 0; i < tc->len; i++)
			if (rmsg[i] != smsg[i]) {
				cmp_ok = 0;
				break;
			}
	}

TEST_END:
	/*
	 * Check results
	 */
	result |= (sys_errno != tc->err) || !cmp_ok;
	PRINT_RESULT_CMP(sys_ret >= 0, tc->ret, tc->err, sys_ret, sys_errno,
			 cmp_ok);

EXIT:
	if (fd >= 0) {
		close(fd);
		mq_unlink(QUEUE_NAME);
	}
	if (pid > 0) {
		int st;
		kill(pid, SIGTERM);
		wait(&st);
	}
	return result;
}


/*
 * sighandler()
 */
void sighandler(int sig)
{
	if (sig == SIGINT)
		return;
	// NOTREACHED
	return;
}


/*
 * usage()
 */
static void usage(const char *progname)
{
	EPRINTF("usage: %s [options]\n", progname);
	EPRINTF("This is a regression test program of %s system call.\n",
		SYSCALL_NAME);
	EPRINTF("options:\n");
	EPRINTF("    -d --debug           Show debug messages\n");
	EPRINTF("    -h --help            Show this message\n");

	RPRINTF("NG\n");
	exit(1);
}


/*
 * main()
 */
int main(int argc, char *argv[])
{
	int result = RESULT_OK;
	int c;
	int i;

	struct option long_options[] = {
		{ "debug", no_argument, 0, 'd' },
		{ "help",  no_argument, 0, 'h' },
		{ NULL, 0, NULL, 0 }
	};

	progname = strchr(argv[0], '/');
	progname = progname ? progname + 1 : argv[0];

	while ((c = getopt_long(argc, argv, "dh", long_options, NULL)) != -1) {
		switch (c) {
		case 'd':
			opt_debug = 1;
			break;

		default:
			usage(progname);
			// NOTREACHED
		}
	}

	if (argc != optind) {
		EPRINTF("Options are not match.\n");
		usage(progname);
		// NOTREACHED
	}

	/*
	 * Execute test
	 */
	signal(SIGINT, sighandler);
	for (i = 0; i < (int)(sizeof(tcase) / sizeof(tcase[0])); i++) {
		int ret;

		PRINTF("(case%02d) START\n", i);
		ret = do_test(&tcase[i]);
		PRINTF("(case%02d) END => %s\n", i, (ret == 0) ? "OK" : "NG");

		result |= ret;
	}

	/*
	 * Check results
	 */
	switch(result) {
	case RESULT_OK:
		RPRINTF("OK\n");
		break;

	default:
		RPRINTF("NG\n");
		break;
	}

	return 0;
}

...

pid_t create_sig_proc(unsigned long usec, int sig)
{
    pid_t pid, cpid;

    signal(SIGUSR2, sighandler_for_sig_proc);
    pid = getpid();
    cpid = fork();
    switch (cpid) {
    case 0:
        pause();
        usleep(usec);
        kill(pid, sig);
        _exit(0);
        break;
    case -1:
        EPRINTF("fork failed.\n");
        return cpid;
    default:
        sleep(10) ; /* workaround to run parent process before child */
        kill(cpid, SIGUSR2);
        return cpid;
    }
}




More information about the uClibc mailing list