xref: /openbsd-src/regress/lib/libpthread/errno/errno.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /* $OpenBSD: errno.c,v 1.2 2012/02/20 02:34:33 guenther Exp $ */
2 /* PUBLIC DOMAIN Sep 2011 <guenther@openbsd.org> */
3 
4 /*
5  * Verify that &errno is different for each thread and is stable across
6  * context switches and in signal handlers
7  */
8 
9 #include <errno.h>
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 
15 #include "test.h"
16 
17 int *main_errno, *t1_errno, *t2_errno, **handler_errno;
18 pthread_t main_tid, t1_tid, t2_tid;
19 
20 enum state
21 {
22 	START,
23 	T1_START,
24 	T1_SIGNAL,
25 	T1_CHECK2,
26 	T1_EXIT,
27 } state;
28 
29 pthread_mutex_t m;
30 pthread_cond_t c;
31 sigset_t sigusr2;
32 
33 static void
34 set_state(enum state new_state)
35 {
36 	CHECKe(pthread_mutex_lock(&m));
37 	ASSERT(state == new_state - 1);
38 	state = new_state;
39 	CHECKe(pthread_cond_signal(&c));
40 	CHECKe(pthread_mutex_unlock(&m));
41 }
42 
43 static void
44 wait_for_state(enum state new_state)
45 {
46 	CHECKe(pthread_mutex_lock(&m));
47 	while(state != new_state)
48 		CHECKe(pthread_cond_wait(&c, &m));
49 	CHECKe(pthread_mutex_unlock(&m));
50 }
51 
52 
53 /*
54  * Yes, pthread_self() isn't async-signal-safe in general, but it should
55  * be okay for the regress test here
56  */
57 static void
58 act_handler(int signal)
59 {
60 	ASSERT(signal == SIGUSR1);
61 	if (handler_errno == &main_errno) {
62 		CHECKe(write(STDOUT_FILENO, "m", 1));
63 		ASSERT(&errno == main_errno);
64 		ASSERTe(errno, == EXDEV);
65 		ASSERT(pthread_equal(t1_tid, pthread_self()));
66 	} else if (handler_errno == &t1_errno) {
67 		CHECKe(write(STDOUT_FILENO, "\n", 1));
68 		ASSERT(&errno == t1_errno);
69 		ASSERTe(errno, == EXDEV);
70 		ASSERT(pthread_equal(t1_tid, pthread_self()));
71 		errno = ENODEV;
72 		CHECKe(kill(getpid(), SIGUSR2));
73 		ASSERTe(errno, == ENODEV);
74 	} else if (handler_errno == &t2_errno) {
75 		CHECKe(write(STDOUT_FILENO, "2", 1));
76 		ASSERT(&errno == t2_errno);
77 		ASSERTe(errno, == EXDEV);
78 		ASSERT(pthread_equal(t2_tid, pthread_self()));
79 	} else {
80 		PANIC("unknown thread in act_handler!");
81 	}
82 }
83 
84 void *
85 tmain(void *arg)
86 {
87 	t1_errno = &errno;
88 	ASSERT(t1_errno != main_errno);
89 	ASSERT(*t1_errno == 0);
90 
91 	/* verify preservation across switch */
92 	errno = EXDEV;
93 
94 	wait_for_state(T1_START);
95 
96 	t1_tid = pthread_self();
97 	ASSERT(pthread_equal(main_tid, t1_tid) == 0);
98 	ASSERT(&errno == t1_errno);
99 
100 	ASSERTe(*t1_errno, == EXDEV);
101 
102 	set_state(T1_SIGNAL);
103 	ASSERT(&errno == t1_errno);
104 	wait_for_state(T1_CHECK2);
105 	ASSERTe(*t1_errno, == ENODEV);
106 
107 	ASSERT(&errno == t1_errno);
108 	ASSERT(pthread_equal(t1_tid, pthread_self()));
109 
110 	set_state(T1_EXIT);
111 	return (NULL);
112 }
113 
114 int
115 main(int argc, char **argv)
116 {
117 	struct sigaction act;
118 	int r;
119 
120 	pthread_mutex_init(&m, NULL);
121 	pthread_cond_init(&c, NULL);
122 	state = START;
123 
124 	main_errno = &errno;
125 	main_tid = pthread_self();
126 
127 	act.sa_handler = act_handler;
128 	sigemptyset(&act.sa_mask);
129 	act.sa_flags = 0;
130 	errno = 0;
131 	CHECKe(sigaction(SIGUSR1, &act, NULL));
132 	ASSERT(*main_errno == 0);
133 	ASSERT(errno == 0);
134 
135 	/*
136 	 * we'll use SIGUSR2 for signal state change from act_handler,
137 	 * detecting it with sigwait(), so block it now
138 	 */
139 	CHECKe(sigaction(SIGUSR2, &act, NULL));
140 	sigemptyset(&sigusr2);
141 	sigaddset(&sigusr2, SIGUSR2);
142 	CHECKr(pthread_sigmask(SIG_BLOCK, &sigusr2, NULL));
143 
144 	sched_yield();
145 	ASSERT(&errno == main_errno);
146 
147 	/* do something to force an error */
148 	r = close(11);
149 	if (r != 0) {
150 		ASSERT(r == -1);
151 		ASSERTe(*main_errno, == EBADF);
152 		ASSERTe(errno, == EBADF);
153 	}
154 	r = write(11, "", 1);
155 	ASSERT(r == -1);
156 	ASSERTe(*main_errno, == EBADF);
157 	ASSERTe(errno, == EBADF);
158 
159 	/* verify that a succesfull syscall doesn't change errno */
160 	CHECKe(write(STDOUT_FILENO, "X", 1));
161 	ASSERTe(*main_errno, == EBADF);
162 	ASSERTe(errno, == EBADF);
163 	ASSERT(&errno == main_errno);
164 
165 	CHECKr(pthread_create(&t1_tid, NULL, tmain, NULL));
166 	ASSERTe(*main_errno, == EBADF);
167 	ASSERT(&errno == main_errno);
168 	ASSERT(pthread_equal(main_tid, pthread_self()));
169 
170 	set_state(T1_START);
171 	ASSERTe(*main_errno, == EBADF);
172 	ASSERT(&errno == main_errno);
173 
174 	wait_for_state(T1_SIGNAL);
175 	ASSERTe(*main_errno, == EBADF);
176 	ASSERT(&errno == main_errno);
177 	ASSERT(pthread_equal(main_tid, pthread_self()));
178 
179 
180 	handler_errno = &t1_errno;
181 	CHECKe(pthread_kill(t1_tid, SIGUSR1));
182 	ASSERT(&errno == main_errno);
183 
184 	CHECKr(sigwait(&sigusr2, &r));
185 	ASSERTe(*main_errno, == EBADF);
186 	ASSERT(&errno == main_errno);
187 	ASSERT(pthread_equal(main_tid, pthread_self()));
188 	set_state(T1_CHECK2);
189 
190 	wait_for_state(T1_EXIT);
191 	CHECKe(pthread_join(t1_tid, NULL));
192 	ASSERT(&errno == main_errno);
193 	ASSERT(pthread_equal(main_tid, pthread_self()));
194 
195 	SUCCEED;
196 }
197