Linux repositories inspector
GNU
2019-03-06
Aliases: swapcontext(3), swapcontext(3), swapcontext(3), swapcontext(3), swapcontext(3), swapcontext(3), swapcontext(3), swapcontext(3)

man-pages-ru

Russian man pages from the Linux Documentation Project

manpages-dev

Manual pages about using GNU/Linux for development

man-pages

Linux kernel and C library user-space interface documentation

ИМЯ

makecontext, swapcontext - управляет пользовательским контекстом

ОБЗОР

#include <ucontext.h>
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);

ОПИСАНИЕ

В окружении, подобном SysV, имеется тип данных mcontext_t, определённый в файле <ucontext.h>, и четыре функции — getcontext(3), setcontext(3), makecontext() и swapcontext(), которые позволяют контексту пользовательского уровня переключаться между несколькими нитями внутри одного процесса.
Описание типа и первых двух функций смотрите в getcontext(3).
Функция makecontext() изменяет контекст, на который указывает ucp (полученный из вызова getcontext(3)). Перед вызовом makecontext(), вызывающий должен выделить новый стек для этого контекста и присвоить его адрес ucp->uc_stack, и определить последующий контекст и присвоить его адрес ucp->uc_link.
Позднее, когда этот контекст активируется (с помощью setcontext(3) или swapcontext()), вызывается функция func и ей передаётся набор целочисленных аргументов (int), указанных после argc; вызывающий должен указать количество этих аргументов в argc. После возврата из функции активируется последующий контекст. Если указатель последующего контекста равен NULL, то нить завершается.
Функция swapcontext() сохраняет текущий контекст в структуру, на которую указывает oucp, и после этого активирует контекст, на который указывает ucp.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении swapcontext() не возвращает выполнение (но мы можем вернуться позднее при активации oucp и это будет выглядеть как если бы swapcontext() вернула 0). При ошибке swapcontext() возвращает -1 и изменяет errno соответствующим образом.

ОШИБКИ

ENOMEM Осталось недостаточно стекового пространства.

ВЕРСИИ

Функции makecontext() и swapcontext() появились в glibc начиная с версии 2.1.

АТРИБУТЫ

Описание терминов данного раздела смотрите в attributes(7).
Интерфейс Атрибут Значение
makecontext() Безвредность в нитях MT-Safe race:ucp
swapcontext() Безвредность в нитях MT-Safe race:oucp race:ucp

СООТВЕТСТВИЕ СТАНДАРТАМ

SUSv2, POSIX.1-2001. В POSIX.1-2008 удалены определения makecontext() и swapcontext() со ссылкой на проблемы с переносимостью и рекомендацией переписать приложение с использование нитей POSIX.

ЗАМЕЧАНИЯ

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

ПРИМЕР

В программе, показанной далее, демонстрируется использование getcontext(3), makecontext() и swapcontext(). Вот результат запуска этой программы:
$ ./a.out main: swapcontext(&uctx_main, &uctx_func2) func2: запущена func2: swapcontext(&uctx_func2, &uctx_func1) func1: запущена func1: swapcontext(&uctx_func1, &uctx_func2) func2: возврат func1: возврат main: выход

Исходный код программы

#include <ucontext.h> #include <stdio.h> #include <stdlib.h>
static ucontext_t uctx_main, uctx_func1, uctx_func2;
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
static void func1(void) {
printf("func1: запущена\n");
printf("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
if (swapcontext(&uctx_func1, &uctx_func2) == -1)
handle_error("swapcontext");
printf("func1: возврат\n"); }
static void func2(void) {
printf("func2: запущена\n");
printf("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
if (swapcontext(&uctx_func2, &uctx_func1) == -1)
handle_error("swapcontext");
printf("func2: возврат\n"); }
int main(int argc, char *argv[]) {
char func1_stack[16384];
char func2_stack[16384];
if (getcontext(&uctx_func1) == -1)
handle_error("getcontext");
uctx_func1.uc_stack.ss_sp = func1_stack;
uctx_func1.uc_stack.ss_size = sizeof(func1_stack);
uctx_func1.uc_link = &uctx_main;
makecontext(&uctx_func1, func1, 0);
if (getcontext(&uctx_func2) == -1)
handle_error("getcontext");
uctx_func2.uc_stack.ss_sp = func2_stack;
uctx_func2.uc_stack.ss_size = sizeof(func2_stack);
/* последующий контекст — f1(), если argc > 1 */
uctx_func2.uc_link = (argc > 1) ? NULL : &uctx_func1;
makecontext(&uctx_func2, func2, 0);
printf("main: swapcontext(&uctx_main, &uctx_func2)\n");
if (swapcontext(&uctx_main, &uctx_func2) == -1)
handle_error("swapcontext");
printf("main: выход\n");
exit(EXIT_SUCCESS); }
⇧ Top