setcontext

setcontext

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

Содержание

Спецификация

setcontext определён в POSIX.1-2001 и во второй версии Single UNIX Specification, однако доступен не во всех UNIX-подобных операционных системах. Функции и связанные с ними типы определены в заголовочном файле ucontext.h. В их число входит тип ucontext_t, с которым взаимодействуют все четыре функции:

typedef struct ucontext {
        struct ucontext *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 является непрозрачным (opaque) указателем.

Также определены следующие функции:

  • int setcontext(const ucontext_t *ucp)
Эта функция переносит управление в контекст в ucp. Исполнение продолжается с точки, на которой контекст был сохранён в ucp. В случае успешного выполнения возврата из setcontext не производится.
  • int getcontext(ucontext_t *ucp)
Сохраняет текущий контекст в ucp. Возврат из этой функции происходит в двух случаях: после первичного вызова или при переключении потока на контекст в ucp с помощью setcontext или swapcontext. Функция getcontext не предоставляет возвращаемого значения для разделения этих случаев (оно служит лишь для сообщения об ошибке), поэтому разработчик должен явным образом использовать переменную-флаг, объявленную без модификатора register и с модификатором 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. Подобный код можно встретить достаточно редко; вместо использования setcontext для реализации кооперативной многозадачности часто используется различные библиотеки-обёртки, например, GNU Portable Threads.

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
 
/* Функция-итератор. Вход в неё осуществляется при первом вызове
 * 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) {
        /* Запись счётчика цикла в место возврата итератора. */
        *i_from_iterator = i;
 
        /* Сохранение контекста цикла в ''loop_context'' и переключение на другой контекст. */
        swapcontext(loop_context, other_context);
    }
} 
 
int main(void)
{
    /* Три контекста:
     *    (1) main_context1 : указывает на main для возврата из цикла.
     *    (2) main_context2 : указывает на место переключения контекста в main
     *    (3) loop_context  : указывает на место в цикле, в которое будет 
     *                        переходить управление из main. */
    ucontext_t main_context1, main_context2, loop_context;
 
    /* Стек для функции итератора. */
    char iterator_stack[SIGSTKSZ];
 
    /* Флаг, сообщающий о завершении итератора. */
    volatile int iterator_finished;
 
    /* Возвращаемое значение итератора. */
    volatile int i_from_iterator;
 
    /* Инициализация контекста итератора. 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);
    getcontext(&loop_context);
 
    /* Заполнение 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 для отключения перезапуска итератора. */
        iterator_finished = 1;
 
        while (1) {
            /* Сохранение этой точки в main_context2 и переключение на итератор.
             * Первый вызов зачинает цикл, последующие осуществляют переключение
             * через swapcontext в цикл. */
            swapcontext(&main_context2, &loop_context);
            printf("%d\n", i_from_iterator);
        }
    }
 
    return 0;
}

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

Примечания

Ссылки


Wikimedia Foundation. 2010.

Игры ⚽ Нужен реферат?

Полезное


Смотреть что такое "setcontext" в других словарях:

  • setcontext — is one of a family of C library functions (the others being getcontext, makecontext and swapcontext) used for context control. The setcontext family allows the implementation in C of advanced control flow patterns such as iterators, fibers, and… …   Wikipedia

  • Setcontext — is one of a family of C library functions (the others being getcontext, makecontext and swapcontext) used for context control. The setcontext family allows the implementation in C of advanced control flow patterns such as iterators, fibers, and… …   Wikipedia

  • setjmp.h — C Standard Library Data types Character classification Strings Mathematics File input/output Date/time Localization …   Wikipedia

  • Setjmp.h — Este artículo o sección necesita ser wikificado con un formato acorde a las convenciones de estilo. Por favor, edítalo para que las cumpla. Mientras tanto, no elimines este aviso puesto el 8 de junio de 2011. También puedes ayudar wikificando… …   Wikipedia Español

  • Coroutine — Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations. Coroutines are well suited for implementing more familiar program components such as …   Wikipedia

  • Fiber (computer science) — In computer science, a fiber is a particularly lightweight thread of execution.Like threads, fibers share address space; where a distinction exists, it is that fibers use co operative multitasking while threads use pre emptive multitasking.… …   Wikipedia

  • Fibre (informatique) — Pour les articles homonymes, voir Fibre (homonymie). En Informatique, une fibre (fiber en anglais) est un thread d exécution particulièrement léger. Comme les threads, les fibres partagent la même mémoire virtuelle. Toutefois, les fibres… …   Wikipédia en Français

  • Continuation — For other uses, see Continuation (disambiguation). In computer science and programming, a continuation is an abstract representation of the control state of a computer program. A continuation reifies the program control state, i.e. the… …   Wikipedia

  • Call stack — In computer science, a call stack is a stack data structure that stores information about the active subroutines of a computer program. This kind of stack is also known as an execution stack, control stack, run time stack, or machine stack, and… …   Wikipedia

  • Continuation — Dieser Artikel wurde aufgrund von inhaltlichen Mängeln auf der Qualitätssicherungsseite der Redaktion Informatik eingetragen. Dies geschieht, um die Qualität der Artikel aus dem Themengebiet Informatik auf ein akzeptables Niveau zu bringen. Hilf… …   Deutsch Wikipedia


Поделиться ссылкой на выделенное

Прямая ссылка:
Нажмите правой клавишей мыши и выберите «Копировать ссылку»