drivers/serial: fix cancellation point leak on uart_tcdrain timeout

uart_tcdrain() registers a cancellation point on entry via
enter_cancellation_point() (when called with cancelable=true), and the
normal exit path calls leave_cancellation_point() before returning.

However the timeout path inside the FIFO drain loop returns -ETIMEDOUT
directly without going through the normal exit path, leaking one
cancellation point reference (tcb->cpcount is left incremented).  Over
repeated timeouts this counter will desync and prevent
pthread_cancel() / pthread_setcancelstate() from behaving correctly
for the calling thread.

Fix by calling leave_cancellation_point() before the early return,
matching the existing exit path.

Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
This commit is contained in:
Lingao Meng 2026-06-02 11:53:22 +08:00 • committed by Xiang Xiao
parent d955fbc8f3
commit 78b3b456eb

View file

@ -604,6 +604,11 @@ static int uart_tcdrain(FAR uart_dev_t *dev,
if (elapsed >= timeout)
{
nxmutex_unlock(&dev->xmit.lock);
if (cancelable)
{
leave_cancellation_point();
}
return -ETIMEDOUT;
}
}