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