summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorShell <[email protected]>2024-01-09 20:37:47 +0800
committerMeco Man <[email protected]>2024-01-16 00:59:18 +0800
commitf6fce5f8d76e26c2315a64de81ce07bd6e379394 (patch)
treeeec5650cafe081bdfff1933f0926c0cc1b6548a9 /src
parent447a22a21dc6da2bcbe7489ae08c9d0e18308511 (diff)
[kservice] MT-safe output support (kprintf/kputs)
Signed-off-by: Shell <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/Kconfig5
-rw-r--r--src/kservice.c112
2 files changed, 99 insertions, 18 deletions
diff --git a/src/Kconfig b/src/Kconfig
index 75e19744e2..81b71be4a1 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -417,6 +417,10 @@ config RT_USING_INTERRUPT_INFO
help
Add name and counter information for interrupt trace.
+config RT_USING_THREDSAFE_PRINTF
+ bool "Enable thread safe kernel print service"
+ default y if RT_USING_SMP && RT_USING_SMART
+
config RT_USING_CONSOLE
bool "Using console for rt_kprintf"
default y
@@ -429,6 +433,7 @@ if RT_USING_CONSOLE
config RT_CONSOLE_DEVICE_NAME
string "the device name for console"
default "uart1"
+
endif
config RT_VER_NUM
diff --git a/src/kservice.c b/src/kservice.c
index 3a42b65410..8323ea6196 100644
--- a/src/kservice.c
+++ b/src/kservice.c
@@ -1485,17 +1485,83 @@ rt_weak void rt_hw_console_output(const char *str)
}
RTM_EXPORT(rt_hw_console_output);
+#ifdef RT_USING_THREDSAFE_PRINTF
+
+static struct rt_spinlock _pr_lock = RT_SPINLOCK_INIT;
+static struct rt_spinlock _prf_lock = RT_SPINLOCK_INIT;
+/* current user of system console */
+static rt_thread_t _pr_curr_user;
+/* nested level of current user */
+static int _pr_curr_user_nested;
+
+rt_thread_t rt_console_current_user(void)
+{
+ return _pr_curr_user;
+}
+
+static void _acquire_console(void)
+{
+ rt_ubase_t level = rt_spin_lock_irqsave(&_pr_lock);
+ rt_thread_t self_thread = rt_thread_self();
+
+ while (_pr_curr_user != self_thread)
+ {
+ if (_pr_curr_user == RT_NULL)
+ {
+ /* no preemption is allowed to avoid dead lock */
+ rt_enter_critical();
+ _pr_curr_user = self_thread;
+ break;
+ }
+ else
+ {
+ rt_spin_unlock_irqrestore(&_pr_lock, level);
+ rt_thread_yield();
+ level = rt_spin_lock_irqsave(&_pr_lock);
+ }
+ }
+
+ _pr_curr_user_nested++;
+
+ rt_spin_unlock_irqrestore(&_pr_lock, level);
+}
+
+static void _release_console(void)
+{
+ rt_ubase_t level = rt_spin_lock_irqsave(&_pr_lock);
+ rt_thread_t self_thread = rt_thread_self();
+
+ RT_ASSERT(_pr_curr_user == self_thread);
+
+ _pr_curr_user_nested--;
+ if (!_pr_curr_user_nested)
+ {
+ _pr_curr_user = RT_NULL;
+ rt_exit_critical();
+ }
+ rt_spin_unlock_irqrestore(&_pr_lock, level);
+}
+
+#define ACQUIRE_CONSOLE _acquire_console()
+#define RELEASE_CONSOLE _release_console()
+#define ACQUIRE_PRINTF_BUFFER rt_ubase_t level = rt_spin_lock_irqsave(&_prf_lock)
+#define RELEASE_PRINTF_BUFFER rt_spin_unlock_irqrestore(&_prf_lock, level)
+#else
+
+#define ACQUIRE_CONSOLE
+#define RELEASE_CONSOLE
+#define ACQUIRE_PRINTF_BUFFER
+#define RELEASE_PRINTF_BUFFER
+#endif /* RT_USING_THREDSAFE_PRINTF */
+
/**
* @brief This function will put string to the console.
*
* @param str is the string output to the console.
*/
-void rt_kputs(const char *str)
+static void _kputs(const char *str, long len)
{
- if (!str)
- {
- return;
- }
+ ACQUIRE_CONSOLE;
#ifdef RT_USING_DEVICE
if (_console_device == RT_NULL)
@@ -1504,11 +1570,28 @@ void rt_kputs(const char *str)
}
else
{
- rt_device_write(_console_device, 0, str, rt_strlen(str));
+ rt_device_write(_console_device, 0, str, len);
}
#else
rt_hw_console_output(str);
#endif /* RT_USING_DEVICE */
+
+ RELEASE_CONSOLE;
+}
+
+/**
+ * @brief This function will put string to the console.
+ *
+ * @param str is the string output to the console.
+ */
+void rt_kputs(const char *str)
+{
+ if (!str)
+ {
+ return;
+ }
+
+ _kputs(str, rt_strlen(str));
}
/**
@@ -1525,6 +1608,8 @@ rt_weak int rt_kprintf(const char *fmt, ...)
static char rt_log_buf[RT_CONSOLEBUF_SIZE];
va_start(args, fmt);
+ ACQUIRE_PRINTF_BUFFER;
+
/* the return value of vsnprintf is the number of bytes that would be
* written to buffer had if the size of the buffer been sufficiently
* large excluding the terminating null byte. If the output string
@@ -1536,18 +1621,9 @@ rt_weak int rt_kprintf(const char *fmt, ...)
length = RT_CONSOLEBUF_SIZE - 1;
}
-#ifdef RT_USING_DEVICE
- if (_console_device == RT_NULL)
- {
- rt_hw_console_output(rt_log_buf);
- }
- else
- {
- rt_device_write(_console_device, 0, rt_log_buf, length);
- }
-#else
- rt_hw_console_output(rt_log_buf);
-#endif /* RT_USING_DEVICE */
+ _kputs(rt_log_buf, length);
+
+ RELEASE_PRINTF_BUFFER;
va_end(args);
return length;