| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| | #define _XOPEN_SOURCE |
| | |
| | #define _XOPEN_SOURCE_EXTENDED 1 |
| | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
| |
|
| | #include <assert.h> |
| | #include <pthread.h> |
| | #include <stddef.h> |
| | #include <stdio.h> |
| | #include <stdlib.h> |
| | #include <ucontext.h> |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | #if defined(__linux__) && !defined(__GLIBC__) |
| | #define MUSL 1 |
| | #endif |
| | #if defined(MUSL) |
| | void callStackSwitchCallbackFromThread(void) { |
| | printf("SKIP\n"); |
| | exit(0); |
| | } |
| | #else |
| |
|
| | |
| | |
| | |
| | #define STACK_SIZE (64ull << 10) |
| |
|
| | static ucontext_t uctx_save, uctx_switch; |
| |
|
| | extern void stackSwitchCallback(void); |
| |
|
| | char *stack2; |
| |
|
| | static void *stackSwitchThread(void *arg) { |
| | |
| | stackSwitchCallback(); |
| |
|
| | |
| |
|
| | char *stack1 = malloc(STACK_SIZE); |
| | if (stack1 == NULL) { |
| | perror("malloc"); |
| | exit(1); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | stack2 = malloc(STACK_SIZE); |
| | if (stack1 == NULL) { |
| | perror("malloc"); |
| | exit(1); |
| | } |
| |
|
| | if (getcontext(&uctx_switch) == -1) { |
| | perror("getcontext"); |
| | exit(1); |
| | } |
| | uctx_switch.uc_stack.ss_sp = stack1; |
| | uctx_switch.uc_stack.ss_size = STACK_SIZE; |
| | uctx_switch.uc_link = &uctx_save; |
| | makecontext(&uctx_switch, stackSwitchCallback, 0); |
| |
|
| | if (swapcontext(&uctx_save, &uctx_switch) == -1) { |
| | perror("swapcontext"); |
| | exit(1); |
| | } |
| |
|
| | if (getcontext(&uctx_switch) == -1) { |
| | perror("getcontext"); |
| | exit(1); |
| | } |
| | uctx_switch.uc_stack.ss_sp = stack2; |
| | uctx_switch.uc_stack.ss_size = STACK_SIZE; |
| | uctx_switch.uc_link = &uctx_save; |
| | makecontext(&uctx_switch, stackSwitchCallback, 0); |
| |
|
| | if (swapcontext(&uctx_save, &uctx_switch) == -1) { |
| | perror("swapcontext"); |
| | exit(1); |
| | } |
| |
|
| | free(stack1); |
| |
|
| | return NULL; |
| | } |
| |
|
| | static void *stackSwitchThread2(void *arg) { |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | char *prev_stack_lo = stack2 + STACK_SIZE - (32*1024); |
| |
|
| | |
| | |
| | |
| | |
| | char *new_stack_hi = prev_stack_lo + 128; |
| |
|
| | if (getcontext(&uctx_switch) == -1) { |
| | perror("getcontext"); |
| | exit(1); |
| | } |
| | uctx_switch.uc_stack.ss_sp = new_stack_hi - (STACK_SIZE / 2); |
| | uctx_switch.uc_stack.ss_size = STACK_SIZE / 2; |
| | uctx_switch.uc_link = &uctx_save; |
| | makecontext(&uctx_switch, stackSwitchCallback, 0); |
| |
|
| | if (swapcontext(&uctx_save, &uctx_switch) == -1) { |
| | perror("swapcontext"); |
| | exit(1); |
| | } |
| |
|
| | free(stack2); |
| |
|
| | return NULL; |
| | } |
| |
|
| | void callStackSwitchCallbackFromThread(void) { |
| | pthread_t thread; |
| | assert(pthread_create(&thread, NULL, stackSwitchThread, NULL) == 0); |
| | assert(pthread_join(thread, NULL) == 0); |
| |
|
| | assert(pthread_create(&thread, NULL, stackSwitchThread2, NULL) == 0); |
| | assert(pthread_join(thread, NULL) == 0); |
| | } |
| |
|
| | #endif |
| |
|