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 }