diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a8b60011..8a19395a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -725,6 +725,14 @@ CHECK_C_SOURCE_COMPILES( "#include int main(int argc, char **argv) { char buf[1]; bzero(buf, 1); return 0; } " LWS_HAVE_BZERO) +CHECK_C_SOURCE_COMPILES( + "#include + int main(int argc, char **argv) { return malloc_trim(0); } + " LWS_HAVE_MALLOC_TRIM) +CHECK_C_SOURCE_COMPILES( + "#include + int main(int argc, char **argv) { return (int)malloc_usable_size((void *)0); } + " LWS_HAVE_MALLOC_USABLE_SIZE) CHECK_FUNCTION_EXISTS(fork LWS_HAVE_FORK) CHECK_FUNCTION_EXISTS(getenv LWS_HAVE_GETENV) diff --git a/cmake/lws_config.h.in b/cmake/lws_config.h.in index 3d6eaa432..ce3d4aa98 100644 --- a/cmake/lws_config.h.in +++ b/cmake/lws_config.h.in @@ -30,6 +30,8 @@ #cmakedefine LWS_HAVE_EVP_aes_128_wrap #cmakedefine LWS_HAVE_LIBCAP #cmakedefine LWS_HAVE_MALLOC_H +#cmakedefine LWS_HAVE_MALLOC_TRIM +#cmakedefine LWS_HAVE_MALLOC_USABLE_SIZE #cmakedefine LWS_HAVE_mbedtls_net_init #cmakedefine LWS_HAVE_mbedtls_ssl_conf_alpn_protocols #cmakedefine LWS_HAVE_mbedtls_ssl_get_alpn_protocol diff --git a/include/libwebsockets/lws-misc.h b/include/libwebsockets/lws-misc.h index d962bc0a4..00bf4d6aa 100644 --- a/include/libwebsockets/lws-misc.h +++ b/include/libwebsockets/lws-misc.h @@ -715,6 +715,23 @@ LWS_VISIBLE LWS_EXTERN int lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb); #endif +/** + * lws_get_allocated_heap() - if the platform supports it, returns amount of + * heap allocated by lws itself + * + * On glibc currently, this reports the total amount of current logical heap + * allocation, found by tracking the amount allocated by lws_malloc() and + * friends and accounting for freed allocations via lws_free(). + * + * This is useful for confirming where processwide heap allocations actually + * come from... this number represents all lws internal allocations, for + * fd tables, wsi allocations, ah, etc combined. It doesn't include allocations + * from user code, since lws_malloc() etc are not exported from the library. + * + * On other platforms, it always returns 0. + */ +size_t lws_get_allocated_heap(void); + /** * lws_is_ssl() - Find out if connection is using SSL * \param wsi: websocket connection to check diff --git a/lib/core-net/server.c b/lib/core-net/server.c index 19364841f..e406d0d0b 100644 --- a/lib/core-net/server.c +++ b/lib/core-net/server.c @@ -212,7 +212,8 @@ lws_json_dump_context(const struct lws_context *context, char *buf, int len, close(fd); } - buf += lws_snprintf(buf, end - buf, "\"contexts\":[\n"); + buf += lws_snprintf(buf, end - buf, "\"heap\":%lld,\n\"contexts\":[\n", + (long long)lws_get_allocated_heap()); buf += lws_snprintf(buf, end - buf, "{ " "\"context_uptime\":\"%ld\",\n" diff --git a/lib/core/alloc.c b/lib/core/alloc.c index 72c8e2697..d28c9f7a0 100644 --- a/lib/core/alloc.c +++ b/lib/core/alloc.c @@ -1,5 +1,13 @@ #include "core/private.h" +#if defined(LWS_HAVE_MALLOC_USABLE_SIZE) + +#include + +/* the heap is processwide */ +static size_t allocated; +#endif + #if defined(LWS_PLAT_OPTEE) #define TEE_USER_MEM_HINT_NO_FILL_ZERO 0x80000000 @@ -72,8 +80,11 @@ void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason)) } #else -static void *_realloc(void *ptr, size_t size, const char *reason) +static void * +_realloc(void *ptr, size_t size, const char *reason) { + void *v; + if (size) { #if defined(LWS_WITH_ESP32) lwsl_notice("%s: size %lu: %s (free heap %d)\n", __func__, @@ -82,14 +93,28 @@ static void *_realloc(void *ptr, size_t size, const char *reason) lwsl_debug("%s: size %lu: %s\n", __func__, (unsigned long)size, reason); #endif -#if defined(LWS_PLAT_OPTEE) - return (void *)TEE_Realloc(ptr, size); -#else - return (void *)realloc(ptr, size); + +#if defined(LWS_HAVE_MALLOC_USABLE_SIZE) + if (ptr) + allocated -= malloc_usable_size(ptr); #endif + +#if defined(LWS_PLAT_OPTEE) + v = (void *)TEE_Realloc(ptr, size); +#else + v = (void *)realloc(ptr, size); +#endif +#if defined(LWS_HAVE_MALLOC_USABLE_SIZE) + allocated += malloc_usable_size(v); +#endif + return v; } - if (ptr) + if (ptr) { +#if defined(LWS_HAVE_MALLOC_USABLE_SIZE) + allocated -= malloc_usable_size(ptr); +#endif free(ptr); + } return NULL; } @@ -104,8 +129,10 @@ void *lws_realloc(void *ptr, size_t size, const char *reason) void *lws_zalloc(size_t size, const char *reason) { void *ptr = _lws_realloc(NULL, size, reason); + if (ptr) memset(ptr, 0, size); + return ptr; } @@ -113,4 +140,13 @@ void lws_set_allocator(void *(*cb)(void *ptr, size_t size, const char *reason)) { _lws_realloc = cb; } + +size_t lws_get_allocated_heap(void) +{ +#if defined(LWS_HAVE_MALLOC_USABLE_SIZE) + return allocated; +#else + return 0; +#endif +} #endif diff --git a/lib/misc/dir.c b/lib/misc/dir.c index 7a491a80a..e8e59022b 100644 --- a/lib/misc/dir.c +++ b/lib/misc/dir.c @@ -94,6 +94,12 @@ lws_dir(const char *dirpath, void *user, lws_dir_callback_function cb) if (strchr(namelist[i]->d_name, '~')) goto skip; lde.name = namelist[i]->d_name; + + /* + * some filesystems don't report this (ZFS) and tell that + * files are LDOT_UNKNOWN + */ + switch (namelist[i]->d_type) { case DT_BLK: lde.type = LDOT_BLOCK; diff --git a/lib/plat/unix/unix-service.c b/lib/plat/unix/unix-service.c index 2a23570bf..217b2e264 100644 --- a/lib/plat/unix/unix-service.c +++ b/lib/plat/unix/unix-service.c @@ -22,6 +22,10 @@ #define _GNU_SOURCE #include "core/private.h" +#if defined(LWS_HAVE_MALLOC_TRIM) +#include +#endif + int lws_poll_listen_fd(struct lws_pollfd *fd) { @@ -209,4 +213,7 @@ lws_plat_service_periodic(struct lws_context *context) kill(context->started_with_parent, 0) < 0) kill(getpid(), SIGTERM); #endif +#if defined(LWS_HAVE_MALLOC_TRIM) + malloc_trim(4 * 1024); +#endif } diff --git a/lib/roles/http/server/lejp-conf.c b/lib/roles/http/server/lejp-conf.c index 3e3d3443e..ffbe98f10 100644 --- a/lib/roles/http/server/lejp-conf.c +++ b/lib/roles/http/server/lejp-conf.c @@ -907,7 +907,7 @@ lwsws_get_config_d_cb(const char *dirpath, void *user, struct lws_dir_args *da = (struct lws_dir_args *)user; char path[256]; - if (lde->type != LDOT_FILE) + if (lde->type != LDOT_FILE && lde->type != LDOT_UNKNOWN /* ZFS */) return 0; lws_snprintf(path, sizeof(path) - 1, "%s/%s", dirpath, lde->name); diff --git a/plugins/server-status.js b/plugins/server-status.js index 1f20cef18..c32ac972d 100644 --- a/plugins/server-status.js +++ b/plugins/server-status.js @@ -105,6 +105,9 @@ function ws_open_server_status() s += ", Virt stack + heap Usage: " + humanize(parseInt(sm[0], 10) * 4096) + "B"; } + s += ", lws heap usage: " + + humanize(jso.i.heap) + "B"; + for (n = 0; n < jso.files.length; n++) { s += "
" + san(jso.files[n].path) + ":
" + san(jso.files[n].val);