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 2015 Joyent, Inc. 14 */ 15 16 /* 17 * workq testing routines 18 * 19 * What we want to guarantee is that every function is executed exactly once. To 20 * that end we have the callback function basically increment a global in the 21 * test around a mutex. 22 */ 23 24 #include <workq.h> 25 #include <stdio.h> 26 #include <errno.h> 27 #include <string.h> 28 #include <stdlib.h> 29 #include <thread.h> 30 #include <synch.h> 31 32 mutex_t wqt_lock = ERRORCHECKMUTEX; 33 uintptr_t wqt_count; 34 35 const char * 36 _umem_debug_init() 37 { 38 return ("default,verbose"); 39 } 40 41 const char * 42 _umem_logging_init(void) 43 { 44 return ("fail,contents"); 45 } 46 47 void * 48 workq_alloc(size_t size) 49 { 50 return (malloc(size)); 51 } 52 53 /*ARGSUSED*/ 54 void 55 workq_free(void *buf, size_t size) 56 { 57 free(buf); 58 } 59 60 /*ARGSUSED*/ 61 int 62 wqt_fatal(void *item, void *arg) 63 { 64 return (-1); 65 } 66 67 int 68 wqt_add(void *item, void *arg) 69 { 70 uintptr_t a = (uintptr_t)item; 71 72 mutex_enter(&wqt_lock); 73 wqt_count += a; 74 mutex_exit(&wqt_lock); 75 76 return (0); 77 } 78 79 typedef struct wq_test { 80 const char *wq_desc; /* test description/name */ 81 workq_proc_f *wq_proc; /* processing function */ 82 int wq_rval; /* workq_work return value */ 83 int wq_uerr; /* user error, if any */ 84 uintptr_t wq_sum; /* expected sum */ 85 void **wq_args; /* argument array */ 86 } wq_test_t; 87 88 static void *wqt_empty_args[] = { NULL }; 89 static void *wqt_single_args[] = { (void *)42, NULL }; 90 static void *wqt_double_args[] = { (void *)42, (void *)27, NULL }; 91 static void *wqt_wrap_args[] = { 92 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 93 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 94 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 95 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 96 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 97 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 98 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 99 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 100 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 101 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 102 (void *)1, (void *)1, (void *)1, (void *)1, NULL 103 }; 104 static void *wqt_grow_args[] = { 105 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 106 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 107 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 108 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 109 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 110 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 111 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 112 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 113 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 114 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 115 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 116 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 117 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 118 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 119 (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, (void *)1, 120 (void *)1, (void *)1, NULL 121 }; 122 123 static wq_test_t wq_tests[] = { 124 { "empty", wqt_add, 0, 0, NULL, wqt_empty_args }, 125 { "single", wqt_add, 0, 0, 42, wqt_single_args }, 126 { "double", wqt_add, 0, 0, 69, wqt_double_args }, 127 { "wrap", wqt_add, 0, 0, 64, wqt_wrap_args }, 128 { "grow", wqt_add, 0, 0, 92, wqt_grow_args }, 129 { "fatal", wqt_fatal, WORKQ_UERROR, -1, -1, wqt_double_args } 130 }; 131 132 #define NWQ_TESTS (sizeof (wq_tests) / sizeof (wq_test_t)) 133 134 static void 135 wq_test_run(workq_t *wqp, wq_test_t *wqt) 136 { 137 int ret, err; 138 void **itemp = wqt->wq_args; 139 140 while (*itemp != NULL) { 141 if ((ret = workq_add(wqp, *itemp)) != 0) { 142 (void) fprintf(stderr, "test %s: failed to add item: " 143 "%s\n", wqt->wq_desc, strerror(errno)); 144 exit(1); 145 } 146 itemp++; 147 } 148 149 wqt_count = 0; 150 ret = workq_work(wqp, wqt->wq_proc, NULL, &err); 151 if (ret != wqt->wq_rval) { 152 (void) fprintf(stderr, "test %s: got incorrect rval. " 153 "Expected %d, got %d (%d)\n", wqt->wq_desc, wqt->wq_rval, 154 ret, errno); 155 exit(1); 156 } 157 158 if (ret == WORKQ_UERROR && err != wqt->wq_uerr) { 159 (void) fprintf(stderr, "test %s: got incorrect user error. " 160 "Expected %d, got %d\n", wqt->wq_desc, wqt->wq_uerr, err); 161 exit(1); 162 } 163 164 if (ret == 0 && wqt_count != wqt->wq_sum) { 165 (void) fprintf(stderr, "test %s: got unexpected " 166 "result: %d, expected %d\n", wqt->wq_desc, wqt_count, 167 wqt->wq_sum); 168 exit(1); 169 } 170 } 171 172 int 173 main(void) 174 { 175 int ret, i, t; 176 workq_t *wqp; 177 int nthreads[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, -1 }; 178 179 for (t = 0; nthreads[t] != -1; t++) { 180 printf("Beginning tests with %d threads\n", nthreads[t]); 181 if ((ret = workq_init(&wqp, nthreads[t])) != 0) { 182 fprintf(stderr, "failed to init workq: %s\n", 183 strerror(errno)); 184 return (1); 185 } 186 187 for (i = 0; i < NWQ_TESTS; i++) { 188 wq_test_run(wqp, &wq_tests[i]); 189 } 190 191 workq_fini(wqp); 192 } 193 194 195 return (0); 196 } 197