Jump to content

установитьконтекст

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

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

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

setcontext был указан в POSIX .1-2001 и Единой спецификации Unix версии 2, но не все Unix-подобные операционные системы предоставляют их. В POSIX .1-2004 эти функции устарели. [1] а в POSIX .1-2008 они были удалены, а потоки POSIX в качестве возможной замены были указаны .

Определения

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

Функции и связанные типы определены в 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, ...)
    The 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>
#include <signal.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;
}

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

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

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

  1. ^ Jump up to: а б Базовые спецификации открытой группы, выпуск 6 Стандарт IEEE 1003.1, издание 2004 г. [1]
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: a668548461038aee08fa25ee7cb1972c__1709964900
URL1:https://arc.ask3.ru/arc/aa/a6/2c/a668548461038aee08fa25ee7cb1972c.html
Заголовок, (Title) документа по адресу, URL1:
setcontext - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)