1/*	$NetBSD: t_getenv_thread.c,v 1.2 2012/03/15 02:02:23 joerg Exp $ */
2
3/*-
4 * Copyright (c) 2010 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matthias Scheler.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31#include <sys/cdefs.h>
32__RCSID("$NetBSD: t_getenv_thread.c,v 1.2 2012/03/15 02:02:23 joerg Exp $");
33
34#include <atf-c.h>
35#include <errno.h>
36#include <pthread.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <time.h>
41
42#define	THREADED_NUM_THREADS	8
43#define	THREADED_NUM_VARS	16
44#define	THREADED_VAR_NAME	"THREADED%zu"
45#define	THREADED_RUN_TIME	10
46
47static void	 *thread_getenv_r(void *);
48static void	 *thread_putenv(void *);
49static void	 *thread_setenv(void *);
50static void	 *thread_unsetenv(void *);
51
52static void *
53thread_getenv_r(void *arg)
54{
55	time_t endtime;
56
57	endtime = *(time_t *)arg;
58	do {
59		size_t i;
60		char name[32], value[128];
61
62		i = lrand48() % THREADED_NUM_VARS;
63		(void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i);
64
65		if (getenv_r(name, value, sizeof(value)) == -1) {
66			ATF_CHECK(errno == ENOENT);
67		}
68	} while (time(NULL) < endtime);
69
70	return NULL;
71}
72
73
74static void *
75thread_putenv(void *arg)
76{
77	time_t endtime;
78	size_t i;
79	static char vars[THREADED_NUM_VARS][128];
80
81	for (i = 0; i < THREADED_NUM_VARS; i++) {
82		(void)snprintf(vars[i], sizeof(vars[i]),
83		    THREADED_VAR_NAME "=putenv %ld", i, lrand48());
84	}
85
86	endtime = *(time_t *)arg;
87	do {
88		char name[128];
89
90		i = lrand48() % THREADED_NUM_VARS;
91		(void)strlcpy(name, vars[i], sizeof(name));
92		*strchr(name, '=') = '\0';
93
94		ATF_CHECK(unsetenv(name) != -1);
95		ATF_CHECK(putenv(vars[i]) != -1);
96	} while (time(NULL) < endtime);
97
98	return NULL;
99}
100
101static void *
102thread_setenv(void *arg)
103{
104	time_t endtime;
105
106	endtime = *(time_t *)arg;
107	do {
108		size_t i;
109		char name[32], value[64];
110
111		i = lrand48() % THREADED_NUM_VARS;
112		(void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i);
113		(void)snprintf(value, sizeof(value), "setenv %ld", lrand48());
114
115		ATF_CHECK(setenv(name, value, 1) != -1);
116	} while (time(NULL) < endtime);
117
118	return NULL;
119}
120
121static void *
122thread_unsetenv(void *arg)
123{
124	time_t endtime;
125
126	endtime = *(time_t *)arg;
127	do {
128		size_t i;
129		char name[32];
130
131		i = lrand48() % THREADED_NUM_VARS;
132		(void)snprintf(name, sizeof(name), THREADED_VAR_NAME, i);
133
134		ATF_CHECK(unsetenv(name) != -1);
135	} while (time(NULL) < endtime);
136
137	return NULL;
138}
139
140ATF_TC(getenv_r_thread);
141ATF_TC_HEAD(getenv_r_thread, tc)
142{
143
144	atf_tc_set_md_var(tc, "descr", "Test getenv_r(3) with threads");
145	atf_tc_set_md_var(tc, "timeout", "%d", THREADED_RUN_TIME + 5);
146}
147
148ATF_TC_BODY(getenv_r_thread, tc)
149{
150	pthread_t threads[THREADED_NUM_THREADS];
151	time_t endtime;
152	size_t i, j;
153
154	endtime = time(NULL) + THREADED_RUN_TIME;
155
156	for (i = j = 0; j < 2; j++) {
157
158		ATF_CHECK(pthread_create(&threads[i++], NULL, thread_getenv_r,
159		    &endtime) == 0);
160	}
161
162	for (j = 0; j < i; j++)
163		ATF_CHECK(pthread_join(threads[j], NULL) == 0);
164}
165
166ATF_TC(putenv_thread);
167ATF_TC_HEAD(putenv_thread, tc)
168{
169	atf_tc_set_md_var(tc, "descr", "Test concurrent access by putenv(3)");
170	atf_tc_set_md_var(tc, "timeout", "%d", THREADED_RUN_TIME + 5);
171}
172
173ATF_TC_BODY(putenv_thread, tc)
174{
175	pthread_t threads[THREADED_NUM_THREADS];
176	time_t endtime;
177	size_t i, j;
178
179	endtime = time(NULL) + THREADED_RUN_TIME;
180
181	for (i = j = 0; j < 2; j++) {
182
183		ATF_CHECK(pthread_create(&threads[i++], NULL, thread_putenv,
184		    &endtime) == 0);
185	}
186
187	for (j = 0; j < i; j++)
188		ATF_CHECK(pthread_join(threads[j], NULL) == 0);
189}
190
191ATF_TC(setenv_thread);
192ATF_TC_HEAD(setenv_thread, tc)
193{
194	atf_tc_set_md_var(tc, "descr", "Test concurrent access by setenv(3)");
195	atf_tc_set_md_var(tc, "timeout", "%d", THREADED_RUN_TIME + 5);
196}
197
198ATF_TC_BODY(setenv_thread, tc)
199{
200	pthread_t threads[THREADED_NUM_THREADS];
201	time_t endtime;
202	size_t i, j;
203
204	endtime = time(NULL) + THREADED_RUN_TIME;
205
206	for (i = j = 0; j < 2; j++) {
207
208		ATF_CHECK(pthread_create(&threads[i++], NULL, thread_setenv,
209		    &endtime) == 0);
210	}
211
212	for (j = 0; j < i; j++)
213		ATF_CHECK(pthread_join(threads[j], NULL) == 0);
214}
215
216ATF_TC(unsetenv_thread);
217ATF_TC_HEAD(unsetenv_thread, tc)
218{
219	atf_tc_set_md_var(tc, "descr", "Test unsetenv(3) with threads");
220	atf_tc_set_md_var(tc, "timeout", "%d", THREADED_RUN_TIME + 5);
221}
222
223ATF_TC_BODY(unsetenv_thread, tc)
224{
225	pthread_t threads[THREADED_NUM_THREADS];
226	time_t endtime;
227	size_t i, j;
228
229	endtime = time(NULL) + THREADED_RUN_TIME;
230
231	for (i = j = 0; j < 2; j++) {
232
233		ATF_CHECK(pthread_create(&threads[i++], NULL, thread_unsetenv,
234		    &endtime) == 0);
235	}
236
237	for (j = 0; j < i; j++)
238		ATF_CHECK(pthread_join(threads[j], NULL) == 0);
239}
240
241ATF_TP_ADD_TCS(tp)
242{
243
244	ATF_TP_ADD_TC(tp, getenv_r_thread);
245	ATF_TP_ADD_TC(tp, putenv_thread);
246	ATF_TP_ADD_TC(tp, setenv_thread);
247	ATF_TP_ADD_TC(tp, unsetenv_thread);
248
249	return atf_no_error();
250}
251