1

I am trying to call getcontext into another function (instead of calling it directly into main) in order to copy the thread's stack and restore it later. This code should print repeatedly, but it won't work once the function that called getcontext returns.

Is there a way to circumvent this limitation and call getcontext in another function (other than inline macros)?

#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>

ucontext_t context;

void set_context() {
    setcontext(&context);
}

void get_context() {
    getcontext(&context);
}

int main() {
    get_context();
    puts("Hello world");
    sleep(1);
    set_context();
    return 0;
}
TheLinuxGK
  • 113
  • 3

1 Answers1

4

getcontext saves only the machine register state at the point of the call. It does not store the content of stack memory at that position. When you call setcontext then it does jump executing the code from get_context but the very next instruction then pops the return address of the set_context call:

#include <stdio.h>
#include <ucontext.h>
#include <unistd.h>

ucontext_t context;

void set_context() {
    puts("Calling setcontext");
    setcontext(&context);
    puts("Returned from setcontext");
}

void get_context() {
    puts("Calling getcontext");
    getcontext(&context);
    puts("Returned from getcontext");
}

int main() {
    get_context();
    puts("Hello world");
    sleep(1);
    set_context();
    return 0;
}

Output:

Calling getcontext
Returned from getcontext
Hello world
Calling setcontext
Returned from getcontext

What you want to do - continuations - could be done this way in principle, but they just wouldn't work in practice... I.e. no, you will never get what you want to do to work with a random C program between these two calls. Furthermore, it was only by accident that your test didn't result in a crash... (both setcontext and getcontext happened in places where the stack top was located at the same address).

  • 2
    This makes sense, given that in general, the stack may be arbitrarily deep when `getcontext()` is called. It is also worth noting that when a context is obtained via `makecontext()`, the caller is required to provide space for a stack, and that when a context is obtained via the third argument of a three-arg signal handler, the handler itself will either be running in its own stack space or on top of the stack of the provided context. – John Bollinger Jan 03 '21 at 18:55