• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lws-api-test-lws_dsh
3  *
4  * Written in 2010-2021 by Andy Green <andy@warmcat.com>
5  *
6  * This file is made available under the Creative Commons CC0 1.0
7  * Universal Public Domain Dedication.
8  */
9 
10 #include <libwebsockets.h>
11 
12 int
test1(void)13 test1(void)
14 {
15 	struct lws_dsh *dsh;
16 	size_t size;
17 	void *a1;
18 
19 	/*
20 	 * test 1: single dsh, alloc 2 kinds and free everything back to a
21 	 *         single free obj
22 	 */
23 
24 	dsh = lws_dsh_create(NULL, 16384, 2);
25 	if (!dsh) {
26 		lwsl_err("%s: Failed to create dsh\n", __func__);
27 
28 		return 1;
29 	}
30 
31 	if (lws_dsh_alloc_tail(dsh, 0, "hello", 5, NULL, 0)) {
32 		lwsl_err("%s: Failed to alloc 1\n", __func__);
33 
34 		goto bail;
35 	}
36 
37 	if (lws_dsh_alloc_tail(dsh, 1, "some other string", 17, NULL, 0)) {
38 		lwsl_err("%s: Failed to alloc 2\n", __func__);
39 
40 		goto bail;
41 	}
42 
43 	if (lws_dsh_alloc_tail(dsh, 0, "hello again", 11, NULL, 0)) {
44 		lwsl_err("%s: Failed to alloc 3\n", __func__);
45 
46 		goto bail;
47 	}
48 
49 	if (lws_dsh_get_head(dsh, 1, &a1, &size)) {
50 		lwsl_err("%s: no head 1\n", __func__);
51 
52 		goto bail;
53 	}
54 	if (size != 17 || memcmp(a1, "some other string", 17)) {
55 		lwsl_err("%s: test 1 mismatch\n", __func__);
56 
57 		goto bail;
58 	}
59 	lws_dsh_free(&a1);
60 
61 	if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
62 		lwsl_err("%s: no head 2\n", __func__);
63 
64 		goto bail;
65 	}
66 	if (size != 5 || memcmp(a1, "hello", 5)) {
67 		lwsl_err("%s: test 2 mismatch\n", __func__);
68 
69 		goto bail;
70 	}
71 	lws_dsh_free(&a1);
72 
73 	if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
74 		lwsl_err("%s: no head 3\n", __func__);
75 
76 		goto bail;
77 	}
78 	if (size != 11 || memcmp(a1, "hello again", 11)) {
79 		lwsl_err("%s: test 3 mismatch\n", __func__);
80 
81 		goto bail;
82 	}
83 	lws_dsh_free(&a1);
84 
85 	lws_dsh_destroy(&dsh);
86 
87 	return 0;
88 bail:
89 	lws_dsh_destroy(&dsh);
90 
91 	return 1;
92 }
93 
94 int
test3(void)95 test3(void)
96 {
97 	struct lws_dsh *dsh, *dsh2;
98 	lws_dll2_owner_t owner;
99 	uint8_t blob[4096];
100 
101 	memset(blob, 0, sizeof(blob));
102 
103 	/*
104 	 * test 3: multiple dsh, umeetable allocation request
105 	 */
106 
107 	lws_dll2_owner_clear(&owner);
108 
109 	dsh = lws_dsh_create(&owner, 4096, 2);
110 	if (!dsh) {
111 		lwsl_err("%s: Failed to create dsh1\n", __func__);
112 
113 		return 1;
114 	}
115 
116 	dsh2 = lws_dsh_create(&owner, 4096, 2);
117 	if (!dsh2) {
118 		lwsl_err("%s: Failed to create dsh2\n", __func__);
119 
120 		goto bail;
121 	}
122 
123 	if (lws_dsh_alloc_tail(dsh, 0, blob, 4000, NULL, 0)) {
124 		lwsl_err("%s: Failed to alloc 1\n", __func__);
125 
126 		goto bail2;
127 	}
128 
129 	if (lws_dsh_alloc_tail(dsh2, 0, "hello", 5, NULL, 0)) {
130 		lwsl_err("%s: Failed to alloc 2\n", __func__);
131 
132 		goto bail2;
133 	}
134 
135 	/*
136 	 * There's just no room for this, we expect it to fail
137 	 */
138 
139 	if (!lws_dsh_alloc_tail(dsh, 0, blob, 5000, NULL, 0)) {
140 		lwsl_err("%s: Didn't fail to alloc as expected\n", __func__);
141 
142 		goto bail2;
143 	}
144 
145 	if (lws_dsh_alloc_tail(dsh2, 0, "hello again", 11, NULL, 0)) {
146 		lwsl_err("%s: Failed to alloc 4\n", __func__);
147 
148 		goto bail2;
149 	}
150 
151 	lws_dsh_destroy(&dsh2);
152 	lws_dsh_destroy(&dsh);
153 
154 	return 0;
155 
156 bail2:
157 	lws_dsh_destroy(&dsh2);
158 
159 bail:
160 	lws_dsh_destroy(&dsh);
161 
162 	return 1;
163 }
164 
165 int
test4(void)166 test4(void)
167 {
168 	uint8_t blob[4096];
169 	struct lws_dsh *dsh;
170 	size_t size;
171 	void *a1;
172 
173 	memset(blob, 0, sizeof(blob));
174 
175 	/*
176 	 * test 4: use up whole free list, then recover and alloc something
177 	 *	   else
178 	 */
179 
180 	dsh = lws_dsh_create(NULL, 4096, 2);
181 	if (!dsh) {
182 		lwsl_err("%s: Failed to create dsh\n", __func__);
183 
184 		return 1;
185 	}
186 
187 	if (lws_dsh_alloc_tail(dsh, 0, blob, 4000, NULL, 0)) {
188 		lwsl_err("%s: Failed to alloc 1\n", __func__);
189 
190 		goto bail;
191 	}
192 
193 	if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
194 		lwsl_err("%s: no head 1\n", __func__);
195 
196 		goto bail;
197 	}
198 	if (size != 4000) {
199 		lwsl_err("%s: test 1 mismatch\n", __func__);
200 
201 		goto bail;
202 	}
203 	lws_dsh_free(&a1);
204 
205 	if (lws_dsh_alloc_tail(dsh, 0, "some other string", 17, NULL, 0)) {
206 		lwsl_err("%s: Failed to alloc 2\n", __func__);
207 
208 		goto bail;
209 	}
210 
211 	if (lws_dsh_alloc_tail(dsh, 0, "hello again", 11, NULL, 0)) {
212 		lwsl_err("%s: Failed to alloc 3\n", __func__);
213 
214 		goto bail;
215 	}
216 
217 	if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
218 		lwsl_err("%s: no head 1\n", __func__);
219 
220 		goto bail;
221 	}
222 	if (size != 17 || memcmp(a1, "some other string", 17)) {
223 		lwsl_err("%s: test 1 mismatch\n", __func__);
224 
225 		goto bail;
226 	}
227 	lws_dsh_free(&a1);
228 
229 	if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
230 		lwsl_err("%s: no head 2\n", __func__);
231 
232 		goto bail;
233 	}
234 	if (size != 11 || memcmp(a1, "hello again", 11)) {
235 		lwsl_err("%s: test 2 mismatch (%zu)\n", __func__, size);
236 
237 		goto bail;
238 	}
239 
240 	lws_dsh_free(&a1);
241 
242 	lws_dsh_destroy(&dsh);
243 
244 	return 0;
245 bail:
246 	lws_dsh_destroy(&dsh);
247 
248 	return 1;
249 }
250 
251 int
test5(void)252 test5(void)
253 {
254 	struct lws_dsh *dsh;
255 	unsigned int budget;
256 	uint8_t blob[4096];
257 	lws_xos_t xos;
258 	size_t size;
259 	void *a1;
260 
261 	memset(blob, 0, sizeof(blob));
262 	lws_xos_init(&xos, 0x123456789abcdef0ull);
263 
264 	budget = (unsigned int)(lws_xos(&xos) % 4000) + 4000;
265 
266 	lwsl_notice("%s: budget %u\n", __func__, budget);
267 
268 
269 	/*
270 	 * test 5: PRNG-based spamming and erratic bidi draining
271 	 */
272 
273 	dsh = lws_dsh_create(NULL, 409600, 2);
274 	if (!dsh) {
275 		lwsl_err("%s: Failed to create dsh\n", __func__);
276 
277 		return 1;
278 	}
279 
280 	do {
281 
282 		if (lws_xos_percent(&xos, 60)) {
283 			/* kind 0 is going to try to write */
284 
285 			size = (size_t)((lws_xos(&xos) & 127) + 1);
286 
287 			if (!lws_dsh_alloc_tail(dsh, 0, blob, size, NULL, 0))
288 				lwsl_notice("%s: kind 0 alloc %d\n", __func__, (int)size);
289 		}
290 
291 		if (lws_xos_percent(&xos, 80)) {
292 			/* kind 1 is going to try to write */
293 
294 			size = (size_t)((lws_xos(&xos) & 127) + 1);
295 
296 			if (!lws_dsh_alloc_tail(dsh, 1, blob, size, NULL, 0))
297 				lwsl_notice("%s: kind 1 alloc %d\n", __func__, (int)size);
298 		}
299 
300 		if (lws_xos_percent(&xos, 40)) {
301 			/* kind 0 is going to try to read */
302 
303 			while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
304 				lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
305 				lws_dsh_free(&a1);
306 			}
307 		}
308 
309 		if (lws_xos_percent(&xos, 30)) {
310 			/* kind 1 is going to try to read */
311 
312 			while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
313 				lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
314 				lws_dsh_free(&a1);
315 			}
316 		}
317 
318 	} while (budget--);
319 
320 	while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
321 		lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
322 		lws_dsh_free(&a1);
323 	}
324 
325 	while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
326 		lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
327 		lws_dsh_free(&a1);
328 	}
329 
330 #if defined(_DEBUG)
331 	lws_dsh_describe(dsh, "test dsh end state");
332 #endif
333 
334 	lws_dsh_destroy(&dsh);
335 
336 	return 0;
337 }
338 
main(int argc,const char ** argv)339 int main(int argc, const char **argv)
340 {
341 	int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
342 	int ret = 0, n;
343 	const char *p;
344 
345 	if ((p = lws_cmdline_option(argc, argv, "-d")))
346 		logs = atoi(p);
347 
348 	lws_set_log_level(logs, NULL);
349 	lwsl_user("LWS API selftest: lws_dsh\n");
350 
351 	n = test1();
352 	lwsl_user("%s: test1: %d\n", __func__, n);
353 	ret |= n;
354 
355 	n = test3();
356 	lwsl_user("%s: test3: %d\n", __func__, n);
357 	ret |= n;
358 
359 	n = test4();
360 	lwsl_user("%s: test4: %d\n", __func__, n);
361 	ret |= n;
362 
363 	n = test5();
364 	lwsl_user("%s: test5: %d\n", __func__, n);
365 	ret |= n;
366 
367 	lwsl_user("Completed: %s\n", ret ? "FAIL" : "PASS");
368 
369 	return ret;
370 }
371