mirror of
https://github.com/apache/nuttx.git
synced 2026-05-10 15:30:25 +08:00
fs/epoll: add TLS cleanup handler to release epoll fd reference on thread exit
When a thread is terminated via pthread_exit() while blocked in epoll_wait(), the file reference taken at the beginning of epoll_wait() is not properly released, leading to resource leaks. Problem scenario found during libuv test: 1. Echo server thread is blocked in epoll_wait() 2. Main task sends pthread_kill signal to the server thread 3. Signal handler calls pthread_exit() to terminate the thread 4. epoll_wait() is interrupted before reaching the file_put() call 5. The epoll fd reference count remains elevated 6. epoll_do_close() is never called, leaving fds in internal queues 7. File descriptors leak Solution: Register a TLS (Thread Local Storage) cleanup handler using tls_cleanup_push() at the beginning of epoll_wait() blocking section. This ensures that if the thread exits abnormally (via pthread_exit, pthread_cancel, etc.), the cleanup handler (epoll_cleanup) will be called automatically to release the file reference via file_put(). The cleanup handler is properly paired with tls_cleanup_pop() when epoll_wait() completes normally, ensuring the handler is only invoked on abnormal exit. This fix is applied to both epoll_wait() code paths (with and without extended mode) to ensure consistent behavior. Impact: - Prevents epoll fd reference count leaks on thread cancellation - Ensures proper cleanup even when epoll_wait() is interrupted by pthread_exit - Critical for multi-threaded applications using signals and thread termination - Works together with previous fix for teardown/oneshot list cleanup Signed-off-by: dongjiuzhu1 <dongjiuzhu1@xiaomi.com>
This commit is contained in:
committed by
Alan C. Assis
parent
61a2ab98ef
commit
291199f833
@@ -42,6 +42,7 @@
|
||||
#include <nuttx/list.h>
|
||||
#include <nuttx/mutex.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/tls.h>
|
||||
|
||||
#include "inode/inode.h"
|
||||
#include "fs_heap.h"
|
||||
@@ -394,6 +395,19 @@ static int epoll_teardown(FAR epoll_head_t *eph, FAR struct epoll_event *evs,
|
||||
return i;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll_cleanup
|
||||
*
|
||||
* Description:
|
||||
* Cleanup the epoll operation.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void epoll_cleanup(FAR void *arg)
|
||||
{
|
||||
file_put(arg);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: epoll_default_cb
|
||||
*
|
||||
@@ -754,6 +768,12 @@ retry:
|
||||
|
||||
nxsig_procmask(SIG_SETMASK, sigmask, &oldsigmask);
|
||||
|
||||
/* Push a cancellation point onto the stack. This will be called if
|
||||
* the thread is canceled.
|
||||
*/
|
||||
|
||||
tls_cleanup_push(tls_get_info(), epoll_cleanup, filep);
|
||||
|
||||
if (timeout == 0)
|
||||
{
|
||||
ret = -ETIMEDOUT;
|
||||
@@ -767,6 +787,10 @@ retry:
|
||||
ret = nxsem_wait(&eph->sem);
|
||||
}
|
||||
|
||||
/* Pop the cancellation point */
|
||||
|
||||
tls_cleanup_pop(tls_get_info(), 0);
|
||||
|
||||
nxsig_procmask(SIG_SETMASK, &oldsigmask, NULL);
|
||||
if (ret < 0 && ret != -ETIMEDOUT)
|
||||
{
|
||||
@@ -825,6 +849,12 @@ retry:
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Push a cancellation point onto the stack. This will be called if
|
||||
* the thread is canceled.
|
||||
*/
|
||||
|
||||
tls_cleanup_push(tls_get_info(), epoll_cleanup, filep);
|
||||
|
||||
/* Wait the poll ready */
|
||||
|
||||
if (timeout == 0)
|
||||
@@ -840,6 +870,10 @@ retry:
|
||||
ret = nxsem_wait(&eph->sem);
|
||||
}
|
||||
|
||||
/* Pop the cancellation point */
|
||||
|
||||
tls_cleanup_pop(tls_get_info(), 0);
|
||||
|
||||
if (ret < 0 && ret != -ETIMEDOUT)
|
||||
{
|
||||
goto err;
|
||||
|
||||
Reference in New Issue
Block a user