1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2014 Garrett D'Amore <garrett@damore.org>
14  */
15 
16 /*
17  * Common handling for test programs.
18  */
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <pthread.h>
24 #include "test_common.h"
25 
26 static int debug = 0;
27 static int force = 0;
28 static pthread_mutex_t lk;
29 
30 struct test {
31 	char		*name;
32 	int		ntids;
33 	pthread_t	*tids;
34 	int		fails;
35 	void		*arg;
36 	void		(*func)(test_t t, void *);
37 };
38 
39 void
40 test_set_debug(void)
41 {
42 	debug++;
43 }
44 
45 void
46 test_set_force(void)
47 {
48 	force++;
49 }
50 
51 test_t
52 test_start(const char *format, ...)
53 {
54 	va_list args;
55 	test_t t;
56 	char *s;
57 
58 	t = calloc(1, sizeof (*t));
59 	va_start(args, format);
60 	(void) vasprintf(&s, format, args);
61 	va_end(args);
62 
63 	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
64 	free(s);
65 
66 	(void) pthread_mutex_lock(&lk);
67 	(void) printf("TEST STARTING %s:\n", t->name);
68 	(void) fflush(stdout);
69 	(void) pthread_mutex_unlock(&lk);
70 
71 #ifdef	LINT
72 	/* We inject references to make avoid name unused warnings */
73 	test_run(0, NULL, NULL, NULL);
74 	test_debugf(t, NULL);
75 	test_failed(t, NULL);
76 	test_passed(t);
77 	test_set_debug();
78 	test_set_force();
79 #endif
80 
81 	return (t);
82 
83 }
84 
85 void
86 test_failed(test_t t, const char *format, ...)
87 {
88 	va_list args;
89 
90 	(void) pthread_mutex_lock(&lk);
91 	if (force || (t->ntids > 0)) {
92 		(void) printf("TEST FAILING %s: ", t->name);
93 	} else {
94 		(void) printf("TEST FAILED %s: ", t->name);
95 	}
96 
97 	va_start(args, format);
98 	(void) vprintf(format, args);
99 	va_end(args);
100 	(void) printf("\n");
101 	(void) fflush(stdout);
102 	(void) pthread_mutex_unlock(&lk);
103 
104 	t->fails++;
105 	if (!force) {
106 		if (t->ntids > 0) {
107 			pthread_exit(NULL);
108 		} else {
109 			(void) exit(EXIT_FAILURE);
110 		}
111 	}
112 }
113 
114 void
115 test_passed(test_t t)
116 {
117 	if (t->ntids > 0) {
118 		if (debug) {
119 			(void) pthread_mutex_lock(&lk);
120 			(void) printf("TEST PASSING: %s\n", t->name);
121 			(void) pthread_mutex_unlock(&lk);
122 		}
123 		return;
124 	}
125 	(void) pthread_mutex_lock(&lk);
126 	if (t->fails == 0) {
127 		(void) printf("TEST PASS: %s\n", t->name);
128 	} else {
129 		(void) printf("TEST FAILED: %d failures\n", t->fails);
130 	}
131 	(void) fflush(stdout);
132 	(void) pthread_mutex_unlock(&lk);
133 	free(t->name);
134 	if (t->tids) {
135 		free(t->tids);
136 	}
137 	free(t);
138 }
139 
140 void
141 test_debugf(test_t t, const char *format, ...)
142 {
143 	va_list args;
144 
145 	if (!debug)
146 		return;
147 
148 	(void) pthread_mutex_lock(&lk);
149 	(void) printf("TEST DEBUG %s: ", t->name);
150 
151 	va_start(args, format);
152 	(void) vprintf(format, args);
153 	va_end(args);
154 	(void) printf("\n");
155 	(void) fflush(stdout);
156 	(void) pthread_mutex_unlock(&lk);
157 }
158 
159 static void *
160 test_thr_one(void *arg)
161 {
162 	test_t t = arg;
163 	t->func(t, t->arg);
164 	return (NULL);
165 }
166 
167 void
168 test_run(int nthr, void (*func)(test_t, void *), void *arg,
169     const char *tname, ...)
170 {
171 	test_t		t;
172 	char		*s;
173 	va_list		args;
174 
175 	t = calloc(1, sizeof (*t));
176 	t->ntids = nthr;
177 	t->tids = calloc(nthr, sizeof (pthread_t));
178 	t->func = func;
179 	t->arg = arg;
180 
181 	va_start(args, tname);
182 	(void) vasprintf(&s, tname, args);
183 	va_end(args);
184 
185 	(void) asprintf(&t->name, "%s (%s)", s, ARCH);
186 	free(s);
187 
188 	(void) pthread_mutex_lock(&lk);
189 	(void) printf("TEST STARTING %s:\n", t->name);
190 	(void) fflush(stdout);
191 	(void) pthread_mutex_unlock(&lk);
192 
193 	test_debugf(t, "running %d threads", nthr);
194 
195 	for (int i = 0; i < nthr; i++) {
196 		test_debugf(t, "started thread %d", i);
197 		(void) pthread_create(&t->tids[i], NULL, test_thr_one, t);
198 	}
199 
200 	for (int i = 0; i < nthr; i++) {
201 		(void) pthread_join(t->tids[i], NULL);
202 		test_debugf(t, "thread %d joined", i);
203 		t->ntids--;
204 	}
205 	test_passed(t);
206 }
207