setcontext - setcontext

редактировать

setcontext является одним из семейства функций C library (остальные являются getcontext, makecontext и swapcontext ), используемые для управления контекстом. Семейство setcontextпозволяет реализовать на C расширенные шаблоны потока управления , такие как итераторы, волокна и сопрограммы. Их можно рассматривать как расширенную версию setjmp / longjmp ; тогда как последний допускает только один нелокальный переход вверх по стеку , setcontextпозволяет создавать несколько кооперативных потоков управления, у каждого свой стек.

Содержание
  • 1 Спецификация
  • 2 Определения
  • 3 Пример
  • 4 Ссылки
  • 5 Внешние ссылки
Спецификация

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хранит выполнение состояния, включая все регистры и CPU флаги, указатель инструкции и указатель стека ; mcontext_t- это непрозрачный тип.

Функции:

  • int setcontext (const ucontext_t * ucp)
    Эта функция передает управление контексту в ucp. Выполнение продолжается с точки, в которой контекст был сохранен в ucp. setcontextне возвращает.
  • int getcontext (ucontext_t * ucp)
    Сохраняет текущий контекст в ucp. Эта функция возвращается в двух возможных случаях: после первоначального вызова или когда поток переключается на контекст в ucpчерез setcontextили swapcontext. Функция getcontextне предоставляет возвращаемое значение для различения случаев (ее возвращаемое значение используется исключительно для сообщения об ошибке), поэтому программист должен использовать явную переменную флага, которая не должна быть регистровой переменной и должна быть объявлена ​​volatile, чтобы избежать распространения константы или других оптимизаций компилятора .
  • 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 #include #include / ​​* три контекста: * (1) main_context1: точка в main, к которой цикл вернется. * (2) main_context2: Точка в main, к которой будет * переходить управление из цикла путем переключения контекстов. * (3) loop_context: Точка в цикле, к которой будет * переходить управление из основного путем переключения контекстов. * / ucontext_t main_context1, main_context2, loop_context; / * Возвращаемое значение итератора. * / volatile int i_from_iterator; / * Это функция итератора. Он вводится при первом вызове * swapcontext и циклически изменяется от 0 до 9. Каждое значение сохраняется в i_from_iterator, * и затем swapcontext используется для возврата в основной цикл. Основной цикл печатает * значение и вызывает swapcontext, чтобы переключиться обратно в функцию. Когда достигается конец * цикла, функция завершается, и выполнение переключается на контекст, на который * указывает 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) {/ * Стек для функции итератора. * / char iterator_stack [SIGSTKSZ]; / * Флаг, указывающий, что итератор завершил работу. * / volatile int iterator_finished; getcontext (loop_context); / * Инициализируем контекст итератора. uc_link указывает на main_context1, точку *, к которой нужно вернуться после завершения итератора. * / loop_context.uc_link = main_context1; loop_context.uc_stack.ss_sp = iterator_stack; loop_context.uc_stack.ss_size = sizeof (iterator_stack); / * Заполняем loop_context так, чтобы он создавал цикл запуска swapcontext. Приведение типов * (void (*) (void)) призвано избежать предупреждения компилятора, но * не имеет отношения к поведению функции. * / makecontext (loop_context, (void (*) (void)) loop, 3, loop_context, main_context2, i_from_iterator); / * Сбросить флаг завершения. * / iterator_finished = 0; / * Сохраняем текущий контекст в main_context1. Когда цикл завершится, * поток управления вернется к этой точке. * / getcontext (main_context1); if (! iterator_finished) {/ * Установите iterator_finished так, чтобы, когда предыдущий getcontext * возвращался через uc_link, вышеуказанное условие if было ложным, а итератор * не перезапускался. * / iterator_finished = 1; while (1) {/ * Сохраните эту точку в main_context2 и переключитесь на итератор. * Первый вызов запустит цикл. Последующие вызовы переключатся на * контекст подкачки в цикле. * / swapcontext (main_context2, loop_context); printf ("% d \ n", i_from_iterator); }} return 0; }

ПРИМЕЧАНИЕ: этот пример неверен, но в некоторых случаях может работать должным образом. Функция makecontextтребует, чтобы дополнительные параметры имели тип int, но в примере передаются указатели. Таким образом, пример может не работать на 64-битных машинах (в частности, LP64 -архитектурах, где sizeof (void *)>sizeof (int)). Эту проблему можно обойти путем разделения и восстановления 64-битных значений, но это приводит к снижению производительности.

В архитектурах, где типы int и указатели имеют одинаковый размер (например, x86-32, где оба типа 32-битные), вы можете избежать передачи указателей в качестве аргументов makecontext () после argc. Однако переносимость этого не гарантируется, оно не определено в соответствии со стандартами и не будет работать на архитектурах, в которых указатели больше, чем целые числа. Тем не менее, начиная с версии 2.8, glibc вносит некоторые изменения в

makecontext(3) , чтобы разрешить это на некоторых 64-битных архитектурах (например, x86-64).

Для получения и установки контекст, меньший контекст может быть удобен:

#include #include #include int main (int argc, const char * argv) {ucontext_t context; getcontext (context); put ("Привет, мир"); сон (1); setcontext (context); возврат 0; }

Это создает бесконечный цикл, потому что контекст содержит счетчик программы.

Ссылки
  1. ^ Базовые спецификации Open Group Выпуск 6 IEEE Std 1003.1, издание 2004 г. [1]
Внешние ссылки
Последняя правка сделана 2021-06-08 01:35:46
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте