[haiku-bugs] Re: [Haiku] #12438: Implement brk and sbrk

  • From: "korli" <trac@xxxxxxxxxxxx>
  • Date: Sun, 17 Jul 2016 13:20:28 -0000

#12438: Implement brk and sbrk
----------------------------+----------------------------
   Reporter:  simonsouth    |      Owner:  nobody
       Type:  enhancement   |     Status:  closed
   Priority:  normal        |  Milestone:  Unscheduled
  Component:  System/POSIX  |    Version:  R1/Development
 Resolution:  fixed         |   Keywords:
 Blocked By:                |   Blocking:
Has a Patch:  0             |   Platform:  All
----------------------------+----------------------------

Comment (by korli):

 I'm proposing this patch for review. Feedback welcome.


 To help the actual sbrk() implementation, we try to free the space after
 the program segments. For this to happen:
 * the runtime_loader now loads the program first segment with its own
 segment as a base address: this avoids the situation when the program is
 loaded at a location before the runtime loader.
 * the runtime loader now loads dependencies at a farer location (1GB on 32
 bits), this avoids having libroot.so loaded near the program.
 * the heap area isn't created on init any more: sbrk is first used to
 provide the first allocations (until 64 pages), then only the heap area is
 created: this avoids having an heap area to be created when the program
 doesn't actually use malloc() (libgcc, libroot might still do though).
 * tested on x86 and x86_64, sbrk() allocated 640M successfully.



 {{{
 diff --git a/src/system/libroot/posix/malloc/arch-specific.cpp
 b/src/system/libroot/posix/malloc/arch-specific.cpp
 index 4167f04..2831213 100644
 --- a/src/system/libroot/posix/malloc/arch-specific.cpp
 +++ b/src/system/libroot/posix/malloc/arch-specific.cpp
 @@ -65,6 +65,7 @@ static void *sHeapBase;
  static addr_t sFreeHeapBase;
  static size_t sFreeHeapSize, sHeapAreaSize;
  static free_chunk *sFreeChunks;
 +static size_t sSbrkFreeSize;


  static void
 @@ -72,7 +73,7 @@ init_after_fork(void)
  {
         // find the heap area
         sHeapArea = area_for((void*)sFreeHeapBase);
 -       if (sHeapArea < 0) {
 +       if (sHeapArea < 0 && sSbrkFreeSize == 0) {
                 // Where is it gone?
                 debug_printf("hoard: init_after_fork(): thread %" B_PRId32
 ", Heap "
                         "area not found! Base address: %p\n",
 find_thread(NULL),
 @@ -96,17 +97,10 @@ __init_heap(void)
         if (status != B_OK)
                 sHeapBase = NULL;

 -       uint32 protection = B_READ_AREA | B_WRITE_AREA;
 -       if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU)
 -               protection |= B_EXECUTE_AREA;
 -       sHeapArea = create_area("heap", (void **)&sHeapBase,
 -               status == B_OK ? B_EXACT_ADDRESS :
 B_RANDOMIZED_BASE_ADDRESS,
 -               kInitialHeapSize, B_NO_LOCK, protection);
 -       if (sHeapArea < B_OK)
 -               return sHeapArea;
 -
 -       sFreeHeapBase = (addr_t)sHeapBase;
 -       sHeapAreaSize = kInitialHeapSize;
 +       sSbrkFreeSize = 64 * B_PAGE_SIZE;
 +       sHeapArea = B_NO_INIT;
 +       sFreeHeapBase = 0;
 +       sHeapAreaSize = 0;

         hoardLockInit(sHeapLock, "heap");

 @@ -157,6 +151,16 @@ hoardSbrk(long size)
         assert(size > 0);
         CTRACE(("sbrk: size = %ld\n", size));

 +       if (sSbrkFreeSize > 0 && size > 0) {
 +               if ((size_t)size < sSbrkFreeSize) {
 +                       sSbrkFreeSize -= min_c((size_t)size,
 sSbrkFreeSize);
 +                       void* ptr = sbrk(size);
 +                       if (ptr != (void*)-1)
 +                               return ptr;
 +               }
 +               sSbrkFreeSize = 0;
 +       }
 +
         // align size request
         size = (size + hoardHeap::ALIGNMENT - 1) & ~(hoardHeap::ALIGNMENT
 - 1);

 @@ -167,6 +171,19 @@ hoardSbrk(long size)

         hoardLock(sHeapLock);

 +       if (sFreeHeapBase == 0) {
 +               sHeapArea = create_area("heap", (void **)&sHeapBase,
 +                       sHeapBase != NULL ? B_EXACT_ADDRESS :
 B_RANDOMIZED_BASE_ADDRESS,
 +                       kInitialHeapSize, B_NO_LOCK, protection);
 +               if (sHeapArea < B_OK) {
 +                       hoardUnlock(sHeapLock);
 +                       return NULL;
 +               }
 +
 +               sFreeHeapBase = (addr_t)sHeapBase;
 +               sHeapAreaSize = kInitialHeapSize;
 +       }
 +
         // find chunk in free list
         free_chunk *chunk = sFreeChunks, *last = NULL;
         for (; chunk != NULL; chunk = chunk->next) {
 diff --git a/src/system/runtime_loader/elf_load_image.cpp
 b/src/system/runtime_loader/elf_load_image.cpp
 index c6bcbbf..3f67675 100644
 --- a/src/system/runtime_loader/elf_load_image.cpp
 +++ b/src/system/runtime_loader/elf_load_image.cpp
 @@ -527,7 +527,8 @@ load_image(char const* name, image_type type, const
 char* rpath,
                 goto err2;
         }

 -       status = map_image(fd, path, image, eheader.e_type == ET_EXEC);
 +       status = map_image(fd, path, image, eheader.e_type == ET_EXEC,
 +               type == B_APP_IMAGE);
         if (status < B_OK) {
                 FATAL("%s: Could not map image: %s\n", image->path,
 strerror(status));
                 status = B_ERROR;
 diff --git a/src/system/runtime_loader/images.cpp
 b/src/system/runtime_loader/images.cpp
 index f2678a3..a291ffd 100644
 --- a/src/system/runtime_loader/images.cpp
 +++ b/src/system/runtime_loader/images.cpp
 @@ -33,9 +33,11 @@
         // page segment alignment.
  #      define RLD_PROGRAM_BASE 0x600000
  #      define MAX_PAGE_SIZE    0x200000
 +#      define RLD_NON_PROGRAM_BASE     0x100000000
  #else
  #      define RLD_PROGRAM_BASE 0x200000
  #      define MAX_PAGE_SIZE    B_PAGE_SIZE
 +#      define RLD_NON_PROGRAM_BASE     0x40000000
  #endif


 @@ -170,13 +172,20 @@ topological_sort(image_t* image, uint32 slot,
 image_t** initList,
  */
  static void
  get_image_region_load_address(image_t* image, uint32 index, long
 lastDelta,
 -       bool fixed, addr_t& loadAddress, uint32& addressSpecifier)
 +       bool fixed, bool executable, addr_t& loadAddress, uint32&
 addressSpecifier)
  {
         if (!fixed) {
                 // relocatable image... we can afford to place wherever
                 if (index == 0) {
                         // but only the first segment gets a free ride
 -                       loadAddress = RLD_PROGRAM_BASE;
 +                       if (!executable)
 +                               // push libs farer in the address space
 +                               loadAddress = RLD_NON_PROGRAM_BASE;
 +                       else {
 +                               // check the provided address against the
 program base
 +                               if (loadAddress < RLD_PROGRAM_BASE)
 +                                       loadAddress = RLD_PROGRAM_BASE;
 +                       }
                         addressSpecifier = B_RANDOMIZED_BASE_ADDRESS;
                 } else {
                         loadAddress = image->regions[index].vmstart +
 lastDelta;
 @@ -287,7 +296,7 @@ put_image(image_t* image)


  status_t
 -map_image(int fd, char const* path, image_t* image, bool fixed)
 +map_image(int fd, char const* path, image_t* image, bool fixed, bool
 executable)
  {
         // cut the file name from the path as base name for the created
 areas
         const char* baseName = strrchr(path, '/');
 @@ -304,6 +313,14 @@ map_image(int fd, char const* path, image_t* image,
 bool fixed)
         size_t length = 0;
         uint32 addressSpecifier = B_RANDOMIZED_ANY_ADDRESS;

 +       // find out our end of segment to be used as a base
 +       area_id ourArea = _kern_area_for((void*)map_image);
 +       if (ourArea > B_OK) {
 +               area_info ourAreaInfo;
 +               if (_kern_get_area_info(ourArea, &ourAreaInfo) == B_OK)
 +                       loadAddress = (addr_t)ourAreaInfo.address +
 ourAreaInfo.size;
 +       }
 +
         for (uint32 i = 0; i < image->num_regions; i++) {
                 // for BeOS compatibility: if we load an old BeOS
 executable, we
                 // have to relocate it, if possible - we recognize it
 because the
 @@ -314,7 +331,7 @@ map_image(int fd, char const* path, image_t* image,
 bool fixed)
                 uint32 regionAddressSpecifier;
                 get_image_region_load_address(image, i,
                         i > 0 ? loadAddress - image->regions[i -
 1].vmstart : 0,
 -                       fixed, loadAddress, regionAddressSpecifier);
 +                       fixed, executable, loadAddress,
 regionAddressSpecifier);
                 if (i == 0) {
                         reservedAddress = loadAddress;
                         addressSpecifier = regionAddressSpecifier;
 @@ -346,8 +363,8 @@ map_image(int fd, char const* path, image_t* image,
 bool fixed)
                         baseName, i, (image->regions[i].flags & RFLAG_RW)
 ? "rw" : "ro");

                 get_image_region_load_address(image, i,
 -                       i > 0 ? image->regions[i - 1].delta : 0, fixed,
 loadAddress,
 -                       addressSpecifier);
 +                       i > 0 ? image->regions[i - 1].delta : 0, fixed,
 executable,
 +                       loadAddress, addressSpecifier);

                 // If the image position is arbitrary, we must let it
 point to the start
                 // of the reserved address range.
 diff --git a/src/system/runtime_loader/images.h
 b/src/system/runtime_loader/images.h
 index a929040..fa47f0c 100644
 --- a/src/system/runtime_loader/images.h
 +++ b/src/system/runtime_loader/images.h
 @@ -50,7 +50,8 @@ void          delete_image_struct(image_t* image);
  void           delete_image(image_t* image);
  void           put_image(image_t* image);

 -status_t       map_image(int fd, char const* path, image_t* image, bool
 fixed);
 +status_t       map_image(int fd, char const* path, image_t* image, bool
 fixed,
 +                               bool executable);
  void           unmap_image(image_t* image);
  void           remap_images();
 }}}

--
Ticket URL: <https://dev.haiku-os.org/ticket/12438#comment:12>
Haiku <https://dev.haiku-os.org>
Haiku - the operating system.

Other related posts: