#include "config.h"
#if defined(HAVE_MMAP)
#include "mmprivate.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <mach/mach.h>
#define HAVE_MSYNC
#if !defined (MAP_ANONYMOUS) && defined (MAP_ANON)
#define MAP_ANONYMOUS MAP_ANON
#endif
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
static size_t pagesize;
#if NEED_DECLARATION_GETPAGESIZE
extern int getpagesize PARAMS ((void));
#endif
#define PAGE_ALIGN(addr) (caddr_t) (((long)(addr) + pagesize - 1) & ~(pagesize - 1))
#define MAP_PRIVATE_OR_SHARED(MDP) ((MDP -> flags & MMALLOC_SHARED) \
? MAP_PRIVATE \
: MAP_SHARED)
PTR
__mmalloc_mmap_morecore (mdp, size)
struct mdesc *mdp;
int size;
{
PTR result = NULL;
off_t foffset;
size_t mapbytes;
caddr_t moveto;
caddr_t mapto;
char buf = 0;
int flags = 0;
if (pagesize == 0)
{
pagesize = getpagesize ();
}
if (size == 0)
{
return (mdp -> breakval);
}
if (size < 0)
{
if (mdp -> breakval + size >= mdp -> base)
{
result = (PTR) mdp -> breakval;
moveto = PAGE_ALIGN (mdp -> breakval + size);
#ifdef HAVE_MSYNC
#ifdef MS_SYNC
msync (moveto, (size_t) (mdp -> top - moveto), MS_SYNC | MS_INVALIDATE);
#else
msync (moveto, (size_t) (mdp -> top - moveto));
#endif
#endif
munmap (moveto, (size_t) (mdp -> top - moveto));
mdp -> breakval += size;
mdp -> top = moveto;
return result;
}
else
{
return NULL;
}
}
#ifndef MAP_ANONYMOUS
if (mdp -> fd < 0)
{
char buf[64];
sprintf (buf, "/tmp/mmalloc.XXXXXX");
mdp -> fd = mkstemp (buf);
if (mdp -> fd < 0)
{
fprintf (stderr, "unable to create default mmalloc allocator: %s",
strerror (errno));
return NULL;
}
if (unlink (buf) != 0)
{
fprintf (stderr, "unable to unlink map file for default mmalloc allocator: %s\n",
strerror (errno));
}
}
#endif
if (mdp -> breakval + size <= mdp -> top)
{
result = (PTR) mdp -> breakval;
mdp -> breakval += size;
return result;
}
moveto = PAGE_ALIGN (mdp -> breakval + size);
mapbytes = moveto - mdp -> top;
foffset = mdp -> top - mdp -> base;
#ifdef MAP_ANONYMOUS
if (mdp -> fd < 0)
{
flags = MAP_PRIVATE | MAP_ANONYMOUS;
}
#endif
if (mdp -> fd > 0)
{
lseek (mdp -> fd, foffset + mapbytes - 1, SEEK_SET);
write (mdp -> fd, &buf, 1);
#ifdef MAP_FILE
flags = MAP_PRIVATE_OR_SHARED (mdp) | MAP_FILE;
#else
flags = MAP_PRIVATE_OR_SHARED (mdp)
#endif
}
if (mdp -> base == 0)
{
mapto = mmap (0, mapbytes, PROT_READ | PROT_WRITE,
flags, mdp -> fd, foffset);
if (mapto != (caddr_t) -1)
{
mdp -> base = mdp -> breakval = mapto;
mdp -> top = mdp -> base + mapbytes;
result = (PTR) mdp -> breakval;
mdp -> breakval += size;
}
}
else
{
vm_address_t r_start;
vm_size_t r_size;
vm_region_basic_info_data_t r_data;
mach_msg_type_number_t r_info_size;
port_t r_object_name;
kern_return_t kret;
r_start = (vm_address_t) mdp -> top;
r_info_size = VM_REGION_BASIC_INFO_COUNT;
kret = vm_region (mach_task_self(), &r_start, &r_size,
VM_REGION_BASIC_INFO, (vm_region_info_t) &r_data,
&r_info_size, &r_object_name);
if ((kret != KERN_SUCCESS) && (kret != KERN_INVALID_ADDRESS))
{
return NULL;
}
if ((kret == KERN_SUCCESS) && (r_start < (mdp -> top + mapbytes)))
{
return NULL;
}
mapto = mmap (mdp -> top, mapbytes, PROT_READ | PROT_WRITE,
flags | MAP_FIXED, mdp -> fd, foffset);
if (mapto == mdp -> top)
{
mdp -> top = moveto;
result = (PTR) mdp -> breakval;
mdp -> breakval += size;
}
else
{
return NULL;
}
}
return (result);
}
PTR
mmalloc_findbase (size, base)
size_t size;
size_t base;
{
vm_address_t last = base;
if (last == 0)
last = 0xd0000000;
for (;;) {
vm_address_t r_start;
vm_size_t r_size;
vm_region_basic_info_data_t r_data;
mach_msg_type_number_t r_info_size;
port_t r_object_name;
kern_return_t kret;
r_start = last;
r_info_size = VM_REGION_BASIC_INFO_COUNT;
kret = vm_region (mach_task_self(), &r_start, &r_size,
VM_REGION_BASIC_INFO, (vm_region_info_t) &r_data,
&r_info_size, &r_object_name);
if ((kret == KERN_INVALID_ADDRESS) && ((last + size) > last))
{
return last;
}
if (kret != KERN_SUCCESS)
{
return NULL;
}
if ((r_start - last) >= size)
{
return last;
}
last = r_start + r_size;
}
}
PTR
mmalloc_findbase_hidden (size)
size_t size;
{
int fd;
int flags;
caddr_t base = NULL;
if (pagesize == 0)
{
pagesize = getpagesize ();
}
#ifdef MAP_ANONYMOUS
flags = MAP_PRIVATE | MAP_ANONYMOUS;
fd = -1;
#else
#ifdef MAP_FILE
flags = MAP_PRIVATE | MAP_FILE;
#else
flags = MAP_PRIVATE;
#endif
#endif
#ifndef MAP_ANONYMOUS
{
char buf[64];
sprintf (buf, "/tmp/mmalloc.XXXXXX");
fd = mkstemp (buf);
if (fd < 0)
{
fprintf (stderr, "unable to create default mmalloc allocator: %s",
strerror (errno));
return NULL;
}
if (unlink (buf) != 0)
{
fprintf (stderr, "unable to unlink map file for default mmalloc allocator: %s",
strerror (errno));
}
}
#endif
size = (size_t) PAGE_ALIGN ((PTR) size);
base = mmap (0, size, PROT_READ | PROT_WRITE, flags, fd, 0);
if (base != (caddr_t) -1)
{
#ifdef MS_SYNC
msync (base, (size_t) size, MS_SYNC | MS_INVALIDATE);
#else
msync (base, (size_t) size);
#endif
munmap (base, (size_t) size);
}
if (fd != -1)
{
close (fd);
}
if (base == 0)
{
base = (caddr_t) getpagesize ();
}
else if (base == (caddr_t) -1)
{
base = NULL;
}
return ((PTR) base);
}
void mmalloc_endpoints (md, start, end)
PTR md;
size_t *start;
size_t *end;
{
struct mdesc *mdp = MD_TO_MDP (md);
if (pagesize == 0)
{
pagesize = getpagesize ();
}
if (mdp->child)
return mmalloc_endpoints (mdp->child, start, end);
*start = (size_t) mdp->base;
*end = (size_t) PAGE_ALIGN (mdp->breakval);
}
#endif