From 375cbc2cc4aa379727b7e0f02a257e1d8e35ce4f Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Fri, 7 Aug 2020 15:06:24 +0300 Subject: Node.js: correct port data memory release. According to libuv documentation, uv_poll_t memory should be released in a callback function passed to uv_close(). Otherwise, the Node.js application process may crash at exit. --- src/nodejs/unit-http/unit.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src/nodejs/unit-http/unit.cpp') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 975174d4..555b21fa 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -13,6 +13,8 @@ #include +static void delete_port_data(uv_handle_t* handle); + napi_ref Unit::constructor_; @@ -418,7 +420,8 @@ Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) if (node_ctx->port_id == *port_id) { uv_poll_stop(&node_ctx->poll); - delete node_ctx; + node_ctx->poll.data = node_ctx; + uv_close((uv_handle_t *) &node_ctx->poll, delete_port_data); ctx->data = NULL; } @@ -428,6 +431,17 @@ Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) } +static void +delete_port_data(uv_handle_t* handle) +{ + nxt_nodejs_ctx_t *node_ctx; + + node_ctx = (nxt_nodejs_ctx_t *) handle->data; + + delete node_ctx; +} + + void Unit::quit_cb(nxt_unit_ctx_t *ctx) { -- cgit From ec3389b63bd7a9159d2be4a2863140f75095c7d3 Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 11 Aug 2020 19:19:55 +0300 Subject: Libunit refactoring: port management. - Changed the port management callbacks to notifications, which e. g. avoids the need to call the libunit function - Added context and library instance reference counts for a safer resource release - Added the router main port initialization --- src/nodejs/unit-http/unit.cpp | 46 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'src/nodejs/unit-http/unit.cpp') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 555b21fa..468acf96 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -18,7 +18,8 @@ static void delete_port_data(uv_handle_t* handle); napi_ref Unit::constructor_; -struct nxt_nodejs_ctx_t { +struct port_data_t { + nxt_unit_ctx_t *ctx; nxt_unit_port_id_t port_id; uv_poll_t poll; }; @@ -360,8 +361,8 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) int err; Unit *obj; uv_loop_t *loop; + port_data_t *data; napi_status status; - nxt_nodejs_ctx_t *node_ctx; if (port->in_fd != -1) { obj = reinterpret_cast(ctx->unit->data); @@ -378,27 +379,28 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) return NXT_UNIT_ERROR; } - node_ctx = new nxt_nodejs_ctx_t; + data = new port_data_t; - err = uv_poll_init(loop, &node_ctx->poll, port->in_fd); + err = uv_poll_init(loop, &data->poll, port->in_fd); if (err < 0) { nxt_unit_warn(ctx, "Failed to init uv.poll"); return NXT_UNIT_ERROR; } - err = uv_poll_start(&node_ctx->poll, UV_READABLE, nxt_uv_read_callback); + err = uv_poll_start(&data->poll, UV_READABLE, nxt_uv_read_callback); if (err < 0) { nxt_unit_warn(ctx, "Failed to start uv.poll"); return NXT_UNIT_ERROR; } - ctx->data = node_ctx; + port->data = data; - node_ctx->port_id = port->id; - node_ctx->poll.data = ctx; + data->ctx = ctx; + data->port_id = port->id; + data->poll.data = ctx; } - return nxt_unit_add_port(ctx, port); + return NXT_UNIT_OK; } @@ -410,35 +412,31 @@ operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) void -Unit::remove_port(nxt_unit_ctx_t *ctx, nxt_unit_port_id_t *port_id) +Unit::remove_port(nxt_unit_t *unit, nxt_unit_port_t *port) { - nxt_nodejs_ctx_t *node_ctx; + port_data_t *data; - if (ctx->data != NULL) { - node_ctx = (nxt_nodejs_ctx_t *) ctx->data; + if (port->data != NULL) { + data = (port_data_t *) port->data; - if (node_ctx->port_id == *port_id) { - uv_poll_stop(&node_ctx->poll); + if (data->port_id == port->id) { + uv_poll_stop(&data->poll); - node_ctx->poll.data = node_ctx; - uv_close((uv_handle_t *) &node_ctx->poll, delete_port_data); - - ctx->data = NULL; + data->poll.data = data; + uv_close((uv_handle_t *) &data->poll, delete_port_data); } } - - nxt_unit_remove_port(ctx, port_id); } static void delete_port_data(uv_handle_t* handle) { - nxt_nodejs_ctx_t *node_ctx; + port_data_t *data; - node_ctx = (nxt_nodejs_ctx_t *) handle->data; + data = (port_data_t *) handle->data; - delete node_ctx; + delete data; } -- cgit From 83595606121a821f9e3cef0f0b7e7fe87eb1e50a Mon Sep 17 00:00:00 2001 From: Max Romanov Date: Tue, 11 Aug 2020 19:20:15 +0300 Subject: Introducing the shared application port. This is the port shared between all application processes which use it to pass requests for processing. Using it significantly simplifies the request processing code in the router. The drawback is 2 more file descriptors per each configured application and more complex libunit message wait/read code. --- src/nodejs/unit-http/unit.cpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src/nodejs/unit-http/unit.cpp') diff --git a/src/nodejs/unit-http/unit.cpp b/src/nodejs/unit-http/unit.cpp index 468acf96..1ee5b742 100644 --- a/src/nodejs/unit-http/unit.cpp +++ b/src/nodejs/unit-http/unit.cpp @@ -20,7 +20,7 @@ napi_ref Unit::constructor_; struct port_data_t { nxt_unit_ctx_t *ctx; - nxt_unit_port_id_t port_id; + nxt_unit_port_t *port; uv_poll_t poll; }; @@ -351,7 +351,11 @@ Unit::shm_ack_handler(nxt_unit_ctx_t *ctx) static void nxt_uv_read_callback(uv_poll_t *handle, int status, int events) { - nxt_unit_run_once((nxt_unit_ctx_t *) handle->data); + port_data_t *data; + + data = (port_data_t *) handle->data; + + nxt_unit_process_port_msg(data->ctx, data->port); } @@ -396,21 +400,14 @@ Unit::add_port(nxt_unit_ctx_t *ctx, nxt_unit_port_t *port) port->data = data; data->ctx = ctx; - data->port_id = port->id; - data->poll.data = ctx; + data->port = port; + data->poll.data = data; } return NXT_UNIT_OK; } -inline bool -operator == (const nxt_unit_port_id_t &p1, const nxt_unit_port_id_t &p2) -{ - return p1.pid == p2.pid && p1.id == p2.id; -} - - void Unit::remove_port(nxt_unit_t *unit, nxt_unit_port_t *port) { @@ -419,10 +416,9 @@ Unit::remove_port(nxt_unit_t *unit, nxt_unit_port_t *port) if (port->data != NULL) { data = (port_data_t *) port->data; - if (data->port_id == port->id) { + if (data->port == port) { uv_poll_stop(&data->poll); - data->poll.data = data; uv_close((uv_handle_t *) &data->poll, delete_port_data); } } -- cgit