MAKECONTEXT - Linux手册页

时间:2019-08-20 18:00:50  来源:igfitidea点击:

Linux程序员手册 第3部分
更新日期: 2020-06-09

名称

makecontext,swapcontext-操作用户上下文

语法

#包括

void makecontext(ucontext_t * ucp,void(* func)(),int argc,...);

int swapcontext(ucontext_t * oucp,const ucontext_t * ucp);

说明

在类似于System V的环境中,一个具有ucontext_t类型定义,并且具有四个函数getcontext(3),setcontext(3),makecontext()和swapcontext(),这些功能允许用户级上下文在一个控件中的多个控制线程之间切换处理。

有关类型和前两个函数,请参见getcontext(3)。

makecontext()函数修改ucp指向的上下文(该上下文是从对getcontext(3)的调用中获得的)。在调用makecontext()之前,调用者必须为此上下文分配一个新的堆栈,并将其地址分配给ucp-> uc_stack,并定义一个后继上下文并将其地址分配给ucp-> uc_link。

稍后(使用setcontext(3)或swapcontext())激活此上下文时,将调用函数func,并传递argc之后的一系列整数(int)参数;调用者必须在argc中指定这些参数的数量。当该函数返回时,后继上下文被激活。如果后继上下文指针为NULL,则线程退出。

swapcontext()函数将当前上下文保存在oucp指向的结构中,然后激活ucp指向的上下文。

返回值

成功时,swapcontext()不返回。 (但是,如果激活了oucp,我们可能稍后再返回,在这种情况下,它看起来像swapcontext()返回0。)错误时,swapcontext()返回-1并适当地设置errno。

错误说明

ENOMEM
剩余的堆栈空间不足。

版本

从版本2.1开始,在glibc中提供了makecontext()和swapcontext()。

属性

有关本节中使用的术语的说明,请参见attribute(7)。

InterfaceAttributeValue
makecontext()Thread safetyMT-Safe race:ucp
swapcontext()Thread safetyMT-Safe race:oucp race:ucp

遵循规范

SUSv2,POSIX.1-2001。 POSIX.1-2008删除了makecontext()和swapcontext()的规范,理由是可移植性问题,并建议重写应用程序以使用POSIX线程。

备注

ucp-> uc_stack的解释与sigaltstack(2)中的解释相同,即,此结构包含用作堆栈的存储区域的起始位置和长度,而与堆栈的增长方向无关。因此,用户程序不必担心该方向。

在int和指针类型具有相同大小的体系结构上(例如x86-32,两种类型均为32位),您可以通过将指针作为参数传递给argc之后的makecontext()来实现。但是,这样做不能保证是可移植的,根据标准是未定义的,并且不能在指针大于int的体系结构上使用。不过,从2.8版开始,glibc对m​​akecontext()进行了一些更改,以允许在某些64位体系结构(例如x86-64)上进行此更改。

示例

下面的示例程序演示了getcontext(3),makecontext()和swapcontext()的用法。运行程序将产生以下输出:

$ ./a.out
main: swapcontext(&uctx_main, &uctx_func2)
func2: started
func2: swapcontext(&uctx_func2, &uctx_func1)
func1: started
func1: swapcontext(&uctx_func1, &uctx_func2)
func2: returning
func1: returning
main: exiting

Program source

#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: started\n");
    printf("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
    if (swapcontext(&uctx_func1, &uctx_func2) == -1)
        handle_error("swapcontext");
    printf("func1: returning\n");
}

static void
func2(void)
{
    printf("func2: started\n");
    printf("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
    if (swapcontext(&uctx_func2, &uctx_func1) == -1)
        handle_error("swapcontext");
    printf("func2: returning\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);
    /* Successor context is f1(), unless 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: exiting\n");
    exit(EXIT_SUCCESS);
}

另外参见

sigaction(2),sigaltstack(2),sigprocmask(2),getcontext(3),sigsetjmp(3)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/