diff options
author | Max Romanov <max.romanov@nginx.com> | 2019-09-18 18:31:22 +0300 |
---|---|---|
committer | Max Romanov <max.romanov@nginx.com> | 2019-09-18 18:31:22 +0300 |
commit | a216b15e991d6e7cdc7b61fe018d58dd387937bd (patch) | |
tree | 72c429920f804ee9dff9afee4efa010f52a5b158 /src/nxt_unit.c | |
parent | 84e4a6437f69b14b1cafbe7915447fdcf1d87f68 (diff) | |
download | unit-a216b15e991d6e7cdc7b61fe018d58dd387937bd.tar.gz unit-a216b15e991d6e7cdc7b61fe018d58dd387937bd.tar.bz2 |
Fixing request release order to avoid crashes on exit.
Each request references the router process structure that owns all memory
maps. The process structure has a reference counter; each request increases
the counter to lock the structure in memory until request processing ends.
Incoming and outgoing buffers reference memory maps that the process owns,
so the process structure should be released only when all buffers are
released to avoid invalid memory access and a crash.
This describes the libunit library mechanism used for application processes.
The background of this issue is as follows:
The issue was found on buildbot when the router crashed during Java
websocket tests. The Java application receives a notification from the
master process; when the notification is processed, libunit deletes the
process structure from its process hash and decrements the use counter;
however, active websocket connections maintain their use counts on the
process structure. After that, when the master process is stopping the
application, libunit releases active websocket connections. At this point,
it's important to release the connections' memory buffers before the
corresponding process structure and all shared memory segments are released.
Diffstat (limited to '')
-rw-r--r-- | src/nxt_unit.c | 16 |
1 files changed, 10 insertions, 6 deletions
diff --git a/src/nxt_unit.c b/src/nxt_unit.c index 18a07f9e..9696e9cd 100644 --- a/src/nxt_unit.c +++ b/src/nxt_unit.c @@ -1093,12 +1093,6 @@ nxt_unit_request_info_release(nxt_unit_request_info_t *req) req->response = NULL; req->response_buf = NULL; - if (req_impl->process != NULL) { - nxt_unit_process_use(req->ctx, req_impl->process, -1); - - req_impl->process = NULL; - } - if (req_impl->websocket) { nxt_unit_request_hash_find(&ctx_impl->requests, req_impl->stream, 1); @@ -1113,6 +1107,16 @@ nxt_unit_request_info_release(nxt_unit_request_info_t *req) nxt_unit_mmap_buf_free(req_impl->incoming_buf); } + /* + * Process release should go after buffers release to guarantee mmap + * existence. + */ + if (req_impl->process != NULL) { + nxt_unit_process_use(req->ctx, req_impl->process, -1); + + req_impl->process = NULL; + } + pthread_mutex_lock(&ctx_impl->mutex); nxt_queue_remove(&req_impl->link); |