xref: /illumos-gate/usr/src/test/util-tests/tests/workq/wqt.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
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, 0, 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