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
set_state(enum state new_state)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
wait_for_state(enum state new_state)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
act_handler(int signal)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 *
tmain(void * arg)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
main(int argc,char ** argv)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