Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 54 additions & 17 deletions components/utilities/ulog/ulog.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,17 +421,47 @@ rt_weak rt_size_t ulog_tail_formater(char *log_buf, rt_size_t log_len, rt_bool_t
return log_len;
}

static void ulog_no_enough_buffer_printf(void)
/**
* @brief Print a warning message once (best-effort).
*
* @param[in,out] printed Pointer to a per-call-site flag used to suppress
* repeated prints.
* @param[in] msg Warning message to print.
*
* @details This helper provides a lightweight, best-effort "print-once"
* mechanism for diagnostic warnings.
*
* ulog output may be executed in different contexts (thread or ISR)
* and on single-core or SMP targets. To avoid unsafe blocking,
* excessive latency, or re-entrancy risks in these contexts, this
* function intentionally avoids locks, spinlocks, and atomic CAS.
*
* Under extreme multi-thread or SMP contention, it is therefore
* possible that the warning is printed more than once. This behavior
* is acceptable because the message is diagnostic-only and the
* critical logging path must remain lightweight.
*/
static void ulog_warn_once(rt_bool_t *printed, const char *msg)
{
static rt_bool_t already_output = RT_FALSE;
if (already_output == RT_FALSE)
if (*printed == RT_FALSE)
{
rt_kprintf("Warning: There is not enough buffer to output the log,"
" please increase the ULOG_LINE_BUF_SIZE option.\n");
already_output = RT_TRUE;
/* Set first to reduce re-entrancy and recursive logging. */
*printed = RT_TRUE;
rt_kprintf("%s", msg);
}
}

/**
* @brief Print a "line buffer too small" warning once (best-effort).
*/
static void ulog_no_enough_buffer_printf(void)
{
static rt_bool_t warned_line_buf = RT_FALSE;
ulog_warn_once(&warned_line_buf,
"Warning: There is not enough buffer to output the log,"
" please increase the ULOG_LINE_BUF_SIZE option.\n");
}

rt_weak rt_size_t ulog_formater(char *log_buf, rt_uint32_t level, const char *tag, rt_bool_t newline,
const char *format, va_list args)
{
Expand Down Expand Up @@ -603,21 +633,29 @@ static void do_output(rt_uint32_t level, const char *tag, rt_bool_t is_raw, cons
}
else
{
static rt_bool_t already_output = RT_FALSE;
if (already_output == RT_FALSE)
{
rt_kprintf("Warning: There is no enough buffer for saving async log,"
" please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option.\n");
already_output = RT_TRUE;
}
static rt_bool_t warned_async_log_buf = RT_FALSE;
ulog_warn_once(&warned_async_log_buf,
"Warning: There is no enough buffer for saving async log,"
" please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option.\n");
}
}
else if (ulog.async_rb)
{
/* log_buf_size contain the tail \0, which will lead discard follow char, so only put log_buf_size -1 */
rt_ringbuffer_put(ulog.async_rb, (const rt_uint8_t *)log_buf, (rt_uint16_t)log_buf_size - 1);
/* send a notice */
rt_sem_release(&ulog.async_notice);
rt_size_t req_len = (rt_size_t)log_buf_size - 1;
rt_size_t put_len = rt_ringbuffer_put(ulog.async_rb, (const rt_uint8_t *)log_buf, (rt_uint32_t)req_len);
/* send a notice after writing data */
if (put_len > 0)
{
rt_sem_release(&ulog.async_notice);
}
if (put_len < req_len)
{
static rt_bool_t warned_async_raw_partial = RT_FALSE;
ulog_warn_once(&warned_async_raw_partial,
"Warning: There is no enough buffer for saving async raw log,"
" please increase the ULOG_ASYNC_OUTPUT_BUF_SIZE option.\n");
Comment on lines +655 to +657
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[spelling/用词]: The warning string uses “There is no enough buffer …”, which is ungrammatical.

English: Consider changing it to “There is not enough buffer …” (or “There is insufficient buffer …”) to keep diagnostic output professional.
中文:告警字符串里使用了 “There is no enough buffer …”,语法不正确。建议改为 “There is not enough buffer …”(或 “There is insufficient buffer …”)以保证诊断信息更规范。

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

}
}

return;
Expand Down Expand Up @@ -1441,7 +1479,6 @@ void ulog_async_output_enabled(rt_bool_t enabled)
*/
rt_err_t ulog_async_waiting_log(rt_int32_t time)
{
rt_sem_control(&ulog.async_notice, RT_IPC_CMD_RESET, RT_NULL);
return rt_sem_take(&ulog.async_notice, time);
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[performance/性能]: Removing RT_IPC_CMD_RESET makes async_notice a counting semaphore. Because ulog_async_output() drains the buffers fully, accumulated semaphore counts can cause async_output_thread_entry to loop with immediate rt_sem_take() successes even when no data remains (busy-loop / empty wakeups).

English: After a burst of logs, async_notice may be >1; the consumer takes once, drains everything, then the 2s timed take returns immediately due to leftover counts and repeats with no work. Consider coalescing notifications (binary-semaphore semantics) via an atomic “pending” flag, or draining/clearing extra counts in the consumer after output before blocking again.
中文:去掉 reset 后,async_notice 变成计数信号量;而 ulog_async_output() 每次会把缓冲区一次性读空。日志突发时信号量计数可能累积>1,导致消费线程在数据已空时仍反复 rt_sem_take() 立即返回并空转(空唤醒/忙循环)。建议使用原子 pending 标志将通知合并为“二值语义”,或在消费侧输出后清掉/耗尽多余计数再进入阻塞等待。

Suggested change
return rt_sem_take(&ulog.async_notice, time);
rt_err_t result;
/* wait for async notice */
result = rt_sem_take(&ulog.async_notice, time);
/*
* When using a timed wait, coalesce multiple pending notifications.
* ulog_async_output() drains all pending logs in one shot, so extra
* semaphore counts would otherwise cause immediate wakeups with no work.
* Drain any additional counts so that the next timed wait will actually
* block until new logs arrive.
*/
if ((result == RT_EOK) && (time > 0))
{
while (rt_sem_trytake(&ulog.async_notice) == RT_EOK)
{
/* drain extra notices */
}
}
return result;

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

}

Expand Down
Loading