Создание и использование нового стека в памяти - PullRequest
1 голос
/ 31 августа 2011

По некоторым особым причинам (пожалуйста, не спрашивайте меня, почему), для некоторых функций я хочу использовать отдельный стек. Например, скажем, я хочу, чтобы функция malloc использовала другой стек для своей обработки, мне нужно переключиться на вновь созданный стек, прежде чем он будет вызван, и вернуться к исходному стеку, используемому программой, после ее завершения. Таким образом, алгоритм будет выглядеть примерно так:

switch_to_new_stack
call malloc
swith back to the original stack

Какой самый простой и эффективный способ сделать это? Есть идеи?

Ответы [ 2 ]

3 голосов
/ 31 августа 2011

Возможно, это не соответствует вашему определению, простому или эффективному, но одним из способов может быть следующее:

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

#include <ucontext.h>

/* utility functions */
static void getctx(ucontext_t* ucp)
{
    if (getcontext(ucp) == -1) {
        perror("getcontext");
        exit(EXIT_FAILURE);
    }
}

static void print_sp()
{
#if defined(__x86_64)
    unsigned long long x; asm ("mov %%rsp, %0" : "=m" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__i386)
    unsigned long x; asm ("mov %%esp, %0" : "=m" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__powerpc__) && defined(__PPC64__)
    unsigned long long x; asm ("addi %0, 1, 0" : "=r" (x));
    printf("sp: %p\n",(void*)x);
#elif defined(__powerpc__)
    unsigned long x; asm ("addi %0, 1, 0" : "=r" (x));
    printf("sp: %p\n",(void*)x);
#else
    printf("unknown architecture\n");
#endif
}


/* stack for 'my_alloc', size arbitrarily chosen */
static int malloc_stack[1024];
static ucontext_t malloc_context; /* context malloc will run in */
static ucontext_t current_context; /* context to return to */

static void my_malloc(size_t sz)
{
    printf("in my_malloc(%zu) ", sz);
    print_sp();
}

void call_my_malloc(size_t sz)
{
    /* prepare context for malloc */
    getctx(&malloc_context);
    malloc_context.uc_stack.ss_sp = malloc_stack;
    malloc_context.uc_stack.ss_size = sizeof(malloc_stack);
    malloc_context.uc_link = &current_context;
    makecontext(&malloc_context, (void(*)())my_malloc, 1, sz);

    if (swapcontext(&current_context, &malloc_context) == -1) {
        perror("swapcontext");
        exit(EXIT_FAILURE);
    }
}

int main()
{
    printf("malloc_stack = %p\n", (void*)malloc_stack);
    printf("in main ");
    print_sp();
    call_my_malloc(42);
    printf("in main ");
    print_sp();
    return 0;
}

Это должно работать на всех платформах, где поддерживается makecontext(3). Цитата из справочной страницы (где я также получил вдохновение для примера кода):

Интерпретация ucp-> uc_stack такая же, как в sigaltstack (2), а именно, эта структура содержит начало и длину области памяти, которая будет использоваться в качестве стека, независимо от направления роста стека. Таким образом, пользовательская программа не должна беспокоиться об этом направлении.

Пример вывода из PPC64:

$ gcc -o stack stack.c -Wall -Wextra -W -ggdb -std=gnu99 -pedantic -Werror -m64 && ./stack
malloc_stack = 0x10010fe0
in main sp: 0xfffffe44420
in my_malloc(42) sp: 0x10011e20
in main sp: 0xfffffe44420
1 голос
/ 01 сентября 2011

GCC поддерживает разделенные стеки, которые работают немного как вы описали.

http://gcc.gnu.org/wiki/SplitStacks

Цель проекта другая, но реализация сделает то, что вы просите.

Цель разделения стеков состоит в том, чтобы создать непрерывный стек, который автоматически увеличивается по мере необходимости. Это означает, что вы можете запускать несколько потоков, каждый из которых начинается с небольшого стека, и увеличивать и уменьшать его в соответствии с требованиями программы. Тогда больше не нужно думать о требованиях к стеку при написании многопоточной программы. Использование памяти типичной многопоточной программы может значительно уменьшиться, поскольку для каждого потока не требуется размер стека в худшем случае. Становится возможным запускать миллионы потоков (либо полных потоков NPTL, либо сопрограмм) в 32-разрядном адресном пространстве.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...