# New Ticket Created by Jeff Clites # Please include the string: [perl #31966] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org:80/rt3/Ticket/Display.html?id=31966 >
This patch implements Parrot_memalign for Mac OS X (to allow
ARENA_DOD_FLAGS usage). It's a patch, plus a new file
(config/gen/platform/darwin/memalign.c).
Notes:
1) In src/interpreter.c, there was a note about
Parrot_memalign_if_possible on OpenBSD having the wrong behavior. I
believe that may have been due to a bad #define in
config/gen/platform/platform_interface.h, which this patch fixes. It
would be good to see if OpenBSD behaves correctly now, after the patch
is applied.
2) You need to enable ARENA_DOD_FLAGS in include/parrot/settings.h for
the patch to make much of a difference. (At one point it defaulted to
"on" if you had memalign, but that appears not to be the case
currently.)
config/gen/platform/darwin/memalign.c:
/*
* memalign related stuff
*/
#include <mach/vm_map.h>
#include <mach/mach_init.h>
static unsigned log2int(unsigned x) { return (x<2) ? 0 : log2int (x>>1)+1; };
static unsigned roundDownPowerOf2(unsigned x) { return (1 << log2int(x)); };
static unsigned roundUpPowerOf2(unsigned x)
{
static unsigned one = 1;
unsigned log2Int = log2int(x);
return ((one << log2Int) == x) ? x : (one << (log2Int + 1));
};
static unsigned roundUpToPageBoundary(unsigned x)
{
unsigned roundedDown = trunc_page(x);
return (roundedDown == x) ? x : (roundedDown + vm_page_size);
};
typedef struct _memalign_marker_t {
vm_address_t start;
vm_size_t size; } memalign_marker_t;
void *
Parrot_memalign(size_t align, size_t size)
{
size_t effectiveAlign = align;
size_t padding = 0;
size_t amountToAllocate = 0;
if( effectiveAlign < sizeof(void *) )
{
effectiveAlign = roundUpPowerOf2(sizeof(void *));
}
else
{
effectiveAlign = roundUpPowerOf2(effectiveAlign);
}
if( effectiveAlign < sizeof(memalign_marker_t) )
{
padding = sizeof(memalign_marker_t);
}
else
{
padding = effectiveAlign;
}
amountToAllocate = roundUpToPageBoundary(size + padding);
{
vm_address_t p = NULL;
kern_return_t status = vm_allocate(mach_task_self(), &p,
amountToAllocate, 1);
if( status != KERN_SUCCESS )
{
return NULL;
}
else
{
vm_size_t logEffectiveAlign = log2int(effectiveAlign);
vm_address_t lowestAvaliableAddress =
p + sizeof(memalign_marker_t);
vm_address_t roundedDownAddress =
((lowestAvaliableAddress >> logEffectiveAlign)
<< logEffectiveAlign);
vm_address_t returnAddress =
(roundedDownAddress == lowestAvaliableAddress) ?
lowestAvaliableAddress :
(roundedDownAddress + effectiveAlign);
vm_address_t firstUnneededPage = 0;
memalign_marker_t *marker =
(memalign_marker_t *)returnAddress - 1;
/* lowest address used, then round down to vm_page boundary */
vm_address_t usedPageBase = trunc_page((vm_address_t)marker);
marker->start = usedPageBase;
marker->size = returnAddress + size - usedPageBase;
if( usedPageBase > p )
{
status = vm_deallocate(mach_task_self(), p, usedPageBase - p);
if( status != KERN_SUCCESS )
{
fprintf(stderr, "Parrot_memalign(%zx, %zx) failed to deallocate
extra header space.\n", align, size);
}
}
firstUnneededPage = roundUpToPageBoundary(returnAddress + size);
if( firstUnneededPage < p + amountToAllocate )
{
status = vm_deallocate(mach_task_self(), firstUnneededPage,
p + amountToAllocate - firstUnneededPage);
if( status != KERN_SUCCESS )
{
fprintf(stderr, "Parrot_memalign(%zx, %zx) failed to deallocate
extra footer space.\n", align, size);
}
}
return (void *)returnAddress;
}
}
}
void
Parrot_free_memalign(void *p)
{
memalign_marker_t *marker = (memalign_marker_t *)p - 1;
kern_return_t status = vm_deallocate(mach_task_self(),
marker->start, marker->size);
if( status != KERN_SUCCESS )
{
fprintf(stderr, "Parrot_free_memalign(%p) failed!\n", p);
}
}
patch:
memalign.patch
Description: application/text
JEff
