Почему печать в stderr вызывает ошибку сегментации при работе с ucontext? - PullRequest
0 голосов
/ 23 декабря 2018

Я работал над проектом для курса по операционным системам.Задача состояла в том, чтобы реализовать библиотеку для работы с потоками, похожую на pthreads, но гораздо более простую.Цель этого состоит в том, чтобы практиковать алгоритмы планирования.Конечный продукт - файл .a.Курс закончен, и все работает нормально (с точки зрения функциональности).

Хотя мне стало любопытно, с какой проблемой я столкнулся.Например, в трех разных функциях моего исходного файла, если я добавлю следующую строку:

fprintf(stderr, "My lucky number is %d\n", 4);

Я получу ошибку сегментации.То же самое не происходит, если вместо этого используется stdout, или если форматирование не содержит никаких переменных.

Это оставляет мне два основных вопроса:

  1. Почему это происходит только в трех функциях моего кода, а не в других?

  2. Может ли создание контекстов с использованием getcontext() и makecontext() или изменение контекстов с использованиемsetcontext() или swapcontext() испортить стандартные файловые дескрипторы?

Моя интуиция говорит, что эти функции могут отвечать за это.Еще больше, если учесть тот факт, что три функции моего кода, в которых это происходит, являются функциями, которые имеют контексты, на которые переключаются другие части кода.Обычно по setcontext(), хотя swapcontext() используется для перехода к планировщику, для выбора другого потока для выполнения.

Дополнительно, если это так, то:

Как правильно создавать потоки, используя эти функции?

В настоящее время я делаю следующее:

/*------------------------------------------------------------------------------
Funct:  Creates an execution context for the function and arguments passed.
Input:  uc      -> Pointer where the context will be created.
        funct   -> Function to be executed in the context.
        arg     -> Argument to the function.
Return: If the function succeeds, 0 will be returned. Otherwise -1.
------------------------------------------------------------------------------*/
static int create_context(ucontext_t *uc, void *funct, void *arg)
{
    if(getcontext(uc) != 0) // Gets a context "model"
    {
        return -1;
    }
    stack_t *sp = (stack_t*)malloc(STACK_SIZE); // Stack area for the execution context
    if(!sp) // A stack area is mandatory
    {
        return -1;
    }
    uc->uc_stack.ss_sp = sp; // Sets stack pointer
    uc->uc_stack.ss_size = STACK_SIZE; // Sets stack size
    uc->uc_link = &context_end; // Sets the context to go after execution

    makecontext(uc, funct, 1, arg); // "Makes everything work" (can't fail)
    return 0;
}

Этот код, вероятно, немного изменен, ноизначально это онлайн-пример использования u_context.

1 Ответ

0 голосов
/ 05 января 2019

Предполагая, что glibc объясняет, что fprintf с небуферизованным потоком (таким как stderr по умолчанию) внутренне создает буфер в стеке размером BUFSIZE байтов.См. Функцию buffered_vfprintf в stdio-common/vfprintf.c.BUFSIZ равно 8192, поэтому вы переполняете стек, поскольку создаваемый вами стек слишком мал.

...