xref: /openbsd/regress/lib/libpthread/errno/errno.c (revision d415bd75)
1 /* $OpenBSD: errno.c,v 1.3 2021/06/23 22:39:31 kettenis 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 		CHECKe(kill(getpid(), SIGUSR2));
72 	} else if (handler_errno == &t2_errno) {
73 		CHECKe(write(STDOUT_FILENO, "2", 1));
74 		ASSERT(&errno == t2_errno);
75 		ASSERTe(errno, == EXDEV);
76 		ASSERT(pthread_equal(t2_tid, pthread_self()));
77 	} else {
78 		PANIC("unknown thread in act_handler!");
79 	}
80 }
81 
82 void *
83 tmain(void *arg)
84 {
85 	t1_errno = &errno;
86 	ASSERT(t1_errno != main_errno);
87 	ASSERT(*t1_errno == 0);
88 
89 	/* verify preservation across switch */
90 	errno = EXDEV;
91 
92 	wait_for_state(T1_START);
93 
94 	t1_tid = pthread_self();
95 	ASSERT(pthread_equal(main_tid, t1_tid) == 0);
96 	ASSERT(&errno == t1_errno);
97 
98 	ASSERTe(*t1_errno, == EXDEV);
99 
100 	set_state(T1_SIGNAL);
101 	ASSERT(&errno == t1_errno);
102 	wait_for_state(T1_CHECK2);
103 
104 	ASSERT(&errno == t1_errno);
105 	ASSERT(pthread_equal(t1_tid, pthread_self()));
106 
107 	set_state(T1_EXIT);
108 	return (NULL);
109 }
110 
111 int
112 main(int argc, char **argv)
113 {
114 	struct sigaction act;
115 	int r;
116 
117 	pthread_mutex_init(&m, NULL);
118 	pthread_cond_init(&c, NULL);
119 	state = START;
120 
121 	main_errno = &errno;
122 	main_tid = pthread_self();
123 
124 	act.sa_handler = act_handler;
125 	sigemptyset(&act.sa_mask);
126 	act.sa_flags = 0;
127 	errno = 0;
128 	CHECKe(sigaction(SIGUSR1, &act, NULL));
129 	ASSERT(*main_errno == 0);
130 	ASSERT(errno == 0);
131 
132 	/*
133 	 * we'll use SIGUSR2 for signal state change from act_handler,
134 	 * detecting it with sigwait(), so block it now
135 	 */
136 	CHECKe(sigaction(SIGUSR2, &act, NULL));
137 	sigemptyset(&sigusr2);
138 	sigaddset(&sigusr2, SIGUSR2);
139 	CHECKr(pthread_sigmask(SIG_BLOCK, &sigusr2, NULL));
140 
141 	sched_yield();
142 	ASSERT(&errno == main_errno);
143 
144 	/* do something to force an error */
145 	r = close(11);
146 	if (r != 0) {
147 		ASSERT(r == -1);
148 		ASSERTe(*main_errno, == EBADF);
149 		ASSERTe(errno, == EBADF);
150 	}
151 	r = write(11, "", 1);
152 	ASSERT(r == -1);
153 	ASSERTe(*main_errno, == EBADF);
154 	ASSERTe(errno, == EBADF);
155 
156 	/* verify that a succesfull syscall doesn't change errno */
157 	CHECKe(write(STDOUT_FILENO, "X", 1));
158 	ASSERTe(*main_errno, == EBADF);
159 	ASSERTe(errno, == EBADF);
160 	ASSERT(&errno == main_errno);
161 
162 	CHECKr(pthread_create(&t1_tid, NULL, tmain, NULL));
163 	ASSERTe(*main_errno, == EBADF);
164 	ASSERT(&errno == main_errno);
165 	ASSERT(pthread_equal(main_tid, pthread_self()));
166 
167 	set_state(T1_START);
168 	ASSERTe(*main_errno, == EBADF);
169 	ASSERT(&errno == main_errno);
170 
171 	wait_for_state(T1_SIGNAL);
172 	ASSERTe(*main_errno, == EBADF);
173 	ASSERT(&errno == main_errno);
174 	ASSERT(pthread_equal(main_tid, pthread_self()));
175 
176 	handler_errno = &t1_errno;
177 	CHECKe(pthread_kill(t1_tid, SIGUSR1));
178 	ASSERT(&errno == main_errno);
179 
180 	CHECKr(sigwait(&sigusr2, &r));
181 	ASSERTe(*main_errno, == EBADF);
182 	ASSERT(&errno == main_errno);
183 	ASSERT(pthread_equal(main_tid, pthread_self()));
184 	set_state(T1_CHECK2);
185 
186 	wait_for_state(T1_EXIT);
187 	CHECKe(pthread_join(t1_tid, NULL));
188 	ASSERT(&errno == main_errno);
189 	ASSERT(pthread_equal(main_tid, pthread_self()));
190 
191 	SUCCEED;
192 }
193