出于某些特殊原因(请不要问我为什么),对于某些功能,我想使用单独的堆栈。例如,假设我希望函数malloc
使用不同的堆栈进行处理,我需要在调用之前切换到我新创建的堆栈,并在完成后返回到程序使用的原始堆栈。所以算法会是这样的。
switch_to_new_stack
call malloc
swith back to the original stack
最简单,最有效的方法是什么?有什么想法吗?
答案 0 :(得分:3)
它可能不符合您对简单或高效的定义,但以下可能是一种方法:
#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 = ¤t_context;
makecontext(&malloc_context, (void(*)())my_malloc, 1, sz);
if (swapcontext(¤t_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-&gt; 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 :(得分:1)
GCC支持分割堆栈,有点像你描述的那样。
http://gcc.gnu.org/wiki/SplitStacks
该项目的目标不同,但实施将按您的要求进行。
拆分堆栈的目标是允许根据需要自动增长的不连续堆栈。这意味着您可以运行多个线程,每个线程从一个小堆栈开始,并根据程序的要求增加和缩小堆栈。在编写多线程程序时,不再需要考虑堆栈要求。典型的多线程程序的内存使用量可能会显着降低,因为每个线程不需要最坏情况的堆栈大小。可以在32位地址空间中运行数百万个线程(完整的NPTL线程或协同例程)。