aboutsummaryrefslogtreecommitdiff
path: root/testcases/open_posix_testsuite/conformance/interfaces/mq_send/5-2.c
blob: 7a8b3ba359795e732f51e1b6cef90c6721e9c41d (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
136
137
138
139
140
141
142
143
144
/*
 * 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 that if the message queue is full and O_NONBLOCK is not set, mq_send()
 * will block until 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 the child.  Test passes if send was interrupted
 * by the signal.
 */

#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_5-2_%d", getpid());

	attr.mq_msgsize = BUFFER;
	attr.mq_maxmsg = MAXMSG;
	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, blocking = 0;

		for (j = 0; j < MAXMSG + 1; j++) {	// "infinite" loop
			if (sleep(3) == 0) {
				/* If sleep finished, child is probably blocking */
				blocking = 1;	//set blocking flag
				kill(pid, SIGABRT);	//signal child
				break;
			}
		}

		if (blocking != 1) {
			printf("Signal never blocked\n");
			kill(pid, SIGKILL);	//kill child if not gone
			mq_close(gqueue);
			mq_unlink(gqname);
			return PTS_UNRESOLVED;
		}

		if (wait(&k) == -1) {
			perror("Error waiting for child to exit\n");
			kill(pid, SIGKILL);	//kill child if not gone
			mq_close(gqueue);
			mq_unlink(gqname);
			return PTS_UNRESOLVED;
		}
		mq_close(gqueue);
		if (mq_unlink(gqname) != 0) {
			perror("mq_unlink()");
			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;
}