mirror of
https://libwebsockets.org/repo/libwebsockets
synced 2024-12-25 23:00:12 +00:00
458 lines
8.2 KiB
C
458 lines
8.2 KiB
C
/*
|
|
* lws-api-test-lws_dsh
|
|
*
|
|
* Written in 2010-2021 by Andy Green <andy@warmcat.com>
|
|
*
|
|
* This file is made available under the Creative Commons CC0 1.0
|
|
* Universal Public Domain Dedication.
|
|
*/
|
|
|
|
#include <libwebsockets.h>
|
|
|
|
int
|
|
test1(void)
|
|
{
|
|
struct lws_dsh *dsh;
|
|
size_t size;
|
|
void *a1;
|
|
|
|
/*
|
|
* test 1: single dsh, alloc 2 kinds and free everything back to a
|
|
* single free obj
|
|
*/
|
|
|
|
dsh = lws_dsh_create(NULL, 16384, 2);
|
|
if (!dsh) {
|
|
lwsl_err("%s: Failed to create dsh\n", __func__);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "hello", 5, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 1, "some other string", 17, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "hello again", 11, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 3\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
|
lwsl_err("%s: no head 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 17 || memcmp(a1, "some other string", 17)) {
|
|
lwsl_err("%s: test 1 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 5 || memcmp(a1, "hello", 5)) {
|
|
lwsl_err("%s: test 2 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 3\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 11 || memcmp(a1, "hello again", 11)) {
|
|
lwsl_err("%s: test 3 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 0;
|
|
bail:
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
test3(void)
|
|
{
|
|
struct lws_dsh *dsh, *dsh2;
|
|
lws_dll2_owner_t owner;
|
|
uint8_t blob[4096];
|
|
|
|
memset(blob, 0, sizeof(blob));
|
|
|
|
/*
|
|
* test 3: multiple dsh, umeetable allocation request
|
|
*/
|
|
|
|
lws_dll2_owner_clear(&owner);
|
|
|
|
dsh = lws_dsh_create(&owner, 4096, 2);
|
|
if (!dsh) {
|
|
lwsl_err("%s: Failed to create dsh1\n", __func__);
|
|
|
|
return 1;
|
|
}
|
|
|
|
dsh2 = lws_dsh_create(&owner, 4096, 2);
|
|
if (!dsh2) {
|
|
lwsl_err("%s: Failed to create dsh2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, blob, 4000, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 1\n", __func__);
|
|
|
|
goto bail2;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh2, 0, "hello", 5, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 2\n", __func__);
|
|
|
|
goto bail2;
|
|
}
|
|
|
|
/*
|
|
* There's just no room for this, we expect it to fail
|
|
*/
|
|
|
|
if (!lws_dsh_alloc_tail(dsh, 0, blob, 5000, NULL, 0)) {
|
|
lwsl_err("%s: Didn't fail to alloc as expected\n", __func__);
|
|
|
|
goto bail2;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh2, 0, "hello again", 11, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 4\n", __func__);
|
|
|
|
goto bail2;
|
|
}
|
|
|
|
lws_dsh_destroy(&dsh2);
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 0;
|
|
|
|
bail2:
|
|
lws_dsh_destroy(&dsh2);
|
|
|
|
bail:
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
test4(void)
|
|
{
|
|
uint8_t blob[4096];
|
|
struct lws_dsh *dsh;
|
|
size_t size;
|
|
void *a1;
|
|
|
|
memset(blob, 0, sizeof(blob));
|
|
|
|
/*
|
|
* test 4: use up whole free list, then recover and alloc something
|
|
* else
|
|
*/
|
|
|
|
dsh = lws_dsh_create(NULL, 4096, 2);
|
|
if (!dsh) {
|
|
lwsl_err("%s: Failed to create dsh\n", __func__);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, blob, 4000, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 4000) {
|
|
lwsl_err("%s: test 1 mismatch %d\n", __func__, (int)size);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "some other string", 17, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "hello again", 11, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 3\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 4\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 17 || memcmp(a1, "some other string", 17)) {
|
|
/* it may (should...) coalesce */
|
|
if (size != 28 || memcmp(a1, "some other stringhello again", 28)) {
|
|
lwsl_err("%s: test 4 mismatch %d\n", __func__, (int)size);
|
|
|
|
goto bail;
|
|
}
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 0;
|
|
bail:
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int
|
|
test5(void)
|
|
{
|
|
struct lws_dsh *dsh;
|
|
unsigned int budget;
|
|
uint8_t blob[4096];
|
|
lws_xos_t xos;
|
|
size_t size;
|
|
void *a1;
|
|
|
|
memset(blob, 0, sizeof(blob));
|
|
lws_xos_init(&xos, 0x123456789abcdef0ull);
|
|
|
|
budget = (unsigned int)(lws_xos(&xos) % 4000) + 4000;
|
|
|
|
lwsl_notice("%s: budget %u\n", __func__, budget);
|
|
|
|
|
|
/*
|
|
* test 5: PRNG-based spamming and erratic bidi draining
|
|
*/
|
|
|
|
dsh = lws_dsh_create(NULL, 409600, 2);
|
|
if (!dsh) {
|
|
lwsl_err("%s: Failed to create dsh\n", __func__);
|
|
|
|
return 1;
|
|
}
|
|
|
|
do {
|
|
|
|
if (lws_xos_percent(&xos, 60)) {
|
|
/* kind 0 is going to try to write */
|
|
|
|
size = (size_t)((lws_xos(&xos) & 127) + 1);
|
|
|
|
if (!lws_dsh_alloc_tail(dsh, 0, blob, size, NULL, 0))
|
|
lwsl_notice("%s: kind 0 alloc %d\n", __func__, (int)size);
|
|
}
|
|
|
|
if (lws_xos_percent(&xos, 80)) {
|
|
/* kind 1 is going to try to write */
|
|
|
|
size = (size_t)((lws_xos(&xos) & 127) + 1);
|
|
|
|
if (!lws_dsh_alloc_tail(dsh, 1, blob, size, NULL, 0))
|
|
lwsl_notice("%s: kind 1 alloc %d\n", __func__, (int)size);
|
|
}
|
|
|
|
if (lws_xos_percent(&xos, 40)) {
|
|
/* kind 0 is going to try to read */
|
|
|
|
while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
|
|
lws_dsh_free(&a1);
|
|
}
|
|
}
|
|
|
|
if (lws_xos_percent(&xos, 30)) {
|
|
/* kind 1 is going to try to read */
|
|
|
|
while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
|
lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
|
|
lws_dsh_free(&a1);
|
|
}
|
|
}
|
|
|
|
} while (budget--);
|
|
|
|
while (!lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_notice("%s: kind 0 read %d\n", __func__, (int)size);
|
|
lws_dsh_free(&a1);
|
|
}
|
|
|
|
while (!lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
|
lwsl_notice("%s: kind 1 read %d\n", __func__, (int)size);
|
|
lws_dsh_free(&a1);
|
|
}
|
|
|
|
#if defined(_DEBUG)
|
|
lws_dsh_describe(dsh, "test dsh end state");
|
|
#endif
|
|
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
test6(void)
|
|
{
|
|
struct lws_dsh *dsh;
|
|
size_t size;
|
|
void *a1;
|
|
|
|
/*
|
|
* test 6: confirm sequential coalescing
|
|
*/
|
|
|
|
dsh = lws_dsh_create(NULL, 16384, 2);
|
|
if (!dsh) {
|
|
lwsl_err("%s: Failed to create dsh\n", __func__);
|
|
|
|
return 1;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "hello", 5, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 1, "some other string", 17, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_alloc_tail(dsh, 0, "hello again", 11, NULL, 0)) {
|
|
lwsl_err("%s: Failed to alloc 3\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
|
|
if (lws_dsh_get_head(dsh, 1, &a1, &size)) {
|
|
lwsl_err("%s: no head 1\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 17 || memcmp(a1, "some other string", 17)) {
|
|
lwsl_err("%s: test 1 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 2\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 5 || memcmp(a1, "hello", 5)) {
|
|
lwsl_err("%s: test 2 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
if (lws_dsh_get_head(dsh, 0, &a1, &size)) {
|
|
lwsl_err("%s: no head 3\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
if (size != 11 || memcmp(a1, "hello again", 11)) {
|
|
lwsl_err("%s: test 3 mismatch\n", __func__);
|
|
|
|
goto bail;
|
|
}
|
|
lws_dsh_free(&a1);
|
|
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 0;
|
|
bail:
|
|
#if defined(_DEBUG)
|
|
lws_dsh_describe(dsh, "test6 fail");
|
|
#endif
|
|
lws_dsh_destroy(&dsh);
|
|
|
|
return 1;
|
|
}
|
|
|
|
int main(int argc, const char **argv)
|
|
{
|
|
int logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE;
|
|
int ret = 0, n;
|
|
const char *p;
|
|
|
|
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
|
logs = atoi(p);
|
|
|
|
lws_set_log_level(logs, NULL);
|
|
lwsl_user("LWS API selftest: lws_dsh\n");
|
|
|
|
n = test1();
|
|
lwsl_user("%s: test1: %d\n", __func__, n);
|
|
ret |= n;
|
|
if (ret)
|
|
goto bail;
|
|
|
|
n = test3();
|
|
lwsl_user("%s: test3: %d\n", __func__, n);
|
|
ret |= n;
|
|
if (ret)
|
|
goto bail;
|
|
|
|
n = test4();
|
|
lwsl_user("%s: test4: %d\n", __func__, n);
|
|
ret |= n;
|
|
if (ret)
|
|
goto bail;
|
|
|
|
n = test5();
|
|
lwsl_user("%s: test5: %d\n", __func__, n);
|
|
ret |= n;
|
|
if (ret)
|
|
goto bail;
|
|
|
|
n = test6();
|
|
lwsl_user("%s: test6: %d\n", __func__, n);
|
|
ret |= n;
|
|
|
|
bail:
|
|
lwsl_user("Completed: %s\n", ret ? "FAIL" : "PASS");
|
|
|
|
return ret;
|
|
}
|