xref: /openbsd-src/regress/lib/csu/callbacks/pthread_atfork/pthread_atfork_test.c (revision 514a545f8a3983d53b7de4e8dfcefe16c9496776)
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