1/*
2 * Copyright (c) 2003, Intel Corporation. All rights reserved.
3 * Created by:  julie.n.fleischer REMOVE-THIS AT intel DOT com
4 * This file is licensed under the GPL license.  For the full content
5 * of this license, see the COPYING file at the top level of this
6 * source tree.
7 */
8
9/*
10 * Test that if the message queue is full and O_NONBLOCK is not set,
11 * mq_timedsend() will block until abs_timeout is reached.
12 *
13 * Test by sending messages in a child process until the message queue is full.
14 * At this point, the child should be blocking on sending.  Then, have the
15 * parent wait for the timeout and return pass when the next message is sent
16 * to the message queue.
17 */
18
19#include <stdio.h>
20#include <mqueue.h>
21#include <fcntl.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <time.h>
26#include <unistd.h>
27#include <string.h>
28#include <stdlib.h>
29#include <stdint.h>
30#include <signal.h>
31#include <errno.h>
32#include "posixtest.h"
33
34#define NAMESIZE 50
35#define MSGSTR "0123456789"
36#define BUFFER 40
37#define MAXMSG 5
38
39#define TIMEOUT 7
40
41#define CHILDPASS 1
42#define CHILDFAIL 0
43
44char gqname[NAMESIZE];
45mqd_t gqueue;
46
47/*
48 * This handler is just used to catch the signal and stop sleep (so the
49 * parent knows the child is still busy sending signals).
50 */
51void stopsleep_handler(int signo)
52{
53	return;
54}
55
56int main()
57{
58	int pid;
59	struct mq_attr attr;
60        const char *msgptr = MSGSTR;
61
62        sprintf(gqname, "/mq_timedsend_5-3_%d", getpid());
63
64	attr.mq_maxmsg = MAXMSG;
65	attr.mq_msgsize = BUFFER;
66        gqueue = mq_open(gqname, O_CREAT |O_RDWR, S_IRUSR | S_IWUSR, &attr);
67        if (gqueue == (mqd_t)-1) {
68                perror("mq_open() did not return success");
69                return PTS_UNRESOLVED;
70        }
71
72	if ((pid = fork()) == 0) {
73		/* child here */
74		int i, sig;
75		struct timespec ts;
76		sigset_t mask;
77
78		/* wait for parent to set up handler */
79		sigemptyset(&mask);
80		sigaddset(&mask, SIGUSR1);
81		sigprocmask(SIG_BLOCK,&mask,NULL);
82		sigwait(&mask, &sig);
83
84		/* child should block in < TIMEOUT seconds */
85		ts.tv_sec=time(NULL)+TIMEOUT;
86		ts.tv_nsec=0;
87
88		for (i=0; i<MAXMSG+1; i++) {
89        		if (mq_timedsend(gqueue, msgptr,
90						strlen(msgptr), 1, &ts) != 0) {
91				/* send will fail after timeout occurs*/
92				kill(getppid(), SIGABRT);
93				return CHILDPASS;
94        		}
95			/* send signal to parent each time message is sent */
96			kill(getppid(), SIGABRT);
97		}
98		printf("Child never interrupted\n");
99		return CHILDFAIL;
100	} else {
101		/* parent here */
102		struct sigaction act;
103		int j;
104
105		/* parent runs stopsleep_handler when sleep is interrupted
106                   by child */
107		act.sa_handler=stopsleep_handler;
108		act.sa_flags=0;
109		sigemptyset(&act.sa_mask);
110		sigaction(SIGABRT, &act, 0);
111
112		/* wait 1 second and tell child handler is set up */
113		sleep(1);
114		kill(pid, SIGUSR1);
115
116		/* wait for heartbeats from child */
117		for (j=0; j<MAXMSG+1; j++) {
118			if (sleep(3) == 0) {
119			/* If sleep finished, child is probably blocking */
120				break;
121			}
122		}
123
124		if (j == MAXMSG+1) {
125			printf("Child never blocked\n");
126			printf("Test FAILED\n");
127			kill(pid, SIGKILL); //kill child
128			mq_close(gqueue);
129			mq_unlink(gqname);
130			return PTS_FAIL;
131		}
132
133		/*
134		 * Wait for timeout to complete.
135		 */
136		if (sleep(TIMEOUT) == 0) {
137			/*
138		 	* If sleep lasted the full time, child never timed out
139		 	*/
140			printf("Child never timed out\n");
141			kill(pid, SIGKILL); //kill child
142			mq_close(gqueue);
143			mq_unlink(gqname);
144			printf("Test FAILED\n");
145			return PTS_FAIL;
146		}
147
148		mq_close(gqueue);
149		mq_unlink(gqname);
150		printf("Test PASSED\n");
151		return PTS_PASS;
152	}
153
154	return PTS_UNRESOLVED;
155}
156
157