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