makecontext(3)

๐Ÿ’– makecontext(3) โ€” manipulate user context ๐Ÿ’–

okay so bestie, we're in the Library Functions Manual today and the star of the show is literally makecontext, with swapcontext riding shotgun. it's giving system-level thread-of-control chaos and honestly? obsessed. ๐Ÿฆ‹


โœจ NAME โœจ

makecontext, swapcontext โ€” manipulate user context

๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library (libc, -lc) ๐ŸŽ€

๐ŸŒธ SYNOPSIS ๐ŸŒธ

#include <ucontext.h>

void makecontext(ucontext_t *ucp, typeof(void (int arg0, ...)) *func,
                 int argc, ...);
int swapcontext(ucontext_t *restrict oucp,
                 const ucontext_t *restrict ucp);

๐Ÿซถ DESCRIPTION ๐Ÿซถ

So in a System V-like environment, you get this type called ucontext_t โ€” it lives in <ucontext.h> and it's fully described over in getcontext(3), go read that bestie โ€” plus four functions: getcontext(3), setcontext(3), makecontext(), and swapcontext(). Together they let you do user-level context switching between multiple threads of control inside one process. no kernel threads required, we're doing this ourselves ๐Ÿ’…

makecontext() modifies the context that ucp points to (and you gotta get that ucp from a call to getcontext(3) first, that's the whole vibe). Before you invoke makecontext(), the caller must:

  • allocate a new stack for this context and assign its address to ucp->uc_stack, and
  • define a successor context and assign its address to ucp->uc_link.

Then, when this context gets activated later (via setcontext(3) or swapcontext()), the function func is called and it's passed that whole series of integer (int) arguments that come after argc. You, the caller, have to say how many of those arguments there are in argc. โœจ

And when func returns? The successor context gets activated. If that successor context pointer is NULL, the thread exits. that's it, that's the end, no cap ๐Ÿ˜ญ

swapcontext() saves the current context into the struct that oucp points to, and then activates the context that ucp points to. swap-and-go, iconic behaviour honestly ๐Ÿ‘‘

๐ŸŽฏ RETURN VALUE ๐ŸŽฏ

When it works, swapcontext() does not return. (But bestie, we may absolutely return later โ€” if oucp gets activated, it looks like swapcontext() returned 0. surprise! ๐Ÿ™ˆ)

On error, swapcontext() returns -1 and sets errno to indicate the error.

๐Ÿ’€ ERRORS ๐Ÿ’€

  • ENOMEM โ€” Insufficient stack space left. the stack said no more, we're out ๐Ÿ“

๐Ÿ”ฅ ATTRIBUTES ๐Ÿ”ฅ

For an explanation of the terms used in this section, see attributes(7). (yes it's a whole glossary, go look ๐Ÿงš)

  • makecontext() โ€” Thread safety: MT-Safe race:ucp
  • swapcontext() โ€” Thread safety: MT-Safe race:oucp race:ucp
note the race: bits bestie โ€” those are the parameters where race conditions are expected/possible. not me casually pointing that out ๐Ÿซฃ

๐Ÿ‘‘ STANDARDS ๐Ÿ‘‘

None. ๐Ÿ’€ literally none, it's giving outlaw behaviour.

๐ŸŒˆ HISTORY ๐ŸŒˆ

  • glibc 2.1
  • SUSv2
  • POSIX.1-2001
  • Removed in POSIX.1-2008, citing portability issues, and recommending that applications be rewritten to use POSIX threads instead.

so yeah, they dropped it and told everybody to go use pthreads instead. rip bozo, but respectfully ๐Ÿ˜ญ

๐Ÿ’… NOTES ๐Ÿ’…

The interpretation of ucp->uc_stack is exactly the same as in sigaltstack(2) โ€” namely, this struct contains the start and length of a memory area to be used as the stack, regardless of the direction of growth of the stack. So your program does not have to worry about that direction at all. one less thing, slay โœจ

Now here's the spicy one. On architectures where int and pointer types are the same size (e.g., x86-32, where both types are 32 bits), you may be able to get away with passing pointers as arguments to makecontext() following argc.

However, doing this:

  • is not guaranteed to be portable,
  • is undefined according to the standards, and
  • won't work on architectures where pointers are larger than ints.

Nevertheless, starting with glibc 2.8, glibc makes some changes to makecontext(), to permit this on some 64-bit architectures (e.g., x86-64). so like... it might work. don't count on it though fr fr ๐Ÿ™

๐ŸŒŸ EXAMPLES ๐ŸŒŸ

The example program below demonstrates the use of getcontext(3), makecontext(), and swapcontext(). Running the program produces the following output:

    $ ./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

look at that bounce between func2 and func1, it's giving ping pong but make it context switching ๐Ÿ“๐Ÿ˜ญ

๐ŸŽ€ Program source ๐ŸŽ€

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>

static ucontext_t uctx_main, uctx_func1, uctx_func2;

static void
func1(void)
{
    printf("%s: started\n", __func__);
    printf("%s: swapcontext(&uctx_func1, &uctx_func2)\n", __func__);
    if (swapcontext(&uctx_func1, &uctx_func2) == -1)
        err(EXIT_FAILURE, "swapcontext");
    printf("%s: returning\n", __func__);
}

static void
func2(void)
{
    printf("%s: started\n", __func__);
    printf("%s: swapcontext(&uctx_func2, &uctx_func1)\n", __func__);
    if (swapcontext(&uctx_func2, &uctx_func1) == -1)
        err(EXIT_FAILURE, "swapcontext");
    printf("%s: returning\n", __func__);
}

int
main(int argc, char *argv[])
{
    char func1_stack[16384];
    char func2_stack[16384];

    if (getcontext(&uctx_func1) == -1)
        err(EXIT_FAILURE, "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)
        err(EXIT_FAILURE, "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("%s: swapcontext(&uctx_main, &uctx_func2)\n", __func__);
    if (swapcontext(&uctx_main, &uctx_func2) == -1)
        err(EXIT_FAILURE, "swapcontext");

    printf("%s: exiting\n", __func__);
    exit(EXIT_SUCCESS);
}
those char func1_stack[16384]; and char func2_stack[16384]; are the stacks bestie โ€” you HAVE to allocate them yourself before makecontext(), that's literally the rule we talked about above ๐Ÿ’–

๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

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


and that's the whole page bestie, you ate it, no crumbs left ๐Ÿซถ

Linux man-pages 6.20 โ€” dated 2026-02-08 ๐Ÿ’– mwah, go write some contexts, you got this ๐Ÿ‘‘โœจ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms