🌱 RTOS 06 - Context Switch - Chuyển đổi ngữ cảnh giữa các Task

🌱 RTOS 06. Context Switch - Chuyển đổi ngữ cảnh giữa các Task

    Một vấn đề quan trọng trong RTOS đó là việc chuyển đổi ngữ cảnh, việc một Task đang chạy phải dừng lại để nhường chỗ cho Task khác, sau đó khi trở lại hoạt động thì Task đó vẫn tiếp tục công việc cũ không hề đơn giản. 

    Vì vậy cần có những cơ chế riêng để thực hiện việc này, đó chính là cơ chế Context Switch - Chuyển đổi ngữ cảnh.

    Các nội dung chính

        👉 Khi nào cần gọi hàm lập lịch - Scheduler()?

        Khi xây dựng việc lập lịch cho RTOS, chúng ta cần có một list các Task cần được thực hiện, cụ thể, để quy định việc Task nào sẽ được thực hiện tiếp theo, chúng ta sẽ xây dựng một Queue - hàng đợi. Task nào đứng đầu Queue sẽ là task tiếp theo cần thực hiện. 

    RTOS Task Queue
    Một ví dụ về Queue để quản lý các Task trong RTOS

        Queue được xây dựng cho các Task sẽ giống như trong hình trên. Các task mới cần được thực hiện sẽ được đưa vào Queue này. 

    • Task có mức độ ưu tiên cao hơn sẽ được xếp trên các Task có mức độ ưu tiên thấp hơn. 
    • Task đến trước sẽ đứng trên Task đến sau nếu có cùng mức độ ưu tiên.
        👉 Các Task trong Queue này sẽ được gọi thực thi bởi hàm lập lịch - Scheduler(). Hàm lập lịch sẽ gọi trong các trường hợp sau:
    • Task có mức độ ưu tiên cao hơn task đang thực thi muốn thực hiện. Khi đó, task này sẽ nhảy lên đầu Queue, task đang thực thi sẽ phải nhường lại quyền điều khiển cho task đó. Lúc này, Kernel sẽ gọi hàm lập lịch Scheduler() để chuyển sang Task có mức ưu tiên cao hơn.
    • Khi Task hiện tại kết thúc hoặc chủ động "nhường" tài nguyên, bằng cách gọi các hàm lập lịch như taskYIELD() hoặc vTaskDelay(), khi gọi hàm này, Task hiện tại sẽ ngưng làm việc trong thời gian delay, vì vậy, để tránh lãng phí tài nguyên hệ thống, Kernel sẽ gọi hàm lập lịch Scheduler() để chuyển qua Task khác.
    • Khi hết thời gian Time-Slice, Kernel sẽ chuyển sang task tiếp theo để thực thi bằng cách gọi hàm lập lịch Scheduler().
    • Task bị block do chờ tài nguyên như chờ semaphore, queue, hoặc mutex.
    • Khi một ngắt xảy ra, OS cũng có thể cần gọi lại hàm lập lịch, ví dụ Scheduler có thể được gọi thông qua hàm như portYIELD_FROM_ISR() trong FreeRTOS.
    • Sự kiện định kỳ từ Timer khi đếm hết timeout.
        Vậy khi gọi hàm lập lịch, Kernel sẽ cho phép chuyển từ Task hiện tại sang Task đứng đầu Queue. Như đã nói thì việc chuyển Task như vậy cần một cơ chế chuyển đổi ngữ cảnh - Context Switch.
    RTOS Context Switching Concept
    RTOS Context Switching Concept

        👉 Context Switch - Chuyển đổi ngữ cảnh

         Việc chuyển đổi ngữ cảnh sinh ra với 2 mục đích: 

    • Lưu lại ngữ cảnh (dữ liệu) của Task đang thực thi trước khi chuyển qua task khác, ngữ cảnh này sẽ được lưu vào vùng nhớ TCB của Task.
    • Lấy lại ngữ cảnh cũ của Task đang chuẩn bị được thực thi để tiếp tục task đó. Việc này ngược lại với việc trên, đó là lấy dữ liệu từ vùng nhớ TCB của Task tương ứng.
    RTOS Context Switch
    RTOS Context Switch
        Việc thực thi Context Switch sẽ dựa trên 2 exceptions của hệ thống, đó là: 
    • SVC - supervisor call.
    • PendSV Exception.
    RTOS Context Switch PendSV and SVCall
    SVCall & PendSV Exception

        ➤ Trigger Context Switch sử dụng PendSV Exception

        PendSV (Pending Supervisor Call) là một loại exception đặc biệt trên vi điều khiển lõi ARM Cortex-M, được thiết kế để hỗ trợ quản lý ngữ cảnh (context switching) trong hệ điều hành thời gian thực (RTOS), giúp chuyển đổi giữa các task hiệu quả và đơn giản.

        Trong RTOS thì PendSV luôn được cấu hình với mức ưu tiên cao nhất trong các ngắt có thể cấu hình, điều này đảm bảo nó chỉ được thực thi khi không có ngắt khác quan trọng hơn đang diễn ra.

        PendSV chỉ được kích hoạt bằng phần mềm, bằng cách ghi vào thanh ghi SCB_ICSR (Interrupt Control and State Register).

    Thanh ghi SCB_ICSR cho PendSV
    Thanh ghi SCB_ICSR cho PendSV

        ➤ PendSV Exception Handler

        Trong hàm xử lý ngắt PendSV_Handler cần lưu trạng thái của task cũ và khôi phục trạng thái của task mới, trạng thái nói đến ở đây chính là các thanh ghi của Core, các thanh ghi tính toán, thanh ghi status, thanh ghi chức năng đặc biệt.

    PendSV Handler for Context Switching
    PendSV Handler for Context Switching

        Chính vì access đến các thanh ghi Core nên PendSV_Handler thường được viết bằng ngôn ngữ Assembly.

    RTOS Context Switch with MSP
    RTOS Context Switch with MSP

        Về cơ bản RTOS Context Switch trong PendSV_Handler sẽ bao gồm 3 bước:

    RTOS PendSV Steps
    PendSV Handler Stepping

    ① Store Context of Current Task

        Bước này cần lưu lại giá trị các thanh ghi cần thiết, các thanh ghi tính toán trong Stack Frame đã được lưu lại khi xảy ra Exception

    RTOS Store Context of Current Task
    Lưu lại trạng thái của Task hiện tại (Task cũ)
    Lưu lại trạng thái của Task hiện tại (Task cũ)
    Lưu lại trạng thái của Task hiện tại (Task cũ)

    ② Switch Current Pointer

        Cập nhật Process Stack Pointer (PSP) của task mới trước khi chạy task mới!

    Switch Current Pointer
    Switch Current Pointer

    ③ Restore Context of Next Task

        Cập nhật ngữ cảnh của Task mới trước khi chạy, tương tự như

    Restore Context of Next Task
    Restore Context of Next Task
    • Sau đó tiếp tục chạy task mới
    Restore Context of Next Task
    Restore Context of Next Task
        ➥ Nhìn chung là với cơ chế trên thì chúng ta có thể sử dụng một ngắt khác thay cho PendSV, tuy nhiên PendSV là exception được tạo ra để làm việc này, khiến cho cơ chế RTOS trở nên đơn giản hơn.

    >>>= Follow ngay =<<<

    Để theo dõi những bài học miễn phí mới nhất nhé 😊

    Chúc các bạn học tập tốt 😊

    Nguyễn Văn Nghĩa

    Mình là một người thích học hỏi và chia sẻ các kiến thức về Nhúng IOT.

    1 Nhận xét

    Mới hơn Cũ hơn