[haiku-development] Re: _kern_reserve_address_range

  • From: Tim Kelly <gtkelly@xxxxxxxxxxxxxxxxx>
  • To: haiku-development@xxxxxxxxxxxxx
  • Date: Wed, 16 Mar 2016 15:03:46 -0400

Ok, as Adrien suggested, the problem appears to occur when two child processes of a parent process request the same exact address (displaying relevant parts of strace -t):

[ 1044] _kern_normalize_path("/boot/system/non-packaged/lib/cpp", true, 0x72fee2f8) = 0x00000000 No error (21 us)
[  1044] _kern_read(0x4, 0x0, 0x72fed2c4, 0x34) = 0x00000034 (4 us)
[  1044] _kern_read(0x4, 0x34, 0x72fed2f8, 0xa0) = 0x000000a0 (2 us)
[ 1044] _kern_reserve_address_range([0x200000], 0x1, 0x2e000) = 0x00000000 No error (2 us)

...

[ 1046] _kern_normalize_path("/boot/system/non-packaged/lib/ccom", true, 0x72ad6238) = 0x00000000 No error (21 us)
[  1046] _kern_read(0x4, 0x0, 0x72ad5204, 0x34) = 0x00000034 (4 us)
[  1046] _kern_read(0x4, 0x34, 0x72ad5238, 0xa0) = 0x000000a0 (3 us)
[ 1046] _kern_reserve_address_range([0x200000], 0x1, 0x67000) = 0x80000005 Invalid Argument (2 us)
[ 1046] _kern_debug_output("runtime_loader: /boot/system/non-packaged/lib/ccom: Could not map image: Out of memory
") (301 us)
[  1046] _kern_write(0x2, 0x0, 0x72ad4da8, 0x57) = 0x00000057 (11 us)
[  1046] _kern_close(0x4) = 0x00000000 No error (3 us)
[  1046] _kern_loading_app_failed(0xffffffff) (3 us)

Digging really deep into how strace could be returning B_BAD_VALUE (INT_MIN + 5)

from _[kernel|user]_reserve_address_range (calling parameters omitted for clarity):

system/kernel/vm/vm.cpp

status_t
_user_reserve_address_range()
{
 -->  status_t status = vm_reserve_address_range(
VMAddressSpace::CurrentID(), (void**)&address, addressSpec, size, RESERVED_AVOID_BASE);
        if (status != B_OK)
                return status;
...
}

status_t
vm_reserve_address_range(team_id team, void** _address, uint32 addressSpec, addr_t size, uint32 flags)
{
...
--> return addressSpace->ReserveAddressRange()
...
}


system/kernel/vm/VMUserAddressSpace.cpp

status_t
VMUserAddressSpace::ReserveAddressRange()
{
...
-->  status_t status = InsertArea(area, size, addressRestrictions,
                allocationFlags, _address);
        if (status != B_OK) {
                area->~VMUserArea();
                free_etc(area, allocationFlags);
                return status;
        }
}


status_t
VMUserAddressSpace::InsertArea()
{
...
-->         status = _InsertAreaSlot(searchBase, size, searchEnd,
                addressRestrictions->address_specification,
                addressRestrictions->alignment, area, allocationFlags);
        if (status == B_OK) {
                if (_address != NULL)
                   *_address = (void*)area->Base();
                   fFreeSpace -= area->Size();
        }

        return status;
}

status_t
VMUserAddressSpace::_InsertAreaSlot()
{
...
 if (addressSpec == B_EXACT_ADDRESS && area->id != RESERVED_AREA_ID) {
 // search for a reserved area
 status_t status = _InsertAreaIntoReservedRegion(start, size, area,
                      allocationFlags);
      if (status == B_OK || status == B_BAD_VALUE)
            return status;

...

       case B_EXACT_ADDRESS:
       // see if we can create it exactly here
       if ((last == NULL || last->Base() + (last->Size() - 1) < start)
           && (next == NULL || next->Base() > start + (size - 1))) {
                 foundSpot = true;
                 area->SetBase(start);
                 break;
            }
            break;
        default:
            return B_BAD_VALUE;
        }

   if (!foundSpot)
      return addressSpec == B_EXACT_ADDRESS ? B_BAD_VALUE : B_NO_MEMORY;
...
}

status_t
VMUserAddressSpace::_InsertAreaIntoReservedRegion()
{
VMUserArea* next;
...
for (VMUserAreaList::Iterator it = fAreas.GetIterator();
                        (next = it.Next()) != NULL;) {
if (next->Base() <= start && next->Base() + (next->Size() - 1) >= start + (size - 1)) {
        // This area covers the requested range
        if (next->id != RESERVED_AREA_ID) {
        // but it's not reserved space, it's a real area
               return B_BAD_VALUE;
...
}

Basically, there are two different places B_BAD_VALUE could be returned (which strace looks up as EINVAL and returns a conflicting message to the Out of Memory/B_NO_MEMORY message runtime_loader returns).

The problem, though, is that the other child process that had requested that area is supposed to have exited:

[ 1042] _kern_wait_for_child(0x414, 0x0, 0x72bb81f8) = 0x00000414 (126849 us)
[  1042] --- Child exited (Child exited) ---
[ 1042] _kern_read_stat(0xffffffff, "/tmp", true, 0x72bb81d8, 0x58) = 0x00000000 No error (13 us)
[ 1042] _kern_open(0xffffffff, "/tmp/ctm.9QlBqW", 0x302, 0x180) = 0x00000004 (177 us)
[  1042] _kern_close(0x4) = 0x00000000 No error (4 us)
[ 1042] _kern_access(0xffffffff, "/system/non-packaged/lib/ccom", 0x1, false) = 0x00000000 No error (12 us)
[  1046] _kern_area_for(0x18372000) = 0x0000ca88 (0 us)
[  1042] _kern_fork() = 0x00000416 (840 us)


Sometimes, though, the above code works perfectly fine and no errors are encountered. Is this a timing issue, in that sometimes the address space has been cleared and sometimes it has not?

tim

Other related posts: