mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-03-26 08:41:47 -07:00
Freebsd support.
Copied from Perforce Change: 23681 ServerID: perforce.ravenbrook.com
This commit is contained in:
commit
4be3e43fe9
15 changed files with 1323 additions and 108 deletions
|
|
@ -19,7 +19,7 @@
|
|||
#include "mpsw3.h"
|
||||
#endif
|
||||
#include <string.h>
|
||||
#ifdef MPS_OS_LI
|
||||
#if defined(MPS_OS_LI) || defined(MPS_OS_FR)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ static void *setup(void *v, size_t s)
|
|||
"Weak AP Create\n");
|
||||
die(mps_ap_create(&bogusap, tablepool, MPS_RANK_EXACT),
|
||||
"Bogus AP Create\n");
|
||||
|
||||
|
||||
test(leafap, exactap, weakap, bogusap);
|
||||
|
||||
mps_ap_destroy(bogusap);
|
||||
|
|
|
|||
|
|
@ -125,12 +125,12 @@ static char *parseArgs(int argc, char *argv[])
|
|||
{
|
||||
char *name = "mpsio.log";
|
||||
int i = 1;
|
||||
|
||||
|
||||
if (argc >= 1)
|
||||
prog = argv[0];
|
||||
else
|
||||
prog = "unknown";
|
||||
|
||||
|
||||
while (i < argc) { /* consider argument i */
|
||||
if (argv[i][0] == '-') { /* it's an option argument */
|
||||
switch (argv[i][1]) {
|
||||
|
|
@ -138,9 +138,9 @@ static char *parseArgs(int argc, char *argv[])
|
|||
++ i;
|
||||
if (i == argc)
|
||||
usageError();
|
||||
else
|
||||
else
|
||||
name = argv[i];
|
||||
break;
|
||||
break;
|
||||
case 'p': /* partial log */
|
||||
partialLog = TRUE;
|
||||
break;
|
||||
|
|
@ -154,7 +154,7 @@ static char *parseArgs(int argc, char *argv[])
|
|||
usageError();
|
||||
else
|
||||
parseEventSpec(argv[i]);
|
||||
} break;
|
||||
} break;
|
||||
case 'b': { /* bucket size */
|
||||
++ i;
|
||||
if (i == argc)
|
||||
|
|
@ -165,7 +165,7 @@ static char *parseArgs(int argc, char *argv[])
|
|||
n = sscanf(argv[i], "%lu", &bucketSize);
|
||||
if (n != 1) usageError();
|
||||
}
|
||||
} break;
|
||||
} break;
|
||||
case 'S': /* style */
|
||||
style = argv[i][2]; /* '\0' for human-readable, 'L' for Lisp, */
|
||||
break; /* 'C' for CDF. */
|
||||
|
|
@ -192,7 +192,7 @@ static void processEvent(EventProc proc, Event event, Word etime)
|
|||
if (res != ResOK)
|
||||
error("Can't record event: error %d.", res);
|
||||
switch(event->any.code) {
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -246,7 +246,7 @@ static void reportEventResults(eventCountArray eventCounts)
|
|||
{
|
||||
EventCode i;
|
||||
unsigned long total = 0;
|
||||
|
||||
|
||||
for(i = 0; i <= EventCodeMAX; ++i) {
|
||||
total += eventCounts[i];
|
||||
if (eventEnabled[i])
|
||||
|
|
@ -441,7 +441,7 @@ static void readLog(EventProc proc)
|
|||
printf("%u", (unsigned)code);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (style) {
|
||||
case '\0':
|
||||
printf(" %8lu", (ulong)eventTime); break;
|
||||
|
|
@ -591,11 +591,16 @@ int main(int argc, char *argv[])
|
|||
EventProc proc;
|
||||
Res res;
|
||||
|
||||
#if !defined(MPS_OS_FR)
|
||||
/* GCC -ansi -pedantic -Werror on FreeBSD will fail here
|
||||
* with the warning "statement with no effect". */
|
||||
|
||||
assert(CHECKCONV(ulong, Word));
|
||||
assert(CHECKCONV(ulong, Addr));
|
||||
assert(CHECKCONV(ulong, void *));
|
||||
assert(CHECKCONV(unsigned, EventCode));
|
||||
assert(CHECKCONV(Addr, void *)); /* for labelled pointers */
|
||||
#endif
|
||||
|
||||
filename = parseArgs(argc, argv);
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
#include <stdlib.h> /* size_t */
|
||||
#include <string.h> /* strcmp */
|
||||
|
||||
|
||||
struct EventProcStruct {
|
||||
Bool partialLog; /* Is this a partial log? */
|
||||
EventProcReader reader; /* reader fn */
|
||||
|
|
@ -91,7 +90,7 @@ static eventRecord eventTypes[] = {
|
|||
static size_t eventType2Index(EventType type)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
||||
for(i = 0; i < eventTypeCount; ++i)
|
||||
if (eventTypes[i].type == type)
|
||||
return i;
|
||||
|
|
@ -105,7 +104,7 @@ static size_t eventType2Index(EventType type)
|
|||
static size_t eventCode2Index(EventCode code, Bool errorp)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
||||
for(i = 0; i < eventTypeCount; ++i)
|
||||
if (eventTypes[i].code == code)
|
||||
return i;
|
||||
|
|
@ -120,7 +119,7 @@ static size_t eventCode2Index(EventCode code, Bool errorp)
|
|||
EventCode EventName2Code(char *name)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
|
||||
for(i = 0; i < eventTypeCount; ++i)
|
||||
if (strcmp(eventTypes[i].name, name) == 0) {
|
||||
assert(eventTypes[i].code <= EventCodeMAX);
|
||||
|
|
@ -250,7 +249,7 @@ EventString LabelText(EventProc proc, Word id)
|
|||
|
||||
Res EventRead(Event *eventReturn, EventProc proc)
|
||||
{
|
||||
size_t index, length;
|
||||
size_t eventIndex, length;
|
||||
Res res;
|
||||
EventType type;
|
||||
Event event;
|
||||
|
|
@ -259,8 +258,8 @@ Res EventRead(Event *eventReturn, EventProc proc)
|
|||
res = proc->reader(proc->readerP, &type, sizeof(EventType));
|
||||
if (res != ResOK) return res;
|
||||
|
||||
index = eventType2Index(type);
|
||||
length = eventTypes[index].length;
|
||||
eventIndex = eventType2Index(type);
|
||||
length = eventTypes[eventIndex].length;
|
||||
if (proc->cachedEvent != NULL) {
|
||||
event = proc->cachedEvent;
|
||||
proc->cachedEvent = NULL;
|
||||
|
|
@ -306,7 +305,7 @@ Res EventRecord(EventProc proc, Event event, Word etime)
|
|||
switch(event->any.code) {
|
||||
case EventIntern: { /* id, label */
|
||||
Symbol sym = malloc(sizeof(symbolStruct));
|
||||
|
||||
|
||||
if (sym == NULL) return ResMEMORY;
|
||||
sym->id = event->ws.w0;
|
||||
res = eventStringCopy(&(sym->name), &(event->ws.s1));
|
||||
|
|
@ -332,7 +331,7 @@ Res EventRecord(EventProc proc, Event event, Word etime)
|
|||
else
|
||||
res = TableDefine(proc->labelTable, (Word)label->addr, label);
|
||||
} break;
|
||||
default:
|
||||
default:
|
||||
res = ResOK;
|
||||
break;
|
||||
}
|
||||
|
|
@ -386,7 +385,11 @@ Res EventProcCreate(EventProc *procReturn, Bool partial,
|
|||
assert(CHECKFIELD(EventUnion, any.code, EventWSStruct, code));
|
||||
assert(CHECKFIELD(EventUnion, any.clock, EventWSStruct, clock));
|
||||
/* check use of labelTable */
|
||||
#if !defined(MPS_OS_FR)
|
||||
/* GCC -ansi -pedantic -Werror on FreeBSD will fail here
|
||||
* with the warning "statement with no effect". */
|
||||
assert(sizeof(Word) >= sizeof(Addr));
|
||||
#endif
|
||||
|
||||
proc->partialLog = partial;
|
||||
proc->reader = reader; proc->readerP = readerP;
|
||||
|
|
|
|||
25
mps/code/fri4gc.gmk
Normal file
25
mps/code/fri4gc.gmk
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# impl.gmk.fri4gc: BUILD FOR FreeBSD/INTEL/GCC PLATFORM
|
||||
#
|
||||
# $HopeName: MMsrc!lii4gc.gmk(trunk.5) $
|
||||
# Copyright (C) 2000 Harlequin Limited. All rights reserved.
|
||||
|
||||
PFM = fri4gc
|
||||
|
||||
PFMDEFS = -D_REENTRANT
|
||||
|
||||
MPMPF = mpsliban.c mpsioan.c lockfr.c thfri4.c pthrdext.c vmfr.c \
|
||||
protfr.c protfri3.c prmcan.c ssfri3.c span.c
|
||||
SWPF = than.c vmfr.c protsw.c prmcan.c ssan.c
|
||||
|
||||
LIBS = -lm -pthread
|
||||
|
||||
include gc.gmk
|
||||
|
||||
CC = cc
|
||||
|
||||
# Suppress some warnings (SuSE).
|
||||
# .void: -Wpointer-arith cannot be used because the string.h header does
|
||||
# arithmetic on void*.
|
||||
CFLAGSCOMPILER := $(subst -Wpointer-arith,,$(CFLAGSCOMPILER))
|
||||
|
||||
include comm.gmk
|
||||
236
mps/code/lockfr.c
Normal file
236
mps/code/lockfr.c
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/* impl.c.lockfr: RECURSIVE LOCKS FOR POSIX SYSTEMS
|
||||
*
|
||||
* $HopeName$
|
||||
* Copyright (C) 2000 Harlequin Limited. All rights reserved.
|
||||
*
|
||||
* .freebsd: This implementation supports FreeBSD (platform
|
||||
* MPS_OS_FR).
|
||||
*
|
||||
* .posix: In fact, the implementation should be reusable for most POSIX
|
||||
* implementations, but may need some customization for each.
|
||||
*
|
||||
* .design: These locks are implemented using mutexes.
|
||||
*
|
||||
* .recursive: Mutexes support both non-recursive and recursive
|
||||
* locking, but only at initialization time. This doesn't match the
|
||||
* API of MPS Lock module, which chooses at locking time, so all locks
|
||||
* are made (non-recursive) errorchecking. Recursive locks are
|
||||
* implemented by checking the error code.
|
||||
*
|
||||
* .claims: During use the claims field is updated to remember the
|
||||
* number of claims acquired on a lock. This field must only be
|
||||
* modified while we hold the mutex. */
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "mpmtypes.h"
|
||||
#include "lock.h"
|
||||
#include "config.h"
|
||||
|
||||
|
||||
#ifndef MPS_OS_FR
|
||||
#error "lockfr.c is FreeBSD specific but MPS_OS_FR not defined"
|
||||
#endif
|
||||
|
||||
SRCID(lockfr, "$HopeName$");
|
||||
|
||||
|
||||
/* LockStruct -- the MPS lock structure
|
||||
*
|
||||
* .lock.posix: Posix lock structure; uses a mutex.
|
||||
*/
|
||||
|
||||
typedef struct LockStruct {
|
||||
Sig sig; /* design.mps.sig */
|
||||
unsigned long claims; /* # claims held by owner */
|
||||
pthread_mutex_t mut; /* the mutex itself */
|
||||
} LockStruct;
|
||||
|
||||
|
||||
/* LockSize -- size of a LockStruct */
|
||||
|
||||
size_t LockSize(void)
|
||||
{
|
||||
return sizeof(LockStruct);
|
||||
}
|
||||
|
||||
|
||||
/* LockCheck -- check a lock */
|
||||
|
||||
Bool LockCheck(Lock lock)
|
||||
{
|
||||
CHECKS(Lock, lock);
|
||||
/* While claims can't be very large, I don't dare to put a limit on it. */
|
||||
/* There's no way to test the mutex, or check if it's held by somebody. */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* LockInit -- initialize a lock */
|
||||
|
||||
void LockInit(Lock lock)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
int res;
|
||||
|
||||
AVER(lock != NULL);
|
||||
lock->claims = 0;
|
||||
res = pthread_mutexattr_init(&attr);
|
||||
AVER(res == 0);
|
||||
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
AVER(res == 0);
|
||||
res = pthread_mutex_init(&lock->mut, &attr);
|
||||
AVER(res == 0);
|
||||
res = pthread_mutexattr_destroy(&attr);
|
||||
AVER(res == 0);
|
||||
lock->sig = LockSig;
|
||||
AVERT(Lock, lock);
|
||||
}
|
||||
|
||||
|
||||
/* LockFinish -- finish a lock */
|
||||
|
||||
void LockFinish(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
AVERT(Lock, lock);
|
||||
/* Lock should not be finished while held */
|
||||
AVER(lock->claims == 0);
|
||||
res = pthread_mutex_destroy(&lock->mut);
|
||||
AVER(res == 0);
|
||||
lock->sig = SigInvalid;
|
||||
}
|
||||
|
||||
|
||||
/* LockClaim -- claim a lock (non-recursive) */
|
||||
|
||||
void LockClaim(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
AVERT(Lock, lock);
|
||||
|
||||
res = pthread_mutex_lock(&lock->mut);
|
||||
/* pthread_mutex_lock will error if we own the lock already. */
|
||||
AVER(res == 0);
|
||||
|
||||
/* This should be the first claim. Now we own the mutex */
|
||||
/* it is ok to check this. */
|
||||
AVER(lock->claims == 0);
|
||||
lock->claims = 1;
|
||||
}
|
||||
|
||||
|
||||
/* LockReleaseMPM -- release a lock (non-recursive) */
|
||||
|
||||
void LockReleaseMPM(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
AVERT(Lock, lock);
|
||||
AVER(lock->claims == 1); /* The lock should only be held once */
|
||||
lock->claims = 0; /* Must set this before releasing the lock */
|
||||
res = pthread_mutex_unlock(&lock->mut);
|
||||
/* pthread_mutex_unlock will error if we didn't own the lock. */
|
||||
AVER(res == 0);
|
||||
}
|
||||
|
||||
|
||||
/* LockClaimRecursive -- claim a lock (recursive) */
|
||||
|
||||
void LockClaimRecursive(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
AVERT(Lock, lock);
|
||||
|
||||
res = pthread_mutex_lock(&lock->mut);
|
||||
/* pthread_mutex_lock will return: */
|
||||
/* 0 if we have just claimed the lock */
|
||||
/* EDEADLK if we own the lock already. */
|
||||
AVER((res == 0 && lock->claims == 0) ||
|
||||
(res == EDEADLK && lock->claims > 0));
|
||||
|
||||
++lock->claims;
|
||||
AVER(lock->claims > 0);
|
||||
}
|
||||
|
||||
|
||||
/* LockReleaseRecursive -- release a lock (recursive) */
|
||||
|
||||
void LockReleaseRecursive(Lock lock)
|
||||
{
|
||||
int res;
|
||||
|
||||
AVERT(Lock, lock);
|
||||
AVER(lock->claims > 0);
|
||||
--lock->claims;
|
||||
if (lock->claims == 0) {
|
||||
res = pthread_mutex_unlock(&lock->mut);
|
||||
/* pthread_mutex_unlock will error if we didn't own the lock. */
|
||||
AVER(res == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Global locks
|
||||
*
|
||||
* .global: The two "global" locks are statically allocated normal locks.
|
||||
*/
|
||||
|
||||
static LockStruct globalLockStruct;
|
||||
static LockStruct globalRecLockStruct;
|
||||
static Lock globalLock = &globalLockStruct;
|
||||
static Lock globalRecLock = &globalRecLockStruct;
|
||||
static pthread_once_t isGlobalLockInit = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void globalLockInit(void)
|
||||
{
|
||||
LockInit(globalLock);
|
||||
LockInit(globalRecLock);
|
||||
}
|
||||
|
||||
|
||||
/* LockClaimGlobalRecursive -- claim the global recursive lock */
|
||||
|
||||
void LockClaimGlobalRecursive(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Ensure the global lock has been initialized */
|
||||
res = pthread_once(&isGlobalLockInit, globalLockInit);
|
||||
AVER(res == 0);
|
||||
LockClaimRecursive(globalRecLock);
|
||||
}
|
||||
|
||||
|
||||
/* LockReleaseGlobalRecursive -- release the global recursive lock */
|
||||
|
||||
void LockReleaseGlobalRecursive(void)
|
||||
{
|
||||
LockReleaseRecursive(globalRecLock);
|
||||
}
|
||||
|
||||
|
||||
/* LockClaimGlobal -- claim the global non-recursive lock */
|
||||
|
||||
void LockClaimGlobal(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
/* Ensure the global lock has been initialized */
|
||||
res = pthread_once(&isGlobalLockInit, globalLockInit);
|
||||
AVER(res == 0);
|
||||
LockClaim(globalLock);
|
||||
}
|
||||
|
||||
|
||||
/* LockReleaseGlobal -- release the global non-recursive lock */
|
||||
|
||||
void LockReleaseGlobal(void)
|
||||
{
|
||||
LockReleaseMPM(globalLock);
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@
|
|||
|
||||
/* GCC 2.7.2.1, gcc -E -dM -traditional-cpp and <URL:http://developer.apple.c
|
||||
* om/techpubs/macosx/System/Documentation/Developer/YellowBox/Reference/DevT
|
||||
* ools/Preprocessor/Preprocessor.[ef].html>
|
||||
* ools/Preprocessor/Preprocessor.[ef].html>
|
||||
*/
|
||||
|
||||
#elif defined(__APPLE__) && defined(__ppc__) && defined(__MACH__) && defined(__GNUC__)
|
||||
|
|
@ -291,6 +291,20 @@
|
|||
#define MPS_WORD_SHIFT 5
|
||||
#define MPS_PF_ALIGN 8 /* @@@@ not tested */
|
||||
|
||||
/* GCC 2.95.3, gcc -E -dM
|
||||
*/
|
||||
|
||||
#elif defined(__FreeBSD__) && defined (__i386__) && defined (__GNUC__)
|
||||
#define MPS_PF_FRI4GC
|
||||
#define MPS_PF_STRING "fri4gc"
|
||||
#define MPS_OS_FR
|
||||
#define MPS_ARCH_I4
|
||||
#define MPS_BUILD_GC
|
||||
#define MPS_T_WORD unsigned long
|
||||
#define MPS_WORD_WIDTH 32
|
||||
#define MPS_WORD_SHIFT 5
|
||||
#define MPS_PF_ALIGN 4
|
||||
|
||||
#else
|
||||
#error "Unable to detect target platform"
|
||||
#endif
|
||||
|
|
|
|||
21
mps/code/prmcfr.h
Normal file
21
mps/code/prmcfr.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* impl.h.prmcfr: PROTECTION MUTATOR CONTEXT (FREEBSD)
|
||||
*
|
||||
* $HopeName: $
|
||||
* Copyright (C) 1998 The Harlequin Group Limited. All rights reserved.
|
||||
*
|
||||
* .readership: MPS developers.
|
||||
*/
|
||||
|
||||
#ifndef prmcfr_h
|
||||
#define prmcfr_h
|
||||
|
||||
#include "mpm.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
typedef struct MutatorFaultContextStruct { /* Protection fault context data */
|
||||
ucontext_t *ucontext;
|
||||
} MutatorFaultContextStruct;
|
||||
|
||||
|
||||
#endif /* prmcfr_h */
|
||||
93
mps/code/protfr.c
Normal file
93
mps/code/protfr.c
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* impl.c.protfr: PROTECTION FOR FreeBSD
|
||||
*
|
||||
* $HopeName: $
|
||||
* Copyright (C) 1995,1999 Harlequin Group, all rights reserved
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mpm.h"
|
||||
|
||||
#ifndef MPS_OS_FR
|
||||
#error "protfr.c is FreeBSD specific, but MPS_OS_FR is not set"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protfr.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
SRCID(protfr, "$HopeName: $");
|
||||
|
||||
|
||||
/* ProtSet -- set protection
|
||||
*
|
||||
* This is just a thin veneer on top of mprotect(2).
|
||||
*/
|
||||
|
||||
void ProtSet(Addr base, Addr limit, AccessSet mode)
|
||||
{
|
||||
int flags;
|
||||
int res;
|
||||
|
||||
AVER(sizeof(int) == sizeof(Addr)); /* should be redundant; will fail on Alpha */
|
||||
AVER(base < limit);
|
||||
AVER(base != 0);
|
||||
AVER(AddrOffset(base, limit) <= INT_MAX); /* should be redundant */
|
||||
|
||||
#if 0
|
||||
/* .flags.trouble: This less strict version of flags (which allows write
|
||||
* access unless explicitly told not to) caused mmqa test 37 to fail.
|
||||
* This might be a bug in MPS, so for now we go with the stricter
|
||||
* version that matches the Win32 implementation. */
|
||||
/* .flags.trouble.freebsd: the above comment was in the Linux version
|
||||
* of this code; I haven't verified it for FreeBSD. */
|
||||
flags = 0;
|
||||
if((mode & AccessREAD) == 0)
|
||||
flags |= PROT_READ | PROT_EXEC;
|
||||
if((mode & AccessWRITE) == 0)
|
||||
flags |= PROT_WRITE;
|
||||
#endif
|
||||
flags = PROT_READ | PROT_WRITE | PROT_EXEC;
|
||||
if((mode & AccessWRITE) != 0)
|
||||
flags = PROT_READ | PROT_EXEC;
|
||||
if((mode & AccessREAD) != 0)
|
||||
flags = 0;
|
||||
|
||||
res = mprotect((void *)base, (size_t)AddrOffset(base, limit), flags);
|
||||
AVER(res == 0);
|
||||
}
|
||||
|
||||
|
||||
/* ProtSync -- synchronize protection settings with hardware
|
||||
*
|
||||
* This does nothing under FreeBSD.
|
||||
*/
|
||||
|
||||
void ProtSync(Arena arena)
|
||||
{
|
||||
NOOP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ProtTramp -- protection trampoline
|
||||
*
|
||||
* The protection trampoline is trivial under FreeBSD, as there is
|
||||
* nothing that needs to be done in the dynamic context of the mutator
|
||||
* in order to catch faults. (Contrast this with Win32 Structured
|
||||
* Exception Handling.)
|
||||
*/
|
||||
|
||||
void ProtTramp(void **resultReturn, void *(*f)(void *, size_t),
|
||||
void *p, size_t s)
|
||||
{
|
||||
AVER(resultReturn != NULL);
|
||||
AVER(FUNCHECK(f));
|
||||
/* Can't check p and s as they are interpreted by the client */
|
||||
|
||||
*resultReturn = (*f)(p, s);
|
||||
}
|
||||
137
mps/code/protfri3.c
Normal file
137
mps/code/protfri3.c
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
/* impl.c.protfri3: PROTECTION FOR FREEBSD (INTEL 386)
|
||||
*
|
||||
* $HopeName: MMsrc!protlii3.c(trunk.3) $
|
||||
* Copyright (C) 2000 Harlequin Limited. All rights reserved.
|
||||
*
|
||||
* SOURCES
|
||||
*
|
||||
* .source.i486: Intel486 Microprocessor Family Programmer's
|
||||
* Reference Manual
|
||||
*
|
||||
* .source.man: sigaction(2): FreeBSD System Calls Manual.
|
||||
*/
|
||||
|
||||
#include "prmcfr.h"
|
||||
|
||||
#ifndef MPS_OS_FR
|
||||
#error "protfri3.c is FreeBSD-specific, but MPS_OS_FR is not set"
|
||||
#endif
|
||||
#if !defined(MPS_ARCH_I3) && !defined(MPS_ARCH_I4)
|
||||
#error "protfri3.c is Intel-specific, but MPS_ARCH_I3 or MPS_ARCH_I4 is not set"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protfri3.c implements protection, but PROTECTION is not set"
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
SRCID(protfri3, "$HopeName: MMsrc!protlii3.c(trunk.3) $");
|
||||
|
||||
|
||||
/* The previously-installed signal action, as returned by */
|
||||
/* sigaction(3). See ProtSetup. */
|
||||
|
||||
static struct sigaction sigNext;
|
||||
|
||||
/* sigHandle -- protection signal handler
|
||||
*
|
||||
* This is the signal handler installed by ProtSetup to deal with
|
||||
* protection faults. It is installed on the SIGBUS signal. It
|
||||
* decodes the protection fault details from the signal context and
|
||||
* passes them to ArenaAccess, which attempts to handle the fault and
|
||||
* remove its cause. If the fault is handled, then the handler
|
||||
* returns and execution resumes. If it isn't handled, then
|
||||
* sigHandle does its best to pass the signal on to the previously
|
||||
* installed signal handler (sigNext).
|
||||
*
|
||||
* .sigh.args: The sigaction manual page .source.man documents three
|
||||
* different handler prototypes: ANSI C sa_handler, traditional BSD
|
||||
* sa_handler, and POSIX SA_SIGINFO sa_sigaction. The ANSI C
|
||||
* prototype isn't powerful enough for us (can't get addresses), and
|
||||
* the manual page deprecates the BSD sa_handler in favour of the
|
||||
* POSIX SA_SIGINFO sa_sigaction. In that prototype, the arguments
|
||||
* are: signal number, pointer to signal info structure, pointer to
|
||||
* signal context structure.
|
||||
*
|
||||
* .sigh.context: We only know how to handle signals with code
|
||||
* BUS_PAGE_FAULT, where info->si_addr gives the fault address.
|
||||
*
|
||||
* .sigh.mode: The fault type (read/write) does not appear to be
|
||||
* available to the signal handler (see mail archive).
|
||||
*/
|
||||
|
||||
static void sigHandle(int sig, siginfo_t *info, void *context) /* .sigh.args */
|
||||
{
|
||||
AVER(sig == SIGBUS);
|
||||
|
||||
if(info->si_code == BUS_PAGE_FAULT) { /* .sigh.context */
|
||||
AccessSet mode;
|
||||
Addr base, limit;
|
||||
|
||||
mode = AccessREAD | AccessWRITE; /* .sigh.mode */
|
||||
|
||||
/* We assume that the access is for one word at the address. */
|
||||
base = (Addr)info->si_addr; /* .sigh.context */
|
||||
limit = AddrAdd(base, (Size)sizeof(Addr));
|
||||
|
||||
/* Offer each protection structure the opportunity to handle the */
|
||||
/* exception. If it succeeds, then allow the mutator to continue. */
|
||||
if(ArenaAccess(base, mode, NULL))
|
||||
return;
|
||||
}
|
||||
|
||||
/* The exception was not handled by any known protection structure, */
|
||||
/* so throw it to the previously installed handler. */
|
||||
|
||||
/* @@@@ This is really weak. */
|
||||
/* Need to implement rest of the contract of sigaction */
|
||||
/* We might also want to set SA_RESETHAND in the flags and explicitly */
|
||||
/* reinstall the handler from withint itself so the SIG_DFL/SIG_IGN */
|
||||
/* case can work properly by just returning. */
|
||||
switch ((int)sigNext.sa_handler) {
|
||||
case (int)SIG_DFL:
|
||||
case (int)SIG_IGN:
|
||||
abort();
|
||||
NOTREACHED;
|
||||
break;
|
||||
default:
|
||||
if ((int)sigNext.sa_handler & SA_SIGINFO) {
|
||||
(*sigNext.sa_sigaction)(sig, info, context);
|
||||
} else {
|
||||
/* @@@@ what if the previous handler is BSD-style? */
|
||||
/* We don't have a struct sigcontext to pass to it.
|
||||
The second argument (the code) is just info->si_code
|
||||
but the third argument (the sigcontext) we would have to
|
||||
fake from the ucontext. We could do that. */
|
||||
(*sigNext.sa_handler)(sig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ProtSetup -- global protection setup
|
||||
*
|
||||
* Under FreeBSD, the global setup involves installing a signal
|
||||
* handler on SIGBUS to catch and handle page faults (see
|
||||
* sigHandle). The previous handler is recorded so that it can be
|
||||
* reached from sigHandle if it fails to handle the fault.
|
||||
*
|
||||
* NOTE: There are problems with this approach:
|
||||
* 1. we can't honor the sa_flags for the previous handler,
|
||||
* 2. what if this thread is suspended just after calling signal(3)?
|
||||
* The sigNext variable will never be initialized! */
|
||||
|
||||
void ProtSetup(void)
|
||||
{
|
||||
struct sigaction sa;
|
||||
int result;
|
||||
|
||||
sa.sa_sigaction = sigHandle;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
|
||||
result = sigaction(SIGBUS, &sa, &sigNext);
|
||||
AVER(result == 0);
|
||||
}
|
||||
|
|
@ -13,9 +13,13 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "mpm.h"
|
||||
|
||||
#if defined(MPS_OS_LI)
|
||||
/* open sesame magic */
|
||||
#define _BSD_SOURCE 1
|
||||
#define _POSIX_C_SOURCE 1
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
|
@ -26,7 +30,6 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "pthrdext.h"
|
||||
#include "mpm.h"
|
||||
|
||||
SRCID(pthreadext, "$HopeName$");
|
||||
|
||||
|
|
@ -37,7 +40,7 @@ SRCID(pthreadext, "$HopeName$");
|
|||
*/
|
||||
|
||||
#define PTHREADEXT_SIGSUSPEND SIGXFSZ
|
||||
#define PTHREADEXT_SIGRESUME SIGPWR
|
||||
#define PTHREADEXT_SIGRESUME SIGXCPU
|
||||
|
||||
|
||||
/* Static data initiatialized on first use of the module
|
||||
|
|
@ -63,9 +66,89 @@ static PThreadext suspendingVictim = NULL; /* current victim */
|
|||
static RingStruct suspendedRing; /* PThreadext suspend ring */
|
||||
|
||||
|
||||
static void suspendSignalHandler(int sig, struct sigcontext scp);
|
||||
static void resumeSignalHandler(int sig);
|
||||
/* suspendSignalHandler -- signal handler called when suspending a thread
|
||||
*
|
||||
* See design.mps.pthreadext.impl.suspend-handler
|
||||
*
|
||||
* The interface for determining the MFC might be platform specific.
|
||||
*
|
||||
* Handle PTHREADEXT_SIGSUSPEND in the target thread, to suspend it until
|
||||
* receiving PTHREADEXT_SIGRESUME (resume). Note that this is run with both
|
||||
* PTHREADEXT_SIGSUSPEND and PTHREADEXT_SIGRESUME blocked. Having
|
||||
* PTHREADEXT_SIGRESUME blocked prevents a resume before we can finish the
|
||||
* suspend protocol.
|
||||
*/
|
||||
|
||||
#if defined(MPS_OS_LI)
|
||||
|
||||
#include "prmcli.h"
|
||||
|
||||
static void suspendSignalHandler(int sig, struct sigcontext scp)
|
||||
{
|
||||
sigset_t signal_set;
|
||||
MutatorFaultContextStruct mfContext;
|
||||
|
||||
AVER(sig == PTHREADEXT_SIGSUSPEND);
|
||||
UNUSED(sig);
|
||||
|
||||
AVER(suspendingVictim != NULL);
|
||||
mfContext.scp = &scp;
|
||||
suspendingVictim->suspendedMFC = &mfContext;
|
||||
/* Block all signals except PTHREADEXT_SIGRESUME while suspended. */
|
||||
sigfillset(&signal_set);
|
||||
sigdelset(&signal_set, PTHREADEXT_SIGRESUME);
|
||||
sem_post(&pthreadextSem);
|
||||
sigsuspend(&signal_set);
|
||||
|
||||
/* Once here, the resume signal handler has run to completion. */
|
||||
return;
|
||||
}
|
||||
|
||||
#elif defined(MPS_OS_FR)
|
||||
|
||||
#include "prmcfr.h"
|
||||
|
||||
static void suspendSignalHandler(int sig,
|
||||
siginfo_t *info,
|
||||
void *context)
|
||||
{
|
||||
sigset_t signal_set;
|
||||
ucontext_t ucontext;
|
||||
MutatorFaultContextStruct mfContext;
|
||||
|
||||
AVER(sig == PTHREADEXT_SIGSUSPEND);
|
||||
UNUSED(sig);
|
||||
|
||||
AVER(suspendingVictim != NULL);
|
||||
/* copy the ucontext structure so we definitely have it on our stack,
|
||||
* not (e.g.) shared with other threads. */
|
||||
ucontext = *(ucontext_t *)context;
|
||||
mfContext.ucontext = &ucontext;
|
||||
suspendingVictim->suspendedMFC = &mfContext;
|
||||
/* Block all signals except PTHREADEXT_SIGRESUME while suspended. */
|
||||
sigfillset(&signal_set);
|
||||
sigdelset(&signal_set, PTHREADEXT_SIGRESUME);
|
||||
sem_post(&pthreadextSem);
|
||||
sigsuspend(&signal_set);
|
||||
|
||||
/* Once here, the resume signal handler has run to completion. */
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* resumeSignalHandler -- signal handler called when resuming a thread
|
||||
*
|
||||
* See design.mps.pthreadext.impl.suspend-handler
|
||||
*/
|
||||
|
||||
static void resumeSignalHandler(int sig)
|
||||
{
|
||||
AVER(sig == PTHREADEXT_SIGRESUME);
|
||||
UNUSED(sig);
|
||||
return;
|
||||
}
|
||||
|
||||
/* PThreadextModuleInit -- Initialize the PThreadext module
|
||||
*
|
||||
|
|
@ -96,13 +179,20 @@ static void PThreadextModuleInit(void)
|
|||
/* PTHREADEXT_SIGRESUME signal cannot be delivered before the */
|
||||
/* target thread calls sigsuspend.) */
|
||||
|
||||
pthreadext_sigsuspend.sa_flags = 0;
|
||||
pthreadext_sigsuspend.sa_handler = (__sighandler_t)suspendSignalHandler;
|
||||
status = sigemptyset(&pthreadext_sigsuspend.sa_mask);
|
||||
AVER(status == 0);
|
||||
status = sigaddset(&pthreadext_sigsuspend.sa_mask, PTHREADEXT_SIGRESUME);
|
||||
AVER(status == 0);
|
||||
|
||||
#if defined(MPS_OS_LI)
|
||||
pthreadext_sigsuspend.sa_flags = 0;
|
||||
pthreadext_sigsuspend.sa_handler = (__sighandler_t)suspendSignalHandler;
|
||||
|
||||
#elif defined(MPS_OS_FR)
|
||||
pthreadext_sigsuspend.sa_flags = SA_SIGINFO;
|
||||
pthreadext_sigsuspend.sa_sigaction = suspendSignalHandler;
|
||||
#endif
|
||||
|
||||
pthreadext_sigresume.sa_flags = 0;
|
||||
pthreadext_sigresume.sa_handler = resumeSignalHandler;
|
||||
status = sigemptyset(&pthreadext_sigresume.sa_mask);
|
||||
|
|
@ -131,7 +221,7 @@ extern Bool PThreadextCheck(PThreadext pthreadext)
|
|||
/* can't check ID */
|
||||
CHECKL(RingCheck(&pthreadext->threadRing));
|
||||
CHECKL(RingCheck(&pthreadext->idRing));
|
||||
if (pthreadext->suspendedScp == NULL) {
|
||||
if (pthreadext->suspendedMFC == NULL) {
|
||||
/* not suspended */
|
||||
CHECKL(RingIsSingle(&pthreadext->threadRing));
|
||||
CHECKL(RingIsSingle(&pthreadext->idRing));
|
||||
|
|
@ -142,7 +232,7 @@ extern Bool PThreadextCheck(PThreadext pthreadext)
|
|||
RING_FOR(node, &pthreadext->idRing, next) {
|
||||
PThreadext pt = RING_ELT(PThreadext, idRing, node);
|
||||
CHECKL(pt->id == pthreadext->id);
|
||||
CHECKL(pt->suspendedScp == pthreadext->suspendedScp);
|
||||
CHECKL(pt->suspendedMFC == pthreadext->suspendedMFC);
|
||||
}
|
||||
}
|
||||
status = pthread_mutex_unlock(&pthreadextMut);
|
||||
|
|
@ -163,7 +253,7 @@ extern void PThreadextInit(PThreadext pthreadext, pthread_t id)
|
|||
AVER(status == 0);
|
||||
|
||||
pthreadext->id = id;
|
||||
pthreadext->suspendedScp = NULL;
|
||||
pthreadext->suspendedMFC = NULL;
|
||||
RingInit(&pthreadext->threadRing);
|
||||
RingInit(&pthreadext->idRing);
|
||||
pthreadext->sig = PThreadextSig;
|
||||
|
|
@ -185,7 +275,7 @@ extern void PThreadextFinish(PThreadext pthreadext)
|
|||
status = pthread_mutex_lock(&pthreadextMut);
|
||||
AVER(status == 0);
|
||||
|
||||
if(pthreadext->suspendedScp == NULL) {
|
||||
if(pthreadext->suspendedMFC == NULL) {
|
||||
AVER(RingIsSingle(&pthreadext->threadRing));
|
||||
AVER(RingIsSingle(&pthreadext->idRing));
|
||||
} else {
|
||||
|
|
@ -205,60 +295,12 @@ extern void PThreadextFinish(PThreadext pthreadext)
|
|||
}
|
||||
|
||||
|
||||
/* suspendSignalHandler -- signal handler called when suspending a thread
|
||||
*
|
||||
* See design.mps.pthreadext.impl.suspend-handler
|
||||
*
|
||||
* The interface for determining the sigcontext might be platform specific.
|
||||
*
|
||||
* Handle PTHREADEXT_SIGSUSPEND in the target thread, to suspend it until
|
||||
* receiving PTHREADEXT_SIGRESUME (resume). Note that this is run with both
|
||||
* PTHREADEXT_SIGSUSPEND and PTHREADEXT_SIGRESUME blocked. Having
|
||||
* PTHREADEXT_SIGRESUME blocked prevents a resume before we can finish the
|
||||
* suspend protocol.
|
||||
*/
|
||||
|
||||
static void suspendSignalHandler(int sig, struct sigcontext scp)
|
||||
{
|
||||
sigset_t signal_set;
|
||||
|
||||
AVER(sig == PTHREADEXT_SIGSUSPEND);
|
||||
UNUSED(sig);
|
||||
|
||||
/* Tell caller about the sigcontext. */
|
||||
AVER(suspendingVictim != NULL);
|
||||
suspendingVictim->suspendedScp = &scp;
|
||||
|
||||
/* Block all signals except PTHREADEXT_SIGRESUME while suspended. */
|
||||
sigfillset(&signal_set);
|
||||
sigdelset(&signal_set, PTHREADEXT_SIGRESUME);
|
||||
sem_post(&pthreadextSem);
|
||||
sigsuspend(&signal_set);
|
||||
|
||||
/* Once here, the resume signal handler has run to completion. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* resumeSignalHandler -- signal handler called when resuming a thread
|
||||
*
|
||||
* See design.mps.pthreadext.impl.suspend-handler
|
||||
*/
|
||||
|
||||
static void resumeSignalHandler(int sig)
|
||||
{
|
||||
AVER(sig == PTHREADEXT_SIGRESUME);
|
||||
UNUSED(sig);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* PThreadextSuspend -- suspend a thread
|
||||
*
|
||||
* See design.mps.pthreadext.impl.suspend
|
||||
*/
|
||||
|
||||
Res PThreadextSuspend(PThreadext target, struct sigcontext **contextReturn)
|
||||
Res PThreadextSuspend(PThreadext target, MutatorFaultContext *contextReturn)
|
||||
{
|
||||
Ring node, next;
|
||||
Res res;
|
||||
|
|
@ -266,7 +308,7 @@ Res PThreadextSuspend(PThreadext target, struct sigcontext **contextReturn)
|
|||
|
||||
AVERT(PThreadext, target);
|
||||
AVER(contextReturn != NULL);
|
||||
AVER(target->suspendedScp == NULL); /* multiple suspends illegal */
|
||||
AVER(target->suspendedMFC == NULL); /* multiple suspends illegal */
|
||||
|
||||
/* Serialize access to suspend, makes life easier */
|
||||
status = pthread_mutex_lock(&pthreadextMut);
|
||||
|
|
@ -280,7 +322,7 @@ Res PThreadextSuspend(PThreadext target, struct sigcontext **contextReturn)
|
|||
PThreadext alreadySusp = RING_ELT(PThreadext, threadRing, node);
|
||||
if (alreadySusp->id == target->id) {
|
||||
RingAppend(&alreadySusp->idRing, &target->idRing);
|
||||
target->suspendedScp = alreadySusp->suspendedScp;
|
||||
target->suspendedMFC = alreadySusp->suspendedMFC;
|
||||
goto noteSuspended;
|
||||
}
|
||||
}
|
||||
|
|
@ -302,9 +344,9 @@ Res PThreadextSuspend(PThreadext target, struct sigcontext **contextReturn)
|
|||
}
|
||||
|
||||
noteSuspended:
|
||||
AVER(target->suspendedScp != NULL);
|
||||
AVER(target->suspendedMFC != NULL);
|
||||
RingAppend(&suspendedRing, &target->threadRing);
|
||||
*contextReturn = target->suspendedScp;
|
||||
*contextReturn = target->suspendedMFC;
|
||||
res = ResOK;
|
||||
|
||||
unlock:
|
||||
|
|
@ -316,7 +358,7 @@ unlock:
|
|||
|
||||
|
||||
/* PThreadextResume -- resume a suspended thread
|
||||
*
|
||||
*
|
||||
* See design.mps.pthreadext.impl.resume
|
||||
*/
|
||||
|
||||
|
|
@ -327,7 +369,7 @@ Res PThreadextResume(PThreadext target)
|
|||
|
||||
AVERT(PThreadext, target);
|
||||
AVER(pthreadextModuleInitialized); /* must have been a prior suspend */
|
||||
AVER(target->suspendedScp != NULL);
|
||||
AVER(target->suspendedMFC != NULL);
|
||||
|
||||
/* Serialize access to suspend, makes life easier. */
|
||||
status = pthread_mutex_lock(&pthreadextMut);
|
||||
|
|
@ -353,7 +395,7 @@ Res PThreadextResume(PThreadext target)
|
|||
noteResumed:
|
||||
/* Remove the thread from the suspended ring */
|
||||
RingRemove(&target->threadRing);
|
||||
target->suspendedScp = NULL;
|
||||
target->suspendedMFC = NULL;
|
||||
res = ResOK;
|
||||
|
||||
unlock:
|
||||
|
|
|
|||
|
|
@ -26,13 +26,13 @@ typedef struct PThreadextStruct *PThreadext;
|
|||
|
||||
/* PThreadextStruct -- structure definition
|
||||
*
|
||||
* Should be embedded in a client structure
|
||||
* Should be embedded in a client structure
|
||||
*/
|
||||
|
||||
typedef struct PThreadextStruct {
|
||||
Sig sig; /* design.mps.sig */
|
||||
pthread_t id; /* Thread ID */
|
||||
struct sigcontext *suspendedScp; /* sigcontext if suspended */
|
||||
MutatorFaultContext suspendedMFC; /* context if suspended */
|
||||
RingStruct threadRing; /* ring of suspended threads */
|
||||
RingStruct idRing; /* duplicate suspensions for id */
|
||||
} PThreadextStruct;
|
||||
|
|
@ -56,8 +56,8 @@ extern void PThreadextFinish(PThreadext pthreadext);
|
|||
|
||||
/* PThreadextSuspend -- Suspend a pthreadext and return its context. */
|
||||
|
||||
extern Res PThreadextSuspend(PThreadext pthreadext,
|
||||
struct sigcontext **contextReturn);
|
||||
extern Res PThreadextSuspend(PThreadext pthreadext,
|
||||
MutatorFaultContext *contextReturn);
|
||||
|
||||
|
||||
/* PThreadextResume -- Resume a suspended pthreadext */
|
||||
|
|
|
|||
58
mps/code/ssfri3.c
Normal file
58
mps/code/ssfri3.c
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/* impl.c.ssfri3: FREEBSD/INTEL STACK SCANNING
|
||||
*
|
||||
* $HopeName: MMsrc!sslii3.c(trunk.1) $
|
||||
* Copyright (C) 1999. Harlequin Group plc. All rights reserved.
|
||||
*
|
||||
* This scans the stack and fixes the registers which may contain
|
||||
* roots. See design.mps.thread-manager
|
||||
*
|
||||
* The registers edi, esi, ebx are the registers defined to be preserved
|
||||
* across function calls and therefore may contain roots.
|
||||
* These are pushed on the stack for scanning.
|
||||
*
|
||||
* SOURCES
|
||||
*
|
||||
* .source.callees.saves: Set of callee-saved registers taken from
|
||||
* CALL_USED_REGISTERS in <gcc-sources>/config/i386/i386.h.
|
||||
*
|
||||
* ASSUMPTIONS
|
||||
*
|
||||
* .assume.align: The stack pointer is assumed to be aligned on a word
|
||||
* boundary.
|
||||
*
|
||||
* .assume.asm.stack: The compiler must not do wacky things with the
|
||||
* stack pointer around a call since we need to ensure that the
|
||||
* callee-save regs are visible during TraceScanArea.
|
||||
*
|
||||
* .assume.asm.order: The volatile modifier should prevent movement
|
||||
* of code, which might break .assume.asm.stack.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "mpm.h"
|
||||
|
||||
SRCID(ssfri3, "$HopeName: MMsrc!sslii3.c(trunk.1) $");
|
||||
|
||||
/* .assume.asm.order */
|
||||
#define ASMV(x) __asm__ volatile (x)
|
||||
|
||||
|
||||
Res StackScan(ScanState ss, Addr *stackBot)
|
||||
{
|
||||
Addr *stackTop;
|
||||
Res res;
|
||||
|
||||
/* .assume.asm.stack */
|
||||
ASMV("push %ebx"); /* These registers are callee-saved */
|
||||
ASMV("push %esi"); /* and so may contain roots. They are pushed */
|
||||
ASMV("push %edi"); /* for scanning. See .source.callees.saves. */
|
||||
ASMV("mov %%esp, %0" : "=r" (stackTop) :); /* stackTop = esp */
|
||||
|
||||
AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */
|
||||
res = TraceScanArea(ss, stackTop, stackBot);
|
||||
|
||||
ASMV("add $12, %esp"); /* pop 3 regs to restore the stack pointer */
|
||||
|
||||
return res;
|
||||
}
|
||||
303
mps/code/thfri4.c
Normal file
303
mps/code/thfri4.c
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
/* impl.c.thfri3: Threads Manager for Intel x86 systems on FreeBSD
|
||||
*
|
||||
* $HopeName: MMsrc!thlii4.c(trunk.2) $
|
||||
* Copyright (C) 2000 Harlequin Limited. All rights reserved.
|
||||
*
|
||||
* .purpose: This is a pthreads implementation of the threads manager.
|
||||
* This implements impl.h.th.
|
||||
*
|
||||
* .design: See design.mps.thread-manager.
|
||||
*
|
||||
* .thread.id: The thread id is used to identify the current thread.
|
||||
*
|
||||
* ASSUMPTIONS
|
||||
*
|
||||
* .error.resume: PThreadextResume is assumed to succeed unless the thread
|
||||
* has been destroyed.
|
||||
* .error.suspend: PThreadextSuspend is assumed to succeed unless the thread
|
||||
* has been destroyed. In this case, the suspend context is set to NULL;
|
||||
*
|
||||
* .stack.full-descend: assumes full descending stack.
|
||||
* i.e. stack pointer points to the last allocated location;
|
||||
* stack grows downwards.
|
||||
*
|
||||
* .stack.below-bottom: it's legal for the stack pointer to be at a
|
||||
* higher address than the registered bottom of stack. This might
|
||||
* happen if the stack of another thread doesn't contain any frames
|
||||
* belonging to the client language. In this case, the stack should
|
||||
* not be scanned.
|
||||
*
|
||||
* .stack.align: assume roots on the stack are always word-aligned,
|
||||
* but don't assume that the stack pointer is necessarily
|
||||
* word-aligned at the time of reading the context of another thread.
|
||||
*
|
||||
* .sp: The stack pointer in the context is ESP.
|
||||
* .context.regroots: The root regs are EDI, ESI, EBX, EDX, ECX, EAX are
|
||||
* assumed to be recorded in the context at pointer-aligned boundaries.
|
||||
*/
|
||||
|
||||
#include "prmcfr.h"
|
||||
#include "mpm.h"
|
||||
|
||||
#if !defined(MPS_OS_FR) || !defined(MPS_ARCH_I4)
|
||||
#error "Compiling thfri4 when MPS_OS_FR or MPS_ARCH_I4 not defined."
|
||||
#endif
|
||||
|
||||
#include <pthread.h>
|
||||
#include "pthrdext.h"
|
||||
|
||||
SRCID(thfri4, "$HopeName: MMsrc!thlii4.c(trunk.2) $");
|
||||
|
||||
|
||||
/* ThreadStruct -- thread desriptor */
|
||||
|
||||
typedef struct ThreadStruct { /* PThreads thread structure */
|
||||
Sig sig; /* design.mps.sig */
|
||||
Serial serial; /* from arena->threadSerial */
|
||||
Arena arena; /* owning arena */
|
||||
RingStruct arenaRing; /* threads attached to arena */
|
||||
PThreadextStruct thrextStruct; /* PThreads extension */
|
||||
pthread_t id; /* Pthread object of thread */
|
||||
MutatorFaultContext mfc; /* Context if thread is suspended */
|
||||
} ThreadStruct;
|
||||
|
||||
|
||||
/* ThreadCheck -- check a thread */
|
||||
|
||||
Bool ThreadCheck(Thread thread)
|
||||
{
|
||||
CHECKS(Thread, thread);
|
||||
CHECKU(Arena, thread->arena);
|
||||
CHECKL(thread->serial < thread->arena->threadSerial);
|
||||
CHECKL(RingCheck(&thread->arenaRing));
|
||||
CHECKD(PThreadext, &thread->thrextStruct);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool ThreadCheckSimple(Thread thread)
|
||||
{
|
||||
CHECKS(Thread, thread);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRegister -- register a thread with an arena */
|
||||
|
||||
Res ThreadRegister(Thread *threadReturn, Arena arena)
|
||||
{
|
||||
Res res;
|
||||
Thread thread;
|
||||
void *p;
|
||||
|
||||
AVER(threadReturn != NULL);
|
||||
AVERT(Arena, arena);
|
||||
|
||||
res = ControlAlloc(&p, arena, sizeof(ThreadStruct),
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
thread = (Thread)p;
|
||||
|
||||
thread->id = pthread_self();
|
||||
|
||||
RingInit(&thread->arenaRing);
|
||||
|
||||
thread->sig = ThreadSig;
|
||||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->arena = arena;
|
||||
thread->mfc = NULL;
|
||||
|
||||
PThreadextInit(&thread->thrextStruct, thread->id);
|
||||
|
||||
AVERT(Thread, thread);
|
||||
|
||||
RingAppend(ArenaThreadRing(arena), &thread->arenaRing);
|
||||
|
||||
*threadReturn = thread;
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadDeregister -- deregister a thread from an arena */
|
||||
|
||||
void ThreadDeregister(Thread thread, Arena arena)
|
||||
{
|
||||
AVERT(Thread, thread);
|
||||
AVERT(Arena, arena);
|
||||
|
||||
RingRemove(&thread->arenaRing);
|
||||
|
||||
thread->sig = SigInvalid;
|
||||
|
||||
RingFinish(&thread->arenaRing);
|
||||
|
||||
PThreadextFinish(&thread->thrextStruct);
|
||||
|
||||
ControlFree(arena, thread, sizeof(ThreadStruct));
|
||||
}
|
||||
|
||||
|
||||
/* mapThreadRing -- map over threads on ring calling a function on each one
|
||||
* except the current thread
|
||||
*/
|
||||
|
||||
static void mapThreadRing(Ring threadRing, void (*func)(Thread))
|
||||
{
|
||||
Ring node, next;
|
||||
pthread_t self;
|
||||
|
||||
AVERT(Ring, threadRing);
|
||||
|
||||
self = pthread_self();
|
||||
RING_FOR(node, threadRing, next) {
|
||||
Thread thread = RING_ELT(Thread, arenaRing, node);
|
||||
AVERT(Thread, thread);
|
||||
if(! pthread_equal(self, thread->id)) /* .thread.id */
|
||||
(*func)(thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingSuspend -- suspend all threads on a ring, expect the current one */
|
||||
|
||||
|
||||
static void threadSuspend(Thread thread)
|
||||
{
|
||||
/* .error.suspend */
|
||||
/* In the error case (PThreadextSuspend returning ResFAIL), we */
|
||||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
Res res;
|
||||
res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc);
|
||||
if(res != ResOK)
|
||||
thread->mfc = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ThreadRingSuspend(Ring threadRing)
|
||||
{
|
||||
mapThreadRing(threadRing, threadSuspend);
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingResume -- resume all threads on a ring (expect the current one) */
|
||||
|
||||
|
||||
static void threadResume(Thread thread)
|
||||
{
|
||||
/* .error.resume */
|
||||
/* If the previous suspend failed (thread->mfc == NULL), */
|
||||
/* or in the error case (PThreadextResume returning ResFAIL), */
|
||||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
if(thread->mfc != NULL) {
|
||||
(void)PThreadextResume(&thread->thrextStruct);
|
||||
thread->mfc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadRingResume(Ring threadRing)
|
||||
{
|
||||
mapThreadRing(threadRing, threadResume);
|
||||
}
|
||||
|
||||
|
||||
/* ThreadRingThread -- return the thread at the given ring element */
|
||||
|
||||
Thread ThreadRingThread(Ring threadRing)
|
||||
{
|
||||
Thread thread;
|
||||
AVERT(Ring, threadRing);
|
||||
thread = RING_ELT(Thread, arenaRing, threadRing);
|
||||
AVERT(Thread, thread);
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadArena -- get the arena of a thread
|
||||
*
|
||||
* Must be thread-safe. See design.mps.interface.c.thread-safety.
|
||||
*/
|
||||
|
||||
Arena ThreadArena(Thread thread)
|
||||
{
|
||||
/* Can't check thread as that would not be thread-safe. */
|
||||
return thread->arena;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadScan -- scan the state of a thread (stack and regs) */
|
||||
|
||||
Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
||||
{
|
||||
pthread_t self;
|
||||
Res res;
|
||||
|
||||
AVERT(Thread, thread);
|
||||
self = pthread_self();
|
||||
if(pthread_equal(self, thread->id)) {
|
||||
/* scan this thread's stack */
|
||||
res = StackScan(ss, stackBot);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
} else {
|
||||
MutatorFaultContext mfc;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
|
||||
mfc = thread->mfc;
|
||||
if(mfc == NULL) {
|
||||
/* .error.suspend */
|
||||
/* We assume that the thread must have been destroyed. */
|
||||
/* We ignore the situation by returning immediately. */
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
stackPtr = (Addr)mfc->ucontext->uc_mcontext.mc_esp; /* .i3.sp */
|
||||
/* .stack.align */
|
||||
stackBase = (Addr *)AddrAlignUp(stackPtr, sizeof(Addr));
|
||||
stackLimit = (Addr *)stackBot;
|
||||
if (stackBase >= stackLimit)
|
||||
return ResOK; /* .stack.below-bottom */
|
||||
|
||||
/* scan stack inclusive of current sp and exclusive of
|
||||
* stackBot (.stack.full-descend)
|
||||
*/
|
||||
res = TraceScanAreaTagged(ss, stackBase, stackLimit);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
||||
/* (.context.regroots)
|
||||
* This scans the root registers (.context.regroots). It also
|
||||
* unecessarily scans the rest of the context. The optimisation
|
||||
* to scan only relevent parts would be machine dependent.
|
||||
*/
|
||||
res = TraceScanAreaTagged(ss, (Addr *)mfc->ucontext,
|
||||
(Addr *)((char *)mfc->ucontext + sizeof(*(mfc->ucontext))));
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
}
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* ThreadDescribe -- describe a thread */
|
||||
|
||||
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
res = WriteF(stream,
|
||||
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
" arena $P ($U)\n",
|
||||
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
|
||||
" id $U\n", (WriteFU)thread->id,
|
||||
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
NULL);
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
||||
return ResOK;
|
||||
}
|
||||
|
|
@ -21,14 +21,14 @@
|
|||
* i.e. stack pointer points to the last allocated location;
|
||||
* stack grows downwards.
|
||||
*
|
||||
* .stack.below-bottom: it's legal for the stack pointer to be at a
|
||||
* higher address than the registered bottom of stack. This might
|
||||
* happen if the stack of another thread doesn't contain any frames
|
||||
* .stack.below-bottom: it's legal for the stack pointer to be at a
|
||||
* higher address than the registered bottom of stack. This might
|
||||
* happen if the stack of another thread doesn't contain any frames
|
||||
* belonging to the client language. In this case, the stack should
|
||||
* not be scanned.
|
||||
*
|
||||
* .stack.align: assume roots on the stack are always word-aligned,
|
||||
* but don't assume that the stack pointer is necessarily
|
||||
* but don't assume that the stack pointer is necessarily
|
||||
* word-aligned at the time of reading the context of another thread.
|
||||
*
|
||||
* .sp: The stack pointer in the context is ESP.
|
||||
|
|
@ -58,7 +58,7 @@ typedef struct ThreadStruct { /* PThreads thread structure */
|
|||
RingStruct arenaRing; /* threads attached to arena */
|
||||
PThreadextStruct thrextStruct; /* PThreads extension */
|
||||
pthread_t id; /* Pthread object of thread */
|
||||
struct sigcontext *scpSusp; /* Context if thread is suspended */
|
||||
MutatorFaultContext mfc; /* Context if thread is suspended */
|
||||
} ThreadStruct;
|
||||
|
||||
|
||||
|
|
@ -92,9 +92,9 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
AVER(threadReturn != NULL);
|
||||
AVERT(Arena, arena);
|
||||
|
||||
res = ControlAlloc(&p, arena, sizeof(ThreadStruct),
|
||||
res = ControlAlloc(&p, arena, sizeof(ThreadStruct),
|
||||
/* withReservoirPermit */ FALSE);
|
||||
if(res != ResOK)
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
thread = (Thread)p;
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ Res ThreadRegister(Thread *threadReturn, Arena arena)
|
|||
thread->serial = arena->threadSerial;
|
||||
++arena->threadSerial;
|
||||
thread->arena = arena;
|
||||
thread->scpSusp = NULL;
|
||||
thread->mfc = NULL;
|
||||
|
||||
PThreadextInit(&thread->thrextStruct, thread->id);
|
||||
|
||||
|
|
@ -169,9 +169,9 @@ static void threadSuspend(Thread thread)
|
|||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
Res res;
|
||||
res = PThreadextSuspend(&thread->thrextStruct, &thread->scpSusp);
|
||||
res = PThreadextSuspend(&thread->thrextStruct, &thread->mfc);
|
||||
if(res != ResOK)
|
||||
thread->scpSusp = NULL;
|
||||
thread->mfc = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -188,13 +188,13 @@ void ThreadRingSuspend(Ring threadRing)
|
|||
static void threadResume(Thread thread)
|
||||
{
|
||||
/* .error.resume */
|
||||
/* If the previous suspend failed (thread->scpSusp == NULL), */
|
||||
/* If the previous suspend failed (thread->mfc == NULL), */
|
||||
/* or in the error case (PThreadextResume returning ResFAIL), */
|
||||
/* assume the thread has been destroyed. */
|
||||
/* In which case we simply continue. */
|
||||
if(thread->scpSusp != NULL) {
|
||||
if(thread->mfc != NULL) {
|
||||
(void)PThreadextResume(&thread->thrextStruct);
|
||||
thread->scpSusp = NULL;
|
||||
thread->mfc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
struct sigcontext *scp;
|
||||
Addr *stackBase, *stackLimit, stackPtr;
|
||||
|
||||
scp = thread->scpSusp;
|
||||
scp = thread->mfc->scp;
|
||||
if(scp == NULL) {
|
||||
/* .error.suspend */
|
||||
/* We assume that the thread must have been destroyed. */
|
||||
|
|
@ -288,15 +288,15 @@ Res ThreadScan(ScanState ss, Thread thread, void *stackBot)
|
|||
Res ThreadDescribe(Thread thread, mps_lib_FILE *stream)
|
||||
{
|
||||
Res res;
|
||||
|
||||
|
||||
res = WriteF(stream,
|
||||
"Thread $P ($U) {\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
" arena $P ($U)\n",
|
||||
" arena $P ($U)\n",
|
||||
(WriteFP)thread->arena, (WriteFU)thread->arena->serial,
|
||||
" id $U\n", (WriteFU)thread->id,
|
||||
"} Thread $P ($U)\n", (WriteFP)thread, (WriteFU)thread->serial,
|
||||
NULL);
|
||||
if(res != ResOK)
|
||||
if(res != ResOK)
|
||||
return res;
|
||||
|
||||
return ResOK;
|
||||
|
|
|
|||
278
mps/code/vmfr.c
Normal file
278
mps/code/vmfr.c
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/* impl.c.vmfr: VIRTUAL MEMORY MAPPING FOR FreeBSD
|
||||
*
|
||||
* $HopeName: MMsrc!vmli.c(trunk.7) $
|
||||
* Copyright (C) 2000 Harlequin Limited. All rights reserved.
|
||||
*
|
||||
* .purpose: This is the implementation of the virtual memory mapping
|
||||
* interface (vm.h) for FreeBSD. It was created by copying vmli.c (the
|
||||
* DIGITAL UNIX implementation) as that seemed to be closest.
|
||||
*
|
||||
* .design: See design.mps.vm. .design.freebsd: mmap(2) is used to
|
||||
* reserve address space by creating a mapping with page access none.
|
||||
* mmap(2) is used to map pages onto store by creating a copy-on-write
|
||||
* (MAP_PRIVATE) mapping with the flag MAP_ANON.
|
||||
*
|
||||
* .assume.not-last: The implementation of VMCreate assumes that
|
||||
* mmap() will not choose a region which contains the last page
|
||||
* in the address space, so that the limit of the mapped area
|
||||
* is representable.
|
||||
*
|
||||
* .assume.mmap.err: ENOMEM is the only error we really expect to
|
||||
* get from mmap. The others are either caused by invalid params
|
||||
* or features we don't use. See mmap(2) for details.
|
||||
*
|
||||
* .remap: Possibly this should use mremap to reduce the number of
|
||||
* distinct mappings. According to our current testing, it doesn't
|
||||
* seem to be a problem.
|
||||
*/
|
||||
|
||||
/* for mmap(2), munmap(2) */
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* for errno(2) */
|
||||
#include <errno.h>
|
||||
|
||||
/* for getpagesize(3) */
|
||||
#include <unistd.h>
|
||||
|
||||
#include "mpm.h"
|
||||
|
||||
|
||||
#ifndef MPS_OS_FR
|
||||
#error "vmfr.c is FreeBSD specific, but MPS_OS_FR is not set"
|
||||
#endif
|
||||
|
||||
SRCID(vmfr, "$HopeName: MMsrc!vmli.c(trunk.7) $");
|
||||
|
||||
|
||||
/* VMStruct -- virtual memory structure */
|
||||
|
||||
#define VMSig ((Sig)0x519B3999) /* SIGnature VM */
|
||||
|
||||
typedef struct VMStruct {
|
||||
Sig sig; /* design.mps.sig */
|
||||
Align align; /* page size */
|
||||
Addr base, limit; /* boundaries of reserved space */
|
||||
Size reserved; /* total reserved address space */
|
||||
Size mapped; /* total mapped memory */
|
||||
} VMStruct;
|
||||
|
||||
|
||||
/* VMAlign -- return page size */
|
||||
|
||||
Align VMAlign(VM vm)
|
||||
{
|
||||
return vm->align;
|
||||
}
|
||||
|
||||
|
||||
/* VMCheck -- check a VM */
|
||||
|
||||
Bool VMCheck(VM vm)
|
||||
{
|
||||
CHECKS(VM, vm);
|
||||
CHECKL(vm->base != 0);
|
||||
CHECKL(vm->limit != 0);
|
||||
CHECKL(vm->base < vm->limit);
|
||||
CHECKL(vm->mapped <= vm->reserved);
|
||||
CHECKL(SizeIsP2(vm->align));
|
||||
CHECKL(AddrIsAligned(vm->base, vm->align));
|
||||
CHECKL(AddrIsAligned(vm->limit, vm->align));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* VMCreate -- reserve some virtual address space, and create a VM structure */
|
||||
|
||||
Res VMCreate(VM *vmReturn, Size size)
|
||||
{
|
||||
Align align;
|
||||
VM vm;
|
||||
int pagesize;
|
||||
void *addr;
|
||||
Res res;
|
||||
|
||||
AVER(vmReturn != NULL);
|
||||
|
||||
/* Find out the page size from the OS */
|
||||
pagesize = getpagesize();
|
||||
/* check the actual returned pagesize will fit in an object of */
|
||||
/* type Align. */
|
||||
AVER(pagesize > 0);
|
||||
AVER((unsigned long)pagesize <= (unsigned long)(Align)-1);
|
||||
/* Note implicit conversion from "int" to "Align". */
|
||||
align = pagesize;
|
||||
AVER(SizeIsP2(align));
|
||||
size = SizeAlignUp(size, align);
|
||||
if((size == 0) || (size > (Size)(size_t)-1))
|
||||
return ResRESOURCE;
|
||||
|
||||
/* Map in a page to store the descriptor on. */
|
||||
addr = mmap(0, (size_t)SizeAlignUp(sizeof(VMStruct), align),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_ANON | MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if(addr == MAP_FAILED) {
|
||||
int e = errno;
|
||||
AVER(e == ENOMEM); /* .assume.mmap.err */
|
||||
return ResMEMORY;
|
||||
}
|
||||
vm = (VM)addr;
|
||||
|
||||
vm->align = align;
|
||||
|
||||
/* See .assume.not-last. */
|
||||
addr = mmap(0, (size_t)size,
|
||||
PROT_NONE, MAP_ANON | MAP_PRIVATE,
|
||||
-1, 0);
|
||||
if(addr == MAP_FAILED) {
|
||||
int e = errno;
|
||||
AVER(e == ENOMEM); /* .assume.mmap.err */
|
||||
res = ResRESOURCE;
|
||||
goto failReserve;
|
||||
}
|
||||
|
||||
vm->base = (Addr)addr;
|
||||
vm->limit = AddrAdd(vm->base, size);
|
||||
vm->reserved = size;
|
||||
vm->mapped = (Size)0;
|
||||
|
||||
vm->sig = VMSig;
|
||||
|
||||
AVERT(VM, vm);
|
||||
|
||||
EVENT_PAA(VMCreate, vm, vm->base, vm->limit);
|
||||
|
||||
*vmReturn = vm;
|
||||
return ResOK;
|
||||
|
||||
failReserve:
|
||||
(void)munmap((void *)vm, (size_t)SizeAlignUp(sizeof(VMStruct), align));
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* VMDestroy -- release all address space and destroy VM structure */
|
||||
|
||||
void VMDestroy(VM vm)
|
||||
{
|
||||
int r;
|
||||
|
||||
AVERT(VM, vm);
|
||||
AVER(vm->mapped == (Size)0);
|
||||
|
||||
/* This appears to be pretty pointless, since the descriptor */
|
||||
/* page is about to vanish completely. However, munmap might fail */
|
||||
/* for some reason, and this would ensure that it was still */
|
||||
/* discovered if sigs were being checked. */
|
||||
vm->sig = SigInvalid;
|
||||
|
||||
r = munmap((void *)vm->base, (size_t)AddrOffset(vm->base, vm->limit));
|
||||
AVER(r == 0);
|
||||
r = munmap((void *)vm,
|
||||
(size_t)SizeAlignUp(sizeof(VMStruct), vm->align));
|
||||
AVER(r == 0);
|
||||
|
||||
EVENT_P(VMDestroy, vm);
|
||||
}
|
||||
|
||||
|
||||
/* VMBase -- return the base address of the memory reserved */
|
||||
|
||||
Addr VMBase(VM vm)
|
||||
{
|
||||
AVERT(VM, vm);
|
||||
|
||||
return vm->base;
|
||||
}
|
||||
|
||||
|
||||
/* VMLimit -- return the limit address of the memory reserved */
|
||||
|
||||
Addr VMLimit(VM vm)
|
||||
{
|
||||
AVERT(VM, vm);
|
||||
|
||||
return vm->limit;
|
||||
}
|
||||
|
||||
|
||||
/* VMReserved -- return the amount of memory reserved */
|
||||
|
||||
Size VMReserved(VM vm)
|
||||
{
|
||||
AVERT(VM, vm);
|
||||
|
||||
return vm->reserved;
|
||||
}
|
||||
|
||||
|
||||
/* VMMapped -- return the amount of memory actually mapped */
|
||||
|
||||
Size VMMapped(VM vm)
|
||||
{
|
||||
AVERT(VM, vm);
|
||||
|
||||
return vm->mapped;
|
||||
}
|
||||
|
||||
|
||||
/* VMMap -- map the given range of memory */
|
||||
|
||||
Res VMMap(VM vm, Addr base, Addr limit)
|
||||
{
|
||||
Size size;
|
||||
|
||||
AVERT(VM, vm);
|
||||
AVER(sizeof(void *) == sizeof(Addr));
|
||||
AVER(base < limit);
|
||||
AVER(base >= vm->base);
|
||||
AVER(limit <= vm->limit);
|
||||
AVER(AddrIsAligned(base, vm->align));
|
||||
AVER(AddrIsAligned(limit, vm->align));
|
||||
|
||||
size = AddrOffset(base, limit);
|
||||
|
||||
if(mmap((void *)base, (size_t)size,
|
||||
PROT_READ | PROT_WRITE | PROT_EXEC,
|
||||
MAP_ANON | MAP_PRIVATE | MAP_FIXED,
|
||||
-1, 0)
|
||||
== MAP_FAILED) {
|
||||
AVER(errno == ENOMEM); /* .assume.mmap.err */
|
||||
return ResMEMORY;
|
||||
}
|
||||
|
||||
vm->mapped += size;
|
||||
|
||||
EVENT_PAA(VMMap, vm, base, limit);
|
||||
return ResOK;
|
||||
}
|
||||
|
||||
|
||||
/* VMUnmap -- unmap the given range of memory */
|
||||
|
||||
void VMUnmap(VM vm, Addr base, Addr limit)
|
||||
{
|
||||
Size size;
|
||||
void *addr;
|
||||
|
||||
AVERT(VM, vm);
|
||||
AVER(base < limit);
|
||||
AVER(base >= vm->base);
|
||||
AVER(limit <= vm->limit);
|
||||
AVER(AddrIsAligned(base, vm->align));
|
||||
AVER(AddrIsAligned(limit, vm->align));
|
||||
|
||||
size = AddrOffset(base, limit);
|
||||
|
||||
/* see design.mps.vmo1.fun.unmap.offset */
|
||||
addr = mmap((void *)base, (size_t)size,
|
||||
PROT_NONE, MAP_ANON | MAP_PRIVATE | MAP_FIXED,
|
||||
-1, 0);
|
||||
AVER(addr == (void *)base);
|
||||
|
||||
vm->mapped -= size;
|
||||
|
||||
EVENT_PAA(VMUnmap, vm, base, limit);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue