본문으로 건너뛰기
Practical RTOS Internals · 48/53

RT-Thread 분석 — Object 모델·Components·Smart·Studio

· Hawk · 8분 읽기

#한 줄 요약

“RT-Thread는 경량 커널과 풍부한 component를 같은 트리에 묶어 둡니다.” — FreeRTOS만큼 가볍지만 Zephyr처럼 통합된 driver·filesystem·shell이 따라옵니다.

#어떤 문제를 푸는가

작은 MCU에서는 FreeRTOS가 충분하지만 파일 시스템·네트워크·POSIX·shell까지 필요한 순간 부족함을 느낍니다. 반대로 Zephyr는 풍부하지만 커널 LoC와 빌드 복잡도가 작은 프로젝트엔 과합니다. RT-Thread는 그 사이를 노린 RTOS입니다.

이번 편의 목표는 두 가지입니다. 첫째, object-oriented C로 구현된 RT-Thread의 커널 구조를 짚습니다. 둘째, components/에 모인 통합 서브시스템과 Smart variant까지 한눈에 정리합니다. 중국 시장에 압도적이지만 글로벌 IoT에서도 채택이 늘고 있는 RTOS의 모양을 잡아 두는 글입니다.

저장소는 github.com/RT-Thread/rt-thread이고, Apache 2.0 라이선스입니다.

#배경

시기이벤트
2006Bernard Xiong 개인 프로젝트로 시작
2015~중국 기업·IoT 시장 확산
2020~글로벌 진출 (Apache 2.0 정식 채택)
현재300+ BSP, 1000+ packages

채택 사례

  • China Mobile OneNET (IoT 클라우드)
  • BYD·길리 자동차 일부 ECU
  • DJI 일부 모듈
  • WCH·GD32·HK32 등 중국 MCU 표준 RTOS

중국 vendor MCU(GD32, HK32, N32, WCH CH32V 등)는 RT-Thread BSP를 공식으로 제공하는 경우가 많아 사실상 표준 RTOS로 자리잡았습니다.

#저장소 구조

rt-thread/
├── src/ # 커널 본체 (~10K LoC)
│ ├── thread.c # rt_thread
│ ├── scheduler.c
│ ├── ipc.c # semaphore·mutex·event·mailbox·msgqueue
│ ├── timer.c
│ ├── mem.c # heap
│ ├── memheap.c # multi-region heap
│ ├── object.c # object 시스템 (kobject 유사)
│ └── ...
├── include/
│ ├── rtthread.h
│ └── rtdef.h
├── libcpu/ # 아키텍처별 port
│ ├── arm/cortex-m4/
│ ├── risc-v/
│ └── ...
├── bsp/ # 보드 지원 (300+)
│ ├── stm32/
│ ├── esp32/
│ ├── ch32/
│ └── ...
├── components/ # 통합 서브시스템
│ ├── dfs/ # device filesystem
│ ├── net/ # LwIP 등
│ ├── libc/
│ ├── finsh/ # CLI
│ ├── drivers/
│ └── posix/
└── examples/

코어가 작고 components가 별도 디렉터리에 모여 있어, 필요한 기능만 빌드에 포함시키는 구조가 분명합니다.

#rt_thread 구조

struct rt_thread {
/* rt_object 상속 */
char name[RT_NAME_MAX];
rt_uint8_t type;
rt_uint8_t flags;
rt_list_t list;
/* stack */
void *sp;
void *entry;
void *parameter;
void *stack_addr;
rt_uint32_t stack_size;
/* scheduling */
rt_err_t error;
rt_uint8_t stat;
rt_uint8_t current_priority;
rt_uint8_t init_priority;
rt_uint32_t number_mask; /* priority bitmap 보조 */
/* time slice */
rt_uint32_t init_tick;
rt_uint32_t remaining_tick;
rt_list_t tlist; /* wait list 등록 노드 */
/* SMP */
int oncpu;
rt_uint32_t cpus_lock_nest;
void *user_data;
};

FreeRTOS TCB나 Zephyr k_thread에 비해 훨씬 단정한 크기입니다. 임베디드 MCU에 적합한 RAM 사용량이 유지됩니다.

#Object 시스템 — C로 흉내낸 상속

RT-Thread의 모든 커널 객체는 rt_object상속합니다. C에 클래스가 없으므로 첫 멤버를 base struct로 두는 관용이 사용됩니다.

struct rt_object {
char name[RT_NAME_MAX];
rt_uint8_t type; /* THREAD, SEMAPHORE, MUTEX, ... */
rt_uint8_t flag;
rt_list_t list;
};

type별 container가 있어, 시스템에 존재하는 모든 스레드모든 세마포어를 한 번에 순회할 수 있습니다.

struct rt_object_information *info = rt_object_get_information(RT_Object_Class_Thread);
rt_list_t *list = &info->object_list;

Linux 커널의 kobject와 비슷한 발상입니다. FinSH의 list_thread, list_sem 같은 명령이 가능한 이유가 이 container에 있습니다.

#Scheduler — Priority Bitmap (최대 256)

rt_uint32_t rt_thread_ready_priority_group; /* 상위 32 비트 그룹 */
rt_uint8_t rt_thread_ready_table[32]; /* 그룹별 8 priority */
void rt_schedule(void)
{
rt_uint8_t highest = __rt_ffs(rt_thread_ready_priority_group);
rt_list_t *list = &rt_thread_priority_table[highest];
struct rt_thread *t = rt_list_entry(list->next, struct rt_thread, tlist);
/* context switch */
}

ARM의 CLZ나 RISC-V의 clz 명령을 이용한 __rt_ffsO(1) priority lookup이 가능합니다. 최대 256 priority를 지원해 매우 다양한 RT 시스템을 표현할 수 있습니다.

#IPC — 다섯 가지를 한 파일에

src/ipc.c에 세마포어, 뮤텍스, event flag, mailbox, message queue가 모두 들어 있습니다. 자료구조가 작아서 한 파일에 다 들어가는 데다, 공통된 wait list와 schedule pattern을 한곳에 모은 효과가 있습니다.

rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t timeout)
{
register rt_base_t temp;
temp = rt_hw_interrupt_disable();
if (sem->value > 0) {
sem->value--;
rt_hw_interrupt_enable(temp);
return RT_EOK;
}
if (timeout == 0) {
rt_hw_interrupt_enable(temp);
return -RT_ETIMEOUT;
}
/* 현재 스레드를 wait list에 끼우고 schedule */
rt_thread_t thread = rt_thread_self();
rt_ipc_list_suspend(&sem->parent.suspend_thread, thread, ...);
if (timeout > 0) {
rt_timer_control(&thread->thread_timer, RT_TIMER_CTRL_SET_TIME, &timeout);
rt_timer_start(&thread->thread_timer);
}
rt_hw_interrupt_enable(temp);
rt_schedule();
return thread->error;
}

rt_hw_interrupt_disable이 critical section 진입입니다. 이후 wait list 등록, timer 설정, schedule 호출이 일관된 순서로 일어납니다. mutex나 message queue도 같은 패턴 위에 priority inheritance나 데이터 복사 단계만 더해지는 모양입니다.

#Components — DFS (Device Filesystem)

#include <dfs_posix.h>
int fd = open("/dev/sd0/file.txt", O_RDONLY);
read(fd, buf, sizeof(buf));
close(fd);

POSIX 파일 API를 그대로 제공합니다. 백엔드는 FATFS, LittleFS, RomFS, ramfs 같은 여러 구현 중 KConfig로 선택합니다. SD 카드, SPI flash, USB mass storage가 같은 인터페이스 뒤에 숨습니다.

#Components — LwIP 통합 네트워크

#include <lwip/sockets.h>
int sock = socket(AF_INET, SOCK_STREAM, 0);
connect(sock, (struct sockaddr*)&addr, sizeof(addr));
send(sock, data, len, 0);

표준 BSD socket API가 활성화됩니다. LwIP는 외부 라이브러리지만 기본 component로 통합되어 있어 별도 통합 작업이 거의 필요 없습니다.

#FinSH·MSH — Linux 같은 shell

msh /> help
msh /> ps
msh /> free
msh /> list_thread
msh /> ifconfig
msh /> ping 8.8.8.8
msh /> echo "Hello" > /dev/console

FinSH는 RT-Thread의 표준 CLI입니다. 디버그 시 시스템 상태를 인터랙티브하게 확인할 수 있어 개발 생산성이 크게 올라갑니다. 새 명령을 추가하는 것도 매크로 한 줄이면 됩니다.

static void hello(int argc, char **argv) {
rt_kprintf("hello from finsh\n");
}
MSH_CMD_EXPORT(hello, simple hello command);

#Smart — POSIX + MMU

RT-Thread Smart(rt-smart)는 MMU를 활용한 변종입니다. Linux 같은 process와 user mode를 지원하면서 RT-Thread의 결정성을 유지합니다.

RT-Thread Smart

  • 대상 하드웨어 — Cortex-A·RISC-V S-mode, 256 MB+ RAM
  • 특징 — user/kernel 분리, fork·exec·shared library
  • 적용 — 자동차 인포테인먼트, 산업 HMI, 디지털 사이니지
  • 위치 — Linux는 너무 무겁고 RTOS는 부족한 중간 영역

자동차 인포테인먼트나 HMI에서 Linux를 쓸 만큼의 자원은 없지만 동적 application 로딩이 필요한 시나리오에 사용됩니다.

#env tool과 scons

RT-Thread 빌드 환경은 env tool + scons(Python 기반)입니다.

Terminal window
env # RT-Thread 빌드 환경 진입 (Windows·Linux)
scons --menuconfig # 인터랙티브 KConfig
scons -j4 # 빌드
scons --target=mdk5 # Keil project 생성
scons --target=iar # IAR project 생성

Makefile이나 CMake가 아니라 scons를 쓰는 이유는 중국 임베디드 시장의 Keil·IAR 친화가 큽니다. scons가 project 파일 생성기 역할도 같이 해 줍니다.

#RT-Thread Studio — IDE

Eclipse 기반의 RT-Thread Studio가 별도 제공됩니다. project generator, SDK 관리, devicetree 비슷한 menuconfig UI, 디버그·플래시 통합이 한 IDE에 모입니다. 중국 임베디드 개발자에게는 STM32CubeIDE를 대체하는 표준 환경입니다.

#SMP Support

#define RT_CPUS_NR 4
struct rt_thread *rt_current_thread_per_cpu[RT_CPUS_NR];
rt_thread_t t = rt_thread_create("rt", entry, NULL, 2048, 5, 10);
rt_thread_control(t, RT_THREAD_CTRL_BIND_CPU, (void*)0); /* CPU 0 affinity */

Cortex-A SMP, RP2040 같은 dual Cortex-M, RISC-V SMP를 모두 지원합니다. 단일 코어와 같은 API에 affinity 설정만 더해진 모양입니다.

#ESP32 적용

ESP32 BSP가 RT-Thread에도 정식 제공됩니다. ESP-IDF(Espressif 기본, FreeRTOS 기반)와는 별개의 선택지로, RT-Thread 친숙한 사용자가 ESP32 H/W를 활용할 때 유리합니다.

#include <rtthread.h>
int main(void)
{
rt_kprintf("Hello RT-Thread on ESP32\n");
while (1) {
rt_thread_mdelay(1000);
}
}

#RT-Thread vs FreeRTOS vs Zephyr

항목RT-ThreadFreeRTOSZephyr
출신중국 (2006)영국 (2003)LF (2016)
커널 LoC~10K~20K~50K
Component 통합★★★ (DFS·net·POSIX·shell)★ (별도)★★★
IDERT-Thread Studio외부west·VSCode
BSP 수300+ (중국 MCU 강점)거의 모든 MCU200+
devicetree× (menuconfig 기반)×
Smart variant (MMU)××
중국 시장 점유★★★★★
글로벌 시장 점유★★★★★★

선택 기준은 단순합니다. 중국 MCU나 OneNET·CMCC 같은 중국 클라우드와 붙어야 하면 RT-Thread, 그 외 글로벌 IoT는 FreeRTOS 또는 Zephyr가 일반적입니다.

#자주 보는 함정

경고 — 너무 작은 스택

rt_thread_create("name", entry, NULL, 256, 10, 10);

DFS, LwIP, FinSH가 함께 도는 시스템에서는 256바이트는 거의 확실한 stack overflow입니다. 최소 512바이트, IPC와 component를 함께 쓴다면 1024바이트 이상이 기준입니다.

경고 — Component KConfig 미설정

#include <dfs_posix.h>
open(...); /* link error: DFS component 비활성 */

components는 기본적으로 꺼져 있습니다. menuconfig에서 DFS, LwIP, POSIX 같은 옵션을 개별적으로 켜야 함수 본체가 빌드에 포함됩니다.

경고 — 영문 문서만 의존

공식 문서가 중국어 쪽이 더 자세하고 최신입니다. 영문 페이지가 outdated인 항목이 적지 않습니다. 중국 forum이나 issue tracker를 함께 보는 것이 도움이 됩니다.

경고 — Make 사용 시도

make는 동작하지 않습니다. scons + env tool 또는 RT-Thread Studio가 정식 빌드 경로입니다. Keil/IAR 사용자는 scons --target=mdk5 등으로 project 파일을 생성해서 그 IDE 안에서 빌드합니다.

#정리

  • RT-Thread는 ~10K LoC 경량 커널과 풍부한 component를 같은 트리에 묶은 RTOS입니다.
  • 모든 커널 객체가 rt_object를 상속하는 object-oriented C 설계로, kobject와 비슷한 container를 가집니다.
  • Scheduler는 최대 256 priority bitmap + __rt_ffs로 O(1) lookup을 제공합니다.
  • ipc.c 하나에 세마포어, 뮤텍스, event, mailbox, msg queue가 같은 wait/schedule 패턴 위에 구현됩니다.
  • DFS, LwIP, POSIX, FinSH 같은 components가 KConfig로 켜고 끄는 모듈형 통합으로 제공됩니다.
  • Smart variant는 MMU 기반 user/kernel 분리를 더해 Linux와 RTOS 사이를 메웁니다.
  • 빌드는 env tool + scons가 표준이며, RT-Thread Studio가 별도 IDE로 제공됩니다.
  • 중국 vendor MCU(GD32, HK32, N32, WCH 등)의 de facto 표준 RTOS입니다.

다음 편은 5-04 RTOS 포팅 가이드에서 새 아키텍처에 RTOS를 옮기는 절차를 정리합니다.

#관련 항목

Practical RTOS Internals · 49 of 53

  1. 1Practical RTOS Internals — 실시간 커널 내부 분석 시리즈 소개
  2. 2RTOS가 필요한 이유 — 일반 OS와의 결정적 차이
  3. 3Task와 Thread 개념 — TCB·상태 머신·생명 주기 분석
  4. 4실시간 스케줄링 알고리즘 비교 — RR·Priority·EDF·RMS
  5. 5Preemption과 Cooperation — 강제 전환 vs 자발 양보
  6. 6인터럽트와 RTOS — ISR Context·Deferred Processing·FromISR API
  7. 7동기화 기초 분석 — Critical Section·Mutual Exclusion·Race Condition
  8. 8Semaphore 개념 분해 — Counting·Binary·P/V 연산
  9. 9Mutex 개념 분해 — Ownership·Recursive·Priority Inheritance
  10. 10큐와 메시지 패싱 — Producer-Consumer·Ring Buffer·전달 의미
  11. 11실시간성 분석 — Latency·Jitter·Deadline·WCET·RMA
  12. 12Ready List 자료구조 분석 — Linked List·Bitmap·O(1) Scheduler
  13. 13Blocked List 자료구조 — Timeout 정렬·Delta List·Two-List Scheme
  14. 14Scheduler 알고리즘 구현 추적 — Next-Task Selection 로직
  15. 15Context Switch 원리 분석 — 레지스터 저장·복원·Stack Frame
  16. 16ARM Cortex-M Context Switch — PendSV·MSP/PSP 어셈블리 추적
  17. 17ARM Cortex-A Context Switch — Mode 전환·SVC·Banked Registers
  18. 18RISC-V Context Switch 분석 — ECALL·mret·CSR
  19. 19RTOS Tick과 타이머 — SysTick·Generic Timer·configTICK_RATE_HZ
  20. 20Tickless 모드 구현 — Idle Tick Suppression·Sleep·Wake 보정
  21. 21Scheduler Latency 측정 기법 — GPIO Toggle·DWT·ftrace·cyclictest
  22. 22RTOS Tracing과 Observability — Tracealyzer·SystemView·ITM/ETM
  23. 23Critical Section 구현 비교 — IRQ Disable·BASEPRI·Spinlock
  24. 24Semaphore 내부 구현 추적 — Counter·Wait List·ISR-Safe Variant
  25. 25Mutex 내부 구현 추적 — Owner·Recursion Count·ISR 금지
  26. 26Priority Inversion 문제 — Mars Pathfinder 사례·Bounded vs Unbounded
  27. 27Priority Inheritance 구현 — Inherit·Disinherit·Chain
  28. 28Priority Ceiling Protocol — Immediate vs Original 비교
  29. 29Queue 내부 구현 추적 — Ring Buffer·2 Wait Lists·Atomic Send/Receive
  30. 30Event Group 분석 — Bit Flag·AND/OR Wait·Sync Barrier
  31. 31ISR-Safe API 설계 — FromISR 패턴·Higher Priority Wake·Deferred Work
  32. 32Deadlock 분석 — 4 조건·Wait-for Graph·Lock Ordering·Timeout
  33. 33Stream Buffer와 Message Buffer — FreeRTOS 10의 Lock-Free SPSC
  34. 34실시간 메모리 요구사항 — Determinism·Fragmentation·WCET
  35. 35FreeRTOS Heap_1~5 분석 — 5종 Allocator의 구조와 트레이드오프
  36. 36TLSF Allocator 분석 — Two-Level Segregated Fit O(1)
  37. 37Static Allocation — 컴파일 타임으로 동적 위험 제거하기
  38. 38Memory Pool — Fixed-Size Block Allocator의 단순함과 강력함
  39. 39Stack Overflow 탐지 — Canary·MPU·Watermark 3중 방어
  40. 40SMP RTOS 설계 — Ready List·Affinity·IPI·Load Balancing
  41. 41SMP Spinlock 구현 — LDREX/STREX·Ticket Lock·MCS·WFE/SEV
  42. 42Software Timer 분석 — Daemon Task·자료구조·ISR-Safe API
  43. 43RTOS System Call — SVC·ECALL·User/Kernel 분리·FreeRTOS-MPU
  44. 44TrustZone과 TF-M — Secure/Non-Secure·NSC Veneer·PSA
  45. 45AMP와 OpenAMP — Heterogeneous SoC·RPMsg·remoteproc
  46. 46C++ in RTOS — RAII·std::thread·ETL·Coroutine
  47. 47FreeRTOS 소스 분석 — tasks.c·queue.c·port.c 추적
  48. 48Zephyr 커널 분석 — k_thread·k_sem·Driver Model
  49. 49RT-Thread 분석 — Object 모델·Components·Smart·Studio
  50. 50RTOS 포팅 가이드 — 새 아키텍처에 옮기는 절차
  51. 51RTOS 선택 가이드 — Footprint·License·Certification·Ecosystem
  52. 52Apache NuttX 분석 — POSIX·PX4·NASA Ingenuity
  53. 53PREEMPT_RT Linux — Mainline 6.12·Xenomai 4·EVL