1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/rcore-os-rCore-Tutorial

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
part-4.md 3.4 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 29.11.2024 21:14 7f8a4fd

Завершение потока

Существующая проблема

Что происходит, когда поток ядра завершается? Если мы посмотрим на текущую реализацию, то обнаружим, что функция, выполняемая потоком, завершается с исключением Exception::InstructionPageFault, при этом адрес, к которому осуществляется доступ, равен stval = 0.

Это происходит потому, что после выполнения функции, на которую указывает entry_point, поток возвращается к адресу, на который указывает ra, и мы не присвоили ему начальное значение (начальное значение равно 0). В этот момент программа пытается перейти по адресу 0x0, который явно не существует.

Решение проблемы

Естественно, мы хотим, чтобы поток ядра вызывал дружественное прерывание при завершении, а не похожее на ошибку исключение отсутствия страницы. Мы могли бы подумать о системном вызове, но, к сожалению, его нельзя использовать, так как системный вызов по своей сути является вызовом среды ecall, а вызовы среды в контексте потока ядра (в режиме ядра) предназначены для взаимодействия с M-режимом. Ранее реализованный SBI-вызов использует S-режим ecall.

Поэтому мы разработали компромиссное решение: поток ядра помечает себя как «завершённый» и одновременно вызывает обычное исключение ebreak. Операционная система, заметив метку потока, завершает его.

/// Поток ядра должен вызвать эту функцию для выхода
fn kernel_thread_exit() {
    // Текущий поток помечается как завершённый
    PROCESSOR.lock().current_thread().as_ref().inner().dead = true;
    // Создаётся прерывание для обработки операционной системой
    unsafe { llvm_asm!("ebreak" :::: "volatile") };
}

Затем мы используем эту функцию в качестве ra для потока ядра, чтобы после завершения функции, на которую он указывает, выполнялась kernel_thread_exit().

/// Создание потока ядра
pub fn create_kernel_thread(
    process: Arc<Process>,
    entry_point: usize,
    arguments: Option<&[usize]>,
) -> Arc<Thread> {
    // Создание потока
    let thread = Thread::new(process, entry_point, arguments).unwrap();
    // Установка адреса возврата потока на kernel_thread_exit
    thread.as_ref().inner().context.as_mut().unwrap()
        .set_ra(kernel_thread_exit as usize);
    thread
}

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/rcore-os-rCore-Tutorial.git
git@api.gitlife.ru:oschina-mirror/rcore-os-rCore-Tutorial.git
oschina-mirror
rcore-os-rCore-Tutorial
rcore-os-rCore-Tutorial
master