setcontext - setcontext
SetContext является одним из семейства C библиотеке функций (другие являющиеся getcontext , makecontext и swapcontext ) , используемое для контекста управления. setcontext Семьи позволяют реализовать в C передового поток управления шаблонами , таких как итераторы , волокна и сопрограммы . Их можно рассматривать как расширенную версию setjmp / longjmp ; в то время как последний позволяет только один нелокальный скачок вверх по стеку , setcontext позволяет создавать несколько совместных потоков управления , каждый со своим собственным стеком.
Спецификация
setcontext был указан в POSIX .1-2001 и Single Unix Specification , версия 2, но не все Unix-подобные операционные системы предоставляют их. POSIX .1-2004 устарел эти функции, а в POSIX .1-2008 они были удалены, с указанием потоков POSIX в качестве возможной замены. Ссылаясь на IEEE Std 1003.1, издание 2004 г .:
С включением стандарта ISO / IEC 9899: 1999 в эту спецификацию было обнаружено, что стандарт ISO C (подраздел 6.11.6) определяет, что использование деклараторов функций с пустыми скобками является устаревшей функцией. Следовательно, используя прототип функции:
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);использует устаревшую функцию стандарта ISO C. Следовательно, приложение, строго соответствующее POSIX, не может использовать эту форму. Поэтому использование getcontext (), makecontext () и swapcontext () помечено как устаревшее.
В стандарте ISO C нет способа указать не устаревший прототип функции, указывающий, что функция будет вызываться с произвольным числом (включая ноль) аргументов произвольных типов (включая целые числа, указатели на данные, указатели на функции и составные типы).
Определения
Функции и связанные типы определены в файле заголовкаucontext.h системы . Сюда входит тип, с которым работают все четыре функции:
ucontext_t
typedef struct {
ucontext_t *uc_link;
sigset_t uc_sigmask;
stack_t uc_stack;
mcontext_t uc_mcontext;
...
} ucontext_t;
uc_link указывает на контекст, который будет возобновлен при выходе из текущего контекста, если контекст был создан с makecontext (вторичным контекстом). uc_sigmask используется для хранения набора сигналов, заблокированных в контексте, и uc_stack является стеком, используемым контекстом. uc_mcontext сохраняет состояние выполнения , включая все регистры и флаги ЦП , указатель команд и указатель стека ; является непрозрачным типом .
mcontext_t
Функции:
-
int setcontext(const ucontext_t *ucp)- Эта функция передает управление контексту в
ucp. Выполнение продолжается с точки, в которой был сохранен контекстucp.setcontextне возвращается.
- Эта функция передает управление контексту в
-
int getcontext(ucontext_t *ucp)- Сохраняет текущий контекст в
ucp. Эта функция возвращается в двух возможных случаях: после первоначального вызова или когда поток переключается на контекстucpчерезsetcontextилиswapcontext.getcontextФункция не обеспечивает возвращаемое значение , чтобы отличить случаи (возвращаемое значение используется исключительно для сигнала ошибки), поэтому программист должен использовать явный переменный флаг, который не должен быть переменным регистр и должен быть признан неустойчивой , чтобы избежать постоянного распространения или другие оптимизации компилятора .
- Сохраняет текущий контекст в
-
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...)makecontextФункция устанавливает альтернативный поток управления вucp, который ранее был инициализирован с помощьюgetcontext. Элементucp.uc_stackдолжен быть указан в стеке подходящего размера;SIGSTKSZобычно используется константа . Приucpпереходе к использованиюsetcontextилиswapcontextвыполнение начнется с точки входа в функцию, на которую указываетfunc, сargcуказанными аргументами. Когдаfuncзавершается, управление возвращается кucp.uc_link.
-
int swapcontext(ucontext_t *oucp, ucontext_t *ucp)- Передает управление
ucpи сохраняет текущее состояние выполненияoucp.
- Передает управление
пример
В приведенном ниже примере демонстрируется использование итератора setcontext .
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
/* The three contexts:
* (1) main_context1 : The point in main to which loop will return.
* (2) main_context2 : The point in main to which control from loop will
* flow by switching contexts.
* (3) loop_context : The point in loop to which control from main will
* flow by switching contexts. */
ucontext_t main_context1, main_context2, loop_context;
/* The iterator return value. */
volatile int i_from_iterator;
/* This is the iterator function. It is entered on the first call to
* swapcontext, and loops from 0 to 9. Each value is saved in i_from_iterator,
* and then swapcontext used to return to the main loop. The main loop prints
* the value and calls swapcontext to swap back into the function. When the end
* of the loop is reached, the function exits, and execution switches to the
* context pointed to by main_context1. */
void loop(
ucontext_t *loop_context,
ucontext_t *other_context,
int *i_from_iterator)
{
int i;
for (i=0; i < 10; ++i) {
/* Write the loop counter into the iterator return location. */
*i_from_iterator = i;
/* Save the loop context (this point in the code) into ''loop_context'',
* and switch to other_context. */
swapcontext(loop_context, other_context);
}
/* The function falls through to the calling context with an implicit
* ''setcontext(&loop_context->uc_link);'' */
}
int main(void)
{
/* The stack for the iterator function. */
char iterator_stack[SIGSTKSZ];
/* Flag indicating that the iterator has completed. */
volatile int iterator_finished;
getcontext(&loop_context);
/* Initialise the iterator context. uc_link points to main_context1, the
* point to return to when the iterator finishes. */
loop_context.uc_link = &main_context1;
loop_context.uc_stack.ss_sp = iterator_stack;
loop_context.uc_stack.ss_size = sizeof(iterator_stack);
/* Fill in loop_context so that it makes swapcontext start loop. The
* (void (*)(void)) typecast is to avoid a compiler warning but it is
* not relevant to the behaviour of the function. */
makecontext(&loop_context, (void (*)(void)) loop,
3, &loop_context, &main_context2, &i_from_iterator);
/* Clear the finished flag. */
iterator_finished = 0;
/* Save the current context into main_context1. When loop is finished,
* control flow will return to this point. */
getcontext(&main_context1);
if (!iterator_finished) {
/* Set iterator_finished so that when the previous getcontext is
* returned to via uc_link, the above if condition is false and the
* iterator is not restarted. */
iterator_finished = 1;
while (1) {
/* Save this point into main_context2 and switch into the iterator.
* The first call will begin loop. Subsequent calls will switch to
* the swapcontext in loop. */
swapcontext(&main_context2, &loop_context);
printf("%d\n", i_from_iterator);
}
}
return 0;
}
ПРИМЕЧАНИЕ: этот пример неверен, но в некоторых случаях может работать должным образом. Функция makecontext требует, чтобы дополнительные параметры были типом int , но в примере передаются указатели. Таким образом, пример может не работать на 64-битных машинах (в частности, на архитектуре LP64, где ). Эту проблему можно обойти, разбив и восстановив 64-битные значения, но это приводит к снижению производительности.
sizeof(void*) > sizeof(int)
В архитектурах, где типы int и указатели имеют одинаковый размер (например, x86-32, где оба типа 32-битные), вы можете обойтись без передачи указателей в качестве аргументов для makecontext () после argc. Однако переносимость этого не гарантируется, оно не определено в соответствии со стандартами и не будет работать на архитектурах, где указатели больше, чем ints. Тем не менее, начиная с версии 2.8, glibc вносит некоторые изменения в
, чтобы разрешить это на некоторых 64-битных архитектурах (например, x86-64).
Для получения и установки контекста может пригодиться меньший контекст:
#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>
int main(int argc, const char *argv[]){
ucontext_t context;
getcontext(&context);
puts("Hello world");
sleep(1);
setcontext(&context);
return 0;
}
Это создает бесконечный цикл, потому что контекст содержит счетчик программы.
Рекомендации
внешние ссылки
- Система V контексты - The GNU C Library Руководство
- : получить / установить текущий пользовательский контекст - Руководство программиста Linux - Библиотечные функции
- setcontext - получить / установить текущий пользовательский контекст справочной страницы FreeBSD.