Bỏ qua điều hướng, tới nội dung chính
Học C
Bài 60.832 phút đọc

Level 8: Mini RTOS

Sau bài này bạn sẽ làm được

  • Cài chuyển ngữ cảnh bằng PendSV và assembly
  • Viết bộ lập lịch xoay vòng theo mức ưu tiên
  • Cài delay không chặn để task khác chạy được
  • Phát hiện tràn ngăn xếp bằng số kỳ diệu ở đáy

Dự án cuối cùng, đỉnh của toàn khoá: viết một hệ điều hành thời gian thực nhỏ. Bạn tự cài chuyển ngữ cảnh, bộ lập lịch, và các nguyên thuỷ đồng bộ. Đây là nơi mọi thứ đã học, kể cả assembly, gặp nhau.

#Mục tiêu

API cần cài
void rtos_init(void);
int  rtos_task_create(void (*fn)(void *), void *arg,
                      uint8_t prio, size_t stack_size);
void rtos_start(void);
void rtos_delay(uint32_t ms);       /* KHONG chan: task khac chay duoc */
void rtos_yield(void);

Semaphore *sem_create(int gia_tri_dau);
void       sem_wait(Semaphore *);
void       sem_post(Semaphore *);

Queue *queue_create(size_t item_size, size_t n);
int    queue_send(Queue *, const void *item, uint32_t timeout);
int    queue_recv(Queue *, void *item, uint32_t timeout);
Thành phầnKỹ thuậtPhần
Chuyển ngữ cảnhPendSV handler, assemblyPhần 18, 12
Task Control BlockCon trỏ ngăn xếp, trạng thái, ưu tiênPhần 5, 6
Bộ lập lịchXoay vòng theo mức ưu tiênPhần 8
Tick hệ thốngSysTick 1 mili giâyPhần 18
Đồng bộSemaphore, mutex, hàng đợiPhần 16
Phát hiện tràn ngăn xếpSố kỳ diệu ở đáyBài 60.7

#Chuyển ngữ cảnh

Task Control Block và ý tưởng chuyển ngữ cảnh
typedef enum { SAN_SANG, DANG_CHAY, DANG_CHO, DANG_NGU } TrangThai;

typedef struct {
    uint32_t   *sp;                 /* CON TRO NGAN XEP da luu cua task */
    TrangThai   trang_thai;
    uint8_t     uu_tien;
    uint32_t    thuc_day_luc;       /* moc thoi gian danh thuc neu dang ngu */
    uint32_t    stack[STACK_CO];    /* ngan xep RIENG cua task */
} TCB;

/* Y tuong chuyen ngu canh:
   1. Task A dang chay. Ngat SysTick (hoac yield) kich hoat PendSV.
   2. PendSV handler LUU moi thanh ghi cua A vao NGAN XEP CUA A,
      roi luu con tro ngan xep hien tai vao tcb_A->sp.
   3. Bo lap lich chon task B tiep theo.
   4. Nap tcb_B->sp vao con tro ngan xep, roi KHOI PHUC moi thanh
      ghi tu ngan xep cua B.
   5. Tra ve tu PendSV -> gio dang chay task B, tu dung cho no
      da dung lai lan truoc.

   Diem tinh te: moi task co NGAN XEP RIENG. "Trang thai" cua mot
   task khong chay chinh la cac thanh ghi da luu tren ngan xep
   cua no. Chuyen task chi la doi con tro ngan xep. */

#Bộ lập lịch

Xoay vòng theo mức ưu tiên
/* Chon task tiep theo:
     - task uu tien CAO chay truoc task uu tien thap
     - cung muc uu tien thi XOAY VONG (round-robin) cong bang
     - bo qua task dang cho hoac dang ngu */

static TCB *chon_task_tiep(void) {
    /* tim muc uu tien cao nhat co task SAN SANG */
    for (int p = UU_TIEN_CAO_NHAT; p >= 0; --p) {
        TCB *bat_dau = con_tro_xoay[p];
        TCB *t = bat_dau;
        do {
            if (t->trang_thai == SAN_SANG) {
                con_tro_xoay[p] = t->tiep;   /* lan sau bat dau tu ke tiep */
                return t;
            }
            t = t->tiep;
        } while (t != bat_dau);
    }
    return task_nhan_roi;               /* khong task nao san sang */
}

#Đồng bộ

#Yêu cầu

Tự làm thử

  1. Chuyển ngữ cảnh bằng PendSV handler, viết assembly.
  2. TCB: con trỏ ngăn xếp, trạng thái, ưu tiên, thời điểm đánh thức.
  3. Bộ lập lịch xoay vòng trong cùng mức ưu tiên, ưu tiên cao chạy trước.
  4. SysTick một mili giây làm tick hệ thống.
  5. delay không chặn, task khác chạy được.
  6. Semaphore, mutex có kế thừa ưu tiên, hàng đợi thông điệp.
  7. Phát hiện tràn ngăn xếp bằng số kỳ diệu ở đáy.
  8. Thống kê: CPU mỗi task, ngăn xếp còn lại.

Trình chấm điểm tự động sẽ được bổ sung ở giai đoạn sau. Hiện tại bạn tự chạy thử trên máy.

Tóm tắt

  • Dự án cuối là viết một RTOS nhỏ: bạn tự lập lịch, tự chuyển ngữ cảnh, tự quản lý bộ nhớ.
  • Chuyển ngữ cảnh phải là assembly trong PendSV vì nó thao tác trực tiếp thanh ghi và phải nguyên tử; mỗi task có ngăn xếp riêng.
  • delay không chặn là cốt lõi của đa nhiệm: task ngủ thì task khác chạy, CPU không lãng phí.
  • Mutex phải có kế thừa ưu tiên để tránh đảo ngược ưu tiên, lỗi từng làm treo tàu Mars Pathfinder.
  • Phát hiện tràn ngăn xếp bằng số kỳ diệu là bắt buộc, và cả dự án cần tài liệu thiết kế cùng lịch sử git hợp lý.