ack/plat/osx/libsys/brk.c
George Koehler 02fb480217 Commit a preview of osx386 and osxppc as new platforms.
These produce Mach-o executables for Mac OS X on Intel or PowerPC
processors.  Our code generator for PowerPC (mach/powerpc) still has
bugs.  Some examples seem to run, but startrek crashes.  Our code
generator for Intel (mach/i386) is better.

There is a problem with job control.  If you run paranoia or startrek,
then suspend the job (^Z) and resume it ('fg' in bash), then read(2)
might fail with EINTR.

The larger files in this commit are
 - plat/osx/cvmach/cvmach.c
 - plat/osx/libsys/brk.c
 - plat/osx386/libsys/sigaction.s
 - plat/osxppc/libsys/sigaction.s
2016-10-02 14:58:05 -04:00

96 lines
2 KiB
C

/*
* This emulates brk() and sbrk() using mmap() and mprotect().
*
* We reserve exactly SEGMENTSZ bytes of address space by calling
* mmap() with PROT_NONE. Then we allocate pages in our segment by
* calling mprotect() with PROT_READ|PROT_WRITE.
*
* This emulation can't resize its segment. If SEGMENTSZ is too big,
* then programs might run out of address space for other mappings.
*/
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
/*
* PAGESZ must be correct for this system!
* SEGMENTSZ must be a multiple of PAGESZ.
*/
#define PAGESZ 0x1000 /* page size for i386, powerpc */
#define SEGMENTSZ 0x20000000
static char *segment;
static char *cbreak; /* current break */
static void brk_init(void)
{
/*
* Try exactly once to reserve our segment. If we fail, then
* segment == MAP_FAILED and we never try again.
*/
if (segment == NULL) {
segment = mmap(NULL, SEGMENTSZ, PROT_NONE,
MAP_PRIVATE|MAP_ANON, -1, 0);
cbreak = segment;
}
}
static int brk1(char *nbreak)
{
size_t sz;
char *new, *old;
sz = (segment == MAP_FAILED) ? 0 : SEGMENTSZ;
if (nbreak < segment || nbreak > segment + sz) {
errno = ENOMEM;
return -1;
}
/* Round up to page size. */
old = (char *)(((size_t)cbreak + (PAGESZ-1)) & ~(PAGESZ-1));
new = (char *)(((size_t)nbreak + (PAGESZ-1)) & ~(PAGESZ-1));
if (new > old) {
/* Allocate pages by unprotecting them. */
if (mprotect(old, new - old, PROT_READ|PROT_WRITE) < 0) {
errno = ENOMEM;
return -1;
}
} else if (new < old) {
/*
* Free pages by using MAP_FIXED to replace the
* mapping. Ignore errors.
*/
mmap(new, old - new, PROT_NONE,
MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
}
cbreak = nbreak;
return 0;
}
int brk(void *addr)
{
brk_init();
return brk1(addr);
}
void *sbrk(int incr)
{
char *base, *nbreak;
brk_init();
base = cbreak;
nbreak = base + incr;
/* Did base + incr overflow? */
if ((incr < 0 && nbreak > base) ||
(incr > 0 && nbreak < base)) {
errno = ENOMEM;
return (void*)-1;
}
if (brk1(nbreak) < 0)
return (void*)-1;
return base;
}