• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 mq_timedsend() will set errno == EINTR if it is interrupted by a signal.
11  *
12  * Steps:
13  * 1. Create a thread and set up a signal handler for SIGUSR1
14  * 2. Thread indicates to main that it is ready to start calling mq_timedsend
15  *    until it blocks for a timeout of 10 seconds.
16  * 3. In main, send the thread the SIGUSR1 signal while mq_timedsend is
17  *    blocking.
18  * 4. Check to make sure that mq_timedsend blocked, and that it returned
19  *    EINTR when it was interrupted by SIGUSR1.
20  */
21 
22 #include <stdio.h>
23 #include <pthread.h>
24 #include <mqueue.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/wait.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 <time.h>
36 #include "posixtest.h"
37 
38 #define NAMESIZE 50
39 #define MSGSTR "0123456789"
40 #define BUFFER 40
41 #define MAXMSG 10
42 #define TIMEOUT 10		/* seconds mq_timedsend will block */
43 #define SIGNAL_DELAY_MS 50	/* delay in ms between 2 signals */
44 
45 #define error_and_exit(en, msg) \
46 	do { errno = en; perror(msg); exit(PTS_UNRESOLVED); } while (0)
47 
48 /* variable to indicate how many times signal handler was called */
49 static volatile int in_handler;
50 
51 /* errno returned by mq_timedsend() */
52 static int mq_timedsend_errno = -1;
53 
54 static pthread_barrier_t barrier;
55 
56 /*
57  * This handler is just used to catch the signal and stop sleep (so the
58  * parent knows the child is still busy sending signals).
59  */
justreturn_handler(int signo PTS_ATTRIBUTE_UNUSED)60 static void justreturn_handler(int signo PTS_ATTRIBUTE_UNUSED)
61 {
62 	in_handler++;
63 }
64 
a_thread_func(void * arg PTS_ATTRIBUTE_UNUSED)65 static void *a_thread_func(void *arg PTS_ATTRIBUTE_UNUSED)
66 {
67 	int i, ret;
68 	struct sigaction act;
69 	char gqname[NAMESIZE];
70 	mqd_t gqueue;
71 	const char *msgptr = MSGSTR;
72 	struct mq_attr attr;
73 	struct timespec ts;
74 
75 	/* Set up handler for SIGUSR1 */
76 	act.sa_handler = justreturn_handler;
77 	act.sa_flags = 0;
78 	sigemptyset(&act.sa_mask);
79 	sigaction(SIGUSR1, &act, 0);
80 
81 	/* Set up mq */
82 	sprintf(gqname, "/mq_timedsend_12-1_%d", getpid());
83 
84 	attr.mq_maxmsg = MAXMSG;
85 	attr.mq_msgsize = BUFFER;
86 	gqueue = mq_open(gqname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR, &attr);
87 	if (gqueue == (mqd_t) -1)
88 		error_and_exit(errno, "mq_open");
89 
90 	/* mq_timedsend will block for TIMEOUT seconds when it waits */
91 	ts.tv_sec = time(NULL) + TIMEOUT;
92 	ts.tv_nsec = 0;
93 
94 	/* main can now start sending SIGUSR1 signal */
95 	ret = pthread_barrier_wait(&barrier);
96 	if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
97 		error_and_exit(ret, "pthread_barrier_wait start");
98 
99 	for (i = 0; i < MAXMSG + 1; i++) {
100 		ret = mq_timedsend(gqueue, msgptr, strlen(msgptr), 1, &ts);
101 		if (ret == -1) {
102 			mq_timedsend_errno = errno;
103 			break;
104 		}
105 	}
106 
107 	if (mq_unlink(gqname) != 0)
108 		error_and_exit(errno, "mq_unlink");
109 
110 	switch (mq_timedsend_errno) {
111 	case -1:
112 		mq_timedsend_errno = 0;
113 		printf("Error: mq_timedsend wasn't interrupted\n");
114 		break;
115 	case EINTR:
116 		printf("thread: mq_timedsend interrupted by signal"
117 			" and correctly set errno to EINTR\n");
118 		break;
119 	default:
120 		printf("mq_timedsend not interrupted by signal or"
121 			" set errno to incorrect code: %d\n",
122 			mq_timedsend_errno);
123 		break;
124 	}
125 
126 	/* wait until main stops sending signals */
127 	ret = pthread_barrier_wait(&barrier);
128 	if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
129 		error_and_exit(ret, "pthread_barrier_wait end");
130 	pthread_exit(NULL);
131 }
132 
main(void)133 int main(void)
134 {
135 	pthread_t new_th;
136 	int i = 0, ret;
137 
138 	ret = pthread_barrier_init(&barrier, NULL, 2);
139 	if (ret != 0)
140 		error_and_exit(ret, "pthread_barrier_init");
141 
142 	ret = pthread_create(&new_th, NULL, a_thread_func, NULL);
143 	if (ret != 0)
144 		error_and_exit(ret, "pthread_create");
145 
146 	/* wait for thread to start */
147 	ret = pthread_barrier_wait(&barrier);
148 	if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
149 		error_and_exit(ret, "pthread_barrier_wait start");
150 
151 	struct timespec completion_wait_ts = {0, SIGNAL_DELAY_MS*1000000};
152 	while (i < TIMEOUT*1000 && mq_timedsend_errno < 0) {
153 		/* signal thread while it's in mq_timedsend */
154 		ret = pthread_kill(new_th, SIGUSR1);
155 		if (ret != 0)
156 			error_and_exit(ret, "pthread_kill");
157 		nanosleep(&completion_wait_ts, NULL);
158 		i += SIGNAL_DELAY_MS;
159 	}
160 
161 	/* thread can now safely exit */
162 	ret = pthread_barrier_wait(&barrier);
163 	if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
164 		error_and_exit(ret, "pthread_barrier_wait end");
165 
166 	ret = pthread_join(new_th, NULL);
167 	if (ret != 0)
168 		error_and_exit(ret, "pthread_join");
169 
170 	/* Test to see if the thread blocked correctly in mq_timedsend,
171 	 * and if it returned EINTR when it caught the signal */
172 	if (mq_timedsend_errno != EINTR) {
173 		printf("Error: mq_timedsend was NOT interrupted\n");
174 		printf(" signal handler was called %d times\n", in_handler);
175 		printf(" SIGUSR1 signals sent: %d\n", i);
176 		printf(" last mq_timedsend errno: %d %s\n",
177 			mq_timedsend_errno, strerror(mq_timedsend_errno));
178 		if (in_handler == 0) {
179 			printf("Error: SIGUSR1 was never received\n");
180 			return PTS_UNRESOLVED;
181 		}
182 		return PTS_FAIL;
183 	}
184 
185 	ret = pthread_barrier_destroy(&barrier);
186 	if (ret != 0)
187 		error_and_exit(ret, "pthread_barrier_destroy");
188 
189 	printf("Test PASSED\n");
190 	return PTS_PASS;
191 }
192