1 /* $OpenBSD: pthread_atfork_test.c,v 1.2 2015/04/07 01:27:07 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2014 Philip Guenther <guenther@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/wait.h>
20 #include <dlfcn.h>
21 #include <err.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26
27 void *libaa, *libab;
28
29 FILE *otherf;
30
31 #define CALLBACK(file, name) \
32 static void name(void) \
33 { \
34 fprintf(file, "testp "#name"\n"); \
35 fflush(file); \
36 }
37
38 #define ATFORK_CALLBACKS(name) \
39 CALLBACK(stdout, name##_prepare) \
40 CALLBACK(stdout, name##_parent) \
41 CALLBACK(otherf, name##_child)
42
43 ATFORK_CALLBACKS(atfork1)
ATFORK_CALLBACKS(atfork2)44 ATFORK_CALLBACKS(atfork2)
45 ATFORK_CALLBACKS(atfork3)
46
47 static void
48 atfork_dlclose(void)
49 {
50 printf("exe atfork_dlclose begin\n");
51 dlclose(libaa);
52 dlclose(libab);
53 printf("exe atfork_dlclose end\n");
54 fflush(stdout);
55 }
56
57 static void
aa_atfork(void)58 aa_atfork(void)
59 {
60 void (*func)(FILE *) = dlsym(libaa, "aa_atfork");
61 if (func == NULL)
62 errx(1, "dlsym(libaa, aa_atfork): %s", dlerror());
63 func(otherf);
64 }
65
66 static void
ab_atfork(void)67 ab_atfork(void)
68 {
69 void (*func)(FILE *) = dlsym(libab, "ab_atfork");
70 if (func == NULL)
71 errx(1, "dlsym(libab, ab_atfork): %s", dlerror());
72 func(otherf);
73 }
74
75 #define REGISTER(prep, parent, child) \
76 do { \
77 int _r = pthread_atfork(prep, parent, child); \
78 if (_r) \
79 errc(1, _r, "pthread_atfork(%s,%s,%s)", \
80 #prep, #parent, #child); \
81 } while (0)
82
83 #define REGISTER_ALL(name) \
84 REGISTER(name##_prepare, name##_parent, name##_child)
85
86 int
main(int argc,char ** argv)87 main(int argc, char **argv)
88 {
89 pid_t pid;
90 int test, status;
91
92 otherf = fdopen(3, "w");
93 if (otherf == NULL)
94 otherf = stderr;
95
96 libaa = dlopen(LIBAA, RTLD_LAZY);
97 if (libaa == NULL)
98 errx(1, "dlopen(%s, RTLD_LAZY): %s", LIBAA, dlerror());
99
100 libab = dlopen(LIBAB, RTLD_LAZY);
101 if (libab == NULL)
102 errx(1, "dlopen(%s, RTLD_LAZY): %s", LIBAB, dlerror());
103
104 if (argc != 2)
105 test = 0;
106 else
107 test = atoi(argv[1]);
108
109 switch (test) {
110 case 0:
111 /* 1, aa, 2, ab, 3, then fork */
112 REGISTER_ALL(atfork1);
113 aa_atfork();
114 REGISTER_ALL(atfork2);
115 ab_atfork();
116 REGISTER_ALL(atfork3);
117 break;
118
119 case 1:
120 /* 1, aa, 2, ab, 3, then dlclose aa and bb, then fork */
121 REGISTER_ALL(atfork1);
122 aa_atfork();
123 REGISTER_ALL(atfork2);
124 ab_atfork();
125 REGISTER_ALL(atfork3);
126 dlclose(libaa);
127 dlclose(libab);
128 break;
129
130 case 2:
131 /* 1, aa, atfork_dlclose, ab, 3, then fork */
132 REGISTER_ALL(atfork1);
133 aa_atfork();
134 REGISTER(atfork_dlclose, NULL, NULL);
135 ab_atfork();
136 REGISTER_ALL(atfork3);
137 break;
138
139 case 3:
140 /* 1, aa, 2, ab, atfork_dlclose, then fork */
141 REGISTER_ALL(atfork1);
142 aa_atfork();
143 REGISTER_ALL(atfork2);
144 ab_atfork();
145 REGISTER(atfork_dlclose, NULL, NULL);
146 break;
147
148 }
149
150 fflush(stdout);
151 fflush(otherf);
152 pid = fork();
153
154 waitpid(pid, &status, 0);
155 return (0);
156 }
157