Почему печать в stderr вызывает ошибку сегментации при работе с ucontext?
Я работал над проектом для курса по операционным системам. Задача состояла в том, чтобы реализовать библиотеку для работы с потоками, аналогичную pthreads
, но гораздо проще. Цель этого состоит в том, чтобы практиковать алгоритмы планирования. Конечный продукт .a
файл. Курс окончен, и все работает просто отлично (с точки зрения функциональности).
Хотя мне стало любопытно, с какой проблемой я столкнулся. В трех разных функциях моего исходного файла, если я добавлю, например, следующую строку:
fprintf(stderr, "My lucky number is %d\n", 4);
Я получаю ошибку сегментации. То же самое не произойдет, если stdout
используется вместо этого, или если форматирование не содержит никаких переменных.
Это оставляет меня с двумя основными вопросами:
Почему это происходит только в трех функциях моего кода, а не в других?
Может ли создание контекстов с помощью
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 ответ
Предполагая, glibc, объяснение состоит в том, что fprintf
с небуферизованным потоком (таким как stderr
по умолчанию) внутренне создает буфер в стеке, который размером BUFSIZE
байт. Смотрите функцию buffered_vfprintf
в stdio-common/vfprintf.c
, BUFSIZ
8192, так что в итоге вы переполняете стек, потому что созданный вами стек слишком мал.