aboutsummaryrefslogtreecommitdiff
path: root/testcases/open_posix_testsuite/conformance/interfaces/mq_send/12-1.c
blob: 32f59a6cd4fb713e3a0527c4dd0e62c10fac6d56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
 * Copyright (c) 2002, Intel Corporation. All rights reserved.
 * Created by:  julie.n.fleischer REMOVE-THIS AT intel DOT com
 * This file is licensed under the GPL license.  For the full content
 * of this license, see the COPYING file at the top level of this
 * source tree.
 */

/*
 * Test mq_send() will set errno == EINTR if it is interrupted by a signal.
 *
 * Have a child send signals until it starts to block.  At that point, have
 * the parent send a signal to interrupt the child.  Test passes if errno ==
 * EINVAL.
 *
 * Test very similar to 5-2.c except we don't have the additional test to
 * verify the child _was_ blocking.
 */

#include <stdio.h>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <errno.h>
#include "posixtest.h"

#define NAMESIZE 50
#define MSGSTR "0123456789"
#define BUFFER 40
#define MAXMSG 5

#define CHILDPASS 1
#define CHILDFAIL 0

char gqname[NAMESIZE];
mqd_t gqueue;

/*
 * This handler is just used to catch the signal and stop sleep (so the
 * parent knows the child is still busy sending signals).
 */
void justreturn_handler(int signo)
{
	return;
}

int main(void)
{
	int pid;
	const char *msgptr = MSGSTR;
	struct mq_attr attr;
	struct sigaction act;

	sprintf(gqname, "/mq_send_12-1_%d", getpid());

	attr.mq_maxmsg = MAXMSG;
	attr.mq_msgsize = BUFFER;
	gqueue = mq_open(gqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &attr);
	if (gqueue == (mqd_t) - 1) {
		perror("mq_open() did not return success");
		return PTS_UNRESOLVED;
	}

	/* parent and child use justreturn_handler to just return out of
	 * situations -- parent uses to stop it's sleep and wait again for
	 * the child; child uses to stop its mq_send
	 */
	act.sa_handler = justreturn_handler;
	act.sa_flags = 0;
	sigemptyset(&act.sa_mask);
	sigaction(SIGABRT, &act, 0);

	if ((pid = fork()) == 0) {
		/* child here */
		int i;

		sleep(1);	// give parent time to set up handler
		for (i = 0; i < MAXMSG + 1; i++) {
			if (mq_send(gqueue, msgptr, strlen(msgptr), 1) == -1) {
				if (errno == EINTR) {
					printf
					    ("mq_send interrupted by signal\n");
					return CHILDPASS;
				} else {
					printf
					    ("mq_send not interrupted by signal\n");
					return CHILDFAIL;
				}
			}
			/* send signal to parent each time message is sent */
			kill(getppid(), SIGABRT);
		}

		printf("Child never blocked\n");
		return CHILDFAIL;
	} else {
		/* parent here */
		int j, k;

		for (j = 0; j < MAXMSG + 1; j++) {
			if (sleep(3) == 0) {
				/* If sleep finished, child is probably blocking */
				kill(pid, SIGABRT);	//signal child
				break;
			}
		}
		mq_close(gqueue);
		if (mq_unlink(gqname) != 0) {
			perror("mq_unlink()");
			return PTS_UNRESOLVED;
		}

		if (wait(&k) == -1) {
			perror("Error waiting for child to exit\n");
			kill(pid, SIGKILL);	//kill child if not gone
			return PTS_UNRESOLVED;
		}
		if (!WIFEXITED(k) || !WEXITSTATUS(k)) {
			printf("Test FAILED\n");
			return PTS_FAIL;
		}

		printf("Test PASSED\n");
		return PTS_PASS;
	}

	return PTS_UNRESOLVED;
}