cygwin下的user heap

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

 

本文适用于

Cygwin checkout-2008-09-28

vs2008

 

欢迎转载,但请保留作者信息

 

cygwin支持所谓的user heap,这个heap将用于malloc / realloc / free操作。当然,malloc操作并不一定要使用这个user heap,经过适当配置也可以直接使用VirtualAlloc这样的API来完成内存分配。但如果希望用cygwin模拟出sbrk的操作,那么只能使用user heap做为malloc操作的heap

1.1    User_heap的描述

Cygwin使用了下面的结构体描述heap信息:

struct user_heap_info

{

  void *base;

  void *ptr;

  void *top;

  void *max;

  unsigned chunk;

  unsigned slop;

};

这几个成员很直观地描述了一个heap所必须的几个信息。这些信息将放在cygheap里面。

 

1.2    user heap初始化

cygwin.dll初始化的时候,它将调用一个叫heap_init的函数:

/* Initialize the heap at process start up.  */

void

heap_init ()

{

     const DWORD alloctype = MEM_RESERVE;

     /* If we're the forkee, we must allocate the heap at exactly the same place

     as our parent.  If not, we don't care where it ends up.  */

 

     page_const = system_info.dwPageSize;

     if (!cygheap->user_heap.base)

     {

         cygheap->user_heap.chunk = cygwin_shared->heap_chunk_size ();

         /* For some obscure reason Vista and 2003 sometimes reserve space after

         calls to CreateProcess overlapping the spot where the heap has been

         allocated.  This apparently spoils cyg_fork.  The behaviour looks quite

         arbitrary.  Experiments on Vista show a memory size of 0x37e000 or

         0x1fd000 overlapping the usual heap by at most 0x1ed000.  So what

         we do here is to allocate the heap with an extra slop of (by default)

         0x200000 and set the appropriate pointers to the start of the heap

         area + slop.  A forking child then creates its heap at the new start

         address and without the slop factor.  Since this is not entirely

         foolproof we add a registry setting "heap_slop_in_mb" so the slop

         factor can be influenced by the user if the need arises. */

         cygheap->user_heap.slop = cygwin_shared->heap_slop_size ();

         while (cygheap->user_heap.chunk >= MINHEAP_SIZE)

         {

              /* Initialize page mask and default heap size.  Preallocate a heap

              * to assure contiguous memory.  */

              cygheap->user_heap.base =

                   VirtualAlloc (NULL, cygheap->user_heap.chunk

                   + cygheap->user_heap.slop,

                   alloctype, PAGE_NOACCESS);

              if (cygheap->user_heap.base)

                   break;

              cygheap->user_heap.chunk -= 1 * 1024 * 1024;

         }

         if (cygheap->user_heap.base == NULL)

              api_fatal ("unable to allocate heap, heap_chunk_size %p, slop %p, %E",

              cygheap->user_heap.chunk, cygheap->user_heap.slop);

         cygheap->user_heap.base = (void *) ((char *) cygheap->user_heap.base

              + cygheap->user_heap.slop);

         cygheap->user_heap.ptr = cygheap->user_heap.top = cygheap->user_heap.base;

         cygheap->user_heap.max = (char *) cygheap->user_heap.base

              + cygheap->user_heap.chunk;

     }

     else

     {

         DWORD chunk = cygheap->user_heap.chunk;   /* allocation chunk */

         /* total size commited in parent */

         DWORD allocsize = (char *) cygheap->user_heap.top -

              (char *) cygheap->user_heap.base;

 

         /* Loop until we've managed to reserve an adequate amount of memory. */

         char *p;

         DWORD reserve_size = chunk * ((allocsize + (chunk - 1)) / chunk);

         while (1)

         {

              p = (char *) VirtualAlloc (cygheap->user_heap.base, reserve_size,

                   alloctype, PAGE_READWRITE);

              if (p)

                   break;

              if ((reserve_size -= page_const) < allocsize)

                   break;

         }

         if (!p && in_forkee && !fork_info->handle_failure (GetLastError ()))

              api_fatal ("couldn't allocate heap, %E, base %p, top %p, "

              "reserve_size %d, allocsize %d, page_const %d",

              cygheap->user_heap.base, cygheap->user_heap.top,

              reserve_size, allocsize, page_const);

         if (p != cygheap->user_heap.base)

              api_fatal ("heap allocated at wrong address %p (mapped) != %p (expected)", p, cygheap->user_heap.base);

         if (allocsize && !VirtualAlloc (cygheap->user_heap.base, allocsize, MEM_COMMIT, PAGE_READWRITE))

              api_fatal ("MEM_COMMIT failed, %E");

     }

 

     debug_printf ("heap base %p, heap top %p", cygheap->user_heap.base,

         cygheap->user_heap.top);

     page_const--;

     // malloc_init ();

}

对于父进程而言,cygheap->user_heap.base的值为NULL,而对于fork出来的子进程,整个cygheap的内容都是从父进程复制而来的,因此这个值将不为NULL,所以父子进程将执行两个不同的分支。

对于父进程,chunk的初始值为0x1800 0000(这是cygwin的保留值,384M),而slop的值则为0Cygwin尝试使用VirtualAlloc分配尽可能大的空间,如果不能满足则以1M为单位向下递减直到满足要求为止,当然,它的大小不能小于MINHEAP_SIZE,即4M

而对于子进程,它将尝试在和父进程相同的地址上分配一块同等大小的空间。

1.3    sbrk

在初始化了user heap之后,就可以正常使用sbrk函数了,其代码如下:

CYG_API void *

sbrk (int n)

{

     char *newtop, *newbrk;

     unsigned commitbytes, newbrksize;

 

     if (n == 0)

         return cygheap->user_heap.ptr;       /* Just wanted to find current cygheap->user_heap.ptr address */

 

     newbrk = (char *) cygheap->user_heap.ptr + n;  /* Where new cygheap->user_heap.ptr will be */

     newtop = (char *) pround (newbrk);        /* Actual top of allocated memory -

                                                   on page boundary */

 

     if (newtop == cygheap->user_heap.top)

         goto good;

 

     if (n < 0)

     {                           /* Freeing memory */

         assert (newtop < cygheap->user_heap.top);

         n = (char *) cygheap->user_heap.top - newtop;

         if (VirtualFree (newtop, n, MEM_DECOMMIT)) /* Give it back to OS */

              goto good;                  /*  Didn't take */

         else

              goto err;

     }

 

     assert (newtop > cygheap->user_heap.top);

 

     /* Find the number of bytes to commit, rounded up to the nearest page. */

     commitbytes = pround (newtop - (char *) cygheap->user_heap.top);

 

     /* Need to grab more pages from the OS.  If this fails it may be because

     we have used up previously reserved memory.  Or, we're just plumb out

     of memory.  Only attempt to commit memory that we know we've previously

     reserved.  */

     if (newtop <= cygheap->user_heap.max)

     {

         if (VirtualAlloc (cygheap->user_heap.top, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)

              goto good;

     }

 

     /* Couldn't allocate memory.  Maybe we can reserve some more.

     Reserve either the maximum of the standard cygwin_shared->heap_chunk_size ()

     or the requested amount.  Then attempt to actually allocate it.  */

     if ((newbrksize = cygheap->user_heap.chunk) < commitbytes)

         newbrksize = commitbytes;

 

     if ((VirtualAlloc (cygheap->user_heap.top, newbrksize, MEM_RESERVE, PAGE_NOACCESS)

         || VirtualAlloc (cygheap->user_heap.top, newbrksize = commitbytes, MEM_RESERVE, PAGE_NOACCESS))

         && VirtualAlloc (cygheap->user_heap.top, commitbytes, MEM_COMMIT, PAGE_READWRITE) != NULL)

     {

         cygheap->user_heap.max = (char *) cygheap->user_heap.max + pround (newbrksize);

         goto good;

     }

 

err:

     set_errno (ENOMEM);

     return (void *) -1;

 

good:

     void *oldbrk = cygheap->user_heap.ptr;

     cygheap->user_heap.ptr = newbrk;

     cygheap->user_heap.top = newtop;

     return oldbrk;

}

这段代码简洁明了,从中可以很清楚地看出user_heap_info中各个成员的作用。

 

 

 

2       参考资料

cygwin下的cygheap:从父进程到子进程的复制(2009-9-7)

cygwin下的/etc/fstab(2009-9-7)

cygwin关键技术:fork(2009-9-4)

cygwin关键技术:设备模拟(2009-9-4)

cygwin关键技术cygheap(2009-9-2)

cygwin关键技术:tls(2009-8-24)

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌云阁主

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值