mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
197aa0d465
This change introduces support for Linux-style uc_context manipulation that's fast and works well on all supported OSes and architectures. It also integrates with the Cosmpolitan runtime which can show backtraces comprised of multiple stacks and fibers. See the test and example code for further details. This will be used by Mold once it's been vendored
79 lines
2.6 KiB
C
79 lines
2.6 KiB
C
#if 0
|
|
/*─────────────────────────────────────────────────────────────────╗
|
|
│ To the extent possible under law, Justine Tunney has waived │
|
|
│ all copyright and related or neighboring rights to this file, │
|
|
│ as it is written in the following disclaimers: │
|
|
│ • http://unlicense.org/ │
|
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
|
╚─────────────────────────────────────────────────────────────────*/
|
|
#endif
|
|
#include "libc/calls/calls.h"
|
|
#include "libc/calls/ucontext.h"
|
|
#include "libc/runtime/runtime.h"
|
|
#include "libc/stdio/stdio.h"
|
|
#include "libc/str/str.h"
|
|
#include "libc/sysv/consts/exit.h"
|
|
|
|
/**
|
|
* @fileoverview swapcontext() and makecontext() example
|
|
* @note adapted from the Linux man-pages project
|
|
*/
|
|
|
|
static ucontext_t uctx_main;
|
|
static ucontext_t uctx_func1;
|
|
static ucontext_t uctx_func2;
|
|
|
|
#define say(s) write(1, s, strlen(s))
|
|
#define handle_error(msg) \
|
|
do { \
|
|
perror(msg); \
|
|
exit(EXIT_FAILURE); \
|
|
} while (0)
|
|
|
|
static void func1(void) {
|
|
say("func1: started\n");
|
|
say("func1: swapcontext(&uctx_func1, &uctx_func2)\n");
|
|
if (swapcontext(&uctx_func1, &uctx_func2) == -1) {
|
|
handle_error("swapcontext");
|
|
}
|
|
say("func1: returning\n");
|
|
}
|
|
|
|
static void func2(void) {
|
|
say("func2: started\n");
|
|
say("func2: swapcontext(&uctx_func2, &uctx_func1)\n");
|
|
if (swapcontext(&uctx_func2, &uctx_func1) == -1) {
|
|
handle_error("swapcontext");
|
|
}
|
|
say("func2: returning\n");
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
char func1_stack[8192];
|
|
char func2_stack[8192];
|
|
|
|
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);
|
|
|
|
say("main: swapcontext(&uctx_main, &uctx_func2)\n");
|
|
if (swapcontext(&uctx_main, &uctx_func2) == -1) {
|
|
handle_error("swapcontext");
|
|
}
|
|
|
|
say("main: exiting\n");
|
|
exit(EXIT_SUCCESS);
|
|
}
|