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