From 43c30eefdbf68734969779a593d1e83ed26d3b7e Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Thu, 9 Aug 2012 16:05:08 +0100 Subject: [PATCH 1/2] Made 64 bit linux port lii6gc. i've renamed thlii4.c to thli.c. Copied from Perforce Change: 178876 ServerID: perforce.ravenbrook.com --- mps/code/lii4gc.gmk | 2 +- mps/code/lii6gc.gmk | 71 +++++++++ mps/code/mpstd.h | 17 +++ mps/code/prmci6li.c | 123 ++++++++++++++++ mps/code/protlii6.c | 180 +++++++++++++++++++++++ mps/code/ssixi6.c | 19 ++- mps/code/thli.c | 350 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 751 insertions(+), 11 deletions(-) create mode 100644 mps/code/lii6gc.gmk create mode 100644 mps/code/prmci6li.c create mode 100644 mps/code/protlii6.c create mode 100644 mps/code/thli.c diff --git a/mps/code/lii4gc.gmk b/mps/code/lii4gc.gmk index 2eceecb9827..6ed66a21f85 100644 --- a/mps/code/lii4gc.gmk +++ b/mps/code/lii4gc.gmk @@ -5,7 +5,7 @@ PFM = lii4gc -THREADSRC = lockli.c thlii4.c pthrdext.c +THREADSRC = lockli.c thli.c pthrdext.c THREADLIB = -lpthread # _XOPEN_SOURCE is to get the modern POSIX signal handling diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk new file mode 100644 index 00000000000..d072f5f62fd --- /dev/null +++ b/mps/code/lii6gc.gmk @@ -0,0 +1,71 @@ +# lii6gc.gmk: BUILD FOR LINUX/x64/GCC PLATFORM +# +# $Id$ +# Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + +PFM = lii6gc + +THREADSRC = lockli.c thli.c pthrdext.c +THREADLIB = -lpthread + +# _XOPEN_SOURCE is to get the modern POSIX signal handling +# _GNU_SOURCE is to get register numbers in prmci3li.c +PFMDEFS = -D_REENTRANT -D_XOPEN_SOURCE=500 -D_GNU_SOURCE + +MPMPF = ${THREADSRC} vmix.c \ + protix.c protlii6.c proti6.c prmci6li.c ssixi6.c span.c +SWPF = than.c vmli.c protsw.c prmcan.c ssan.c + +LIBS = -lm ${THREADLIB} + +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 := -pthread $(subst -Wpointer-arith,,$(CFLAGSCOMPILER)) + +include comm.gmk + + +# C. COPYRIGHT AND LICENSE +# +# Copyright (C) 2001-2002 Ravenbrook Limited . +# All rights reserved. This is an open source license. Contact +# Ravenbrook for commercial licensing options. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Redistributions in any form must be accompanied by information on how +# to obtain complete source code for this software and any accompanying +# software that uses this software. The source code must either be +# included in the distribution or be available for no more than the cost +# of distribution plus a nominal fee, and must be freely redistributable +# under reasonable conditions. For an executable file, complete source +# code means the source code for all modules it contains. It does not +# include source code for modules or files that typically accompany the +# major components of the operating system on which the executable file +# runs. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/mps/code/mpstd.h b/mps/code/mpstd.h index 4a8a0875ca3..86b89c836f5 100644 --- a/mps/code/mpstd.h +++ b/mps/code/mpstd.h @@ -470,6 +470,23 @@ #define MPS_WORD_SHIFT 5 #define MPS_PF_ALIGN 4 +/* GCC 4.6.3, gcc -E -dM */ + +#elif defined(__linux__) && defined(__x86_64) && defined(__GNUC__) +#if defined(CONFIG_PF_STRING) && ! defined(CONFIG_PF_LII6GC) +#error "specified CONFIG_PF_... inconsistent with detected lii6gc" +#endif +#define MPS_PF_LII6GC +#define MPS_PF_STRING "lii6gc" +#define MPS_OS_LI +#define MPS_ARCH_I6 +#define MPS_BUILD_GC +#define MPS_T_WORD unsigned long +#define MPS_T_ULONGEST unsigned long +#define MPS_WORD_WIDTH 64 +#define MPS_WORD_SHIFT 6 +#define MPS_PF_ALIGN 8 + /* GCC 2.7.2, gcc -E -dM */ #elif defined(__linux__) && defined(__PPC__) && defined(__GNUC__) diff --git a/mps/code/prmci6li.c b/mps/code/prmci6li.c new file mode 100644 index 00000000000..e81a7cfd750 --- /dev/null +++ b/mps/code/prmci6li.c @@ -0,0 +1,123 @@ +/* prmci6li.c: PROTECTION MUTATOR CONTEXT x64 (LINUX) + * + * $Id$ + * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * + * .purpose: This module implements the part of the protection module + * that decodes the MutatorFaultContext. + * + * + * SOURCES + * + * .source.linux.kernel: Linux kernel source files. + * + * + * ASSUMPTIONS + * + * .assume.regref: The resisters in the context can be modified by + * storing into an MRef pointer. + */ + +#include "prmcix.h" +#include "prmci6.h" + +SRCID(prmci6li, "$Id$"); + + +/* Prmci6AddressHoldingReg -- return an address of a register in a context */ + +MRef Prmci6AddressHoldingReg(MutatorFaultContext mfc, unsigned int regnum) +{ + Word *gregs; + + AVER(regnum <= 15); + AVER(regnum >= 0); + + gregs = (Word *)&mfc->ucontext->uc_mcontext.gregs; + + /* .assume.regref */ + /* The REG_EAX etc. symbols are only present if _GNU_SOURCE is defined. + * Currently this is in lii6gc.gmk in PFMDEFS. */ + switch (regnum) { + case 0: return &gregs[REG_RAX]; + case 1: return &gregs[REG_RCX]; + case 2: return &gregs[REG_RDX]; + case 3: return &gregs[REG_RBX]; + case 4: return &gregs[REG_RSP]; + case 5: return &gregs[REG_RBP]; + case 6: return &gregs[REG_RSI]; + case 7: return &gregs[REG_RDI]; + case 8: return &gregs[REG_R8]; + case 9: return &gregs[REG_R9]; + case 10: return &gregs[REG_R10]; + case 11: return &gregs[REG_R11]; + case 12: return &gregs[REG_R12]; + case 13: return &gregs[REG_R13]; + case 14: return &gregs[REG_R14]; + case 15: return &gregs[REG_R15]; + } + NOTREACHED; + return (MRef)NULL; /* Avoids compiler warning. */ +} + + +/* Prmci3DecodeFaultContext -- decode fault to find faulting address and IP */ + +void Prmci6DecodeFaultContext(MRef *faultmemReturn, + Byte **insvecReturn, + MutatorFaultContext mfc) +{ + /* .source.linux.kernel (linux/arch/x86/mm/fault.c). */ + *faultmemReturn = (MRef)mfc->info->si_addr; + *insvecReturn = (Byte*)mfc->ucontext->uc_mcontext.gregs[REG_RIP]; +} + + +/* Prmci3StepOverIns -- modify context to step over instruction */ + +void Prmci6StepOverIns(MutatorFaultContext mfc, Size inslen) +{ + mfc->ucontext->uc_mcontext.gregs[REG_RIP] += (Word)inslen; +} + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2001-2002 Ravenbrook Limited . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/mps/code/protlii6.c b/mps/code/protlii6.c new file mode 100644 index 00000000000..e149d5269ed --- /dev/null +++ b/mps/code/protlii6.c @@ -0,0 +1,180 @@ +/* protlii6.c: PROTECTION FOR LINUX (x64) + * + * $Id$ + * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * + * SOURCES + * + * .source.linux.kernel: Linux kernel source files. + */ + +#include "prmcix.h" + +#ifndef MPS_OS_LI +#error "protlii6.c is Linux-specific, but MPS_OS_LI is not set" +#endif +#if !defined(MPS_ARCH_I6) +#error "protlii6.c is x64, but MPS_ARCH_I6 is not set" +#endif +#ifndef PROTECTION +#error "protlii6.c implements protection, but PROTECTION is not set" +#endif + +#include +#include +#include +#include +#include + +SRCID(protlii6, "$Id$"); + + + +/* 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 SIGSEGV 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.context: We check si_code for being a memory access + * si_addr gives the fault address. See + * .source.linux.kernel (linux/arch/x86/mm/fault.c). + * + * .sigh.addr: We assume that the OS decodes the address to something + * sensible + */ +/* This is defined here to keep the sources closer to those in protsgix.c + * They can't be merged yet because protsgix doesn't pass the context to + * ArenaAccess */ + +#define PROT_SIGNAL SIGSEGV + +static void sigHandle(int sig, siginfo_t *info, void *context) /* .sigh.args */ +{ + int e; + /* sigset renamed to asigset due to clash with global on Darwin. */ + sigset_t asigset, oldset; + struct sigaction sa; + + AVER(sig == PROT_SIGNAL); + + if(info->si_code == SEGV_ACCERR) { /* .sigh.context */ + AccessSet mode; + Addr base; + ucontext_t *ucontext; + MutatorFaultContextStruct mfContext; + + ucontext = (ucontext_t *)context; + mfContext.ucontext = ucontext; + mfContext.info = info; + + /* on linux we used to be able to tell whether this was a read or a write */ + mode = AccessREAD | AccessWRITE; + + /* We assume that the access is for one word at the address. */ + base = (Addr)info->si_addr; /* .sigh.addr */ + /* 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, &mfContext)) + return; + } + + /* The exception was not handled by any known protection structure, */ + /* so throw it to the previously installed handler. That handler won't */ + /* get an accurate context (the MPS would fail if it were the second in */ + /* line) but it's the best we can do. */ + + e = sigaction(PROT_SIGNAL, &sigNext, &sa); + AVER(e == 0); + sigemptyset(&asigset); + sigaddset(&asigset, PROT_SIGNAL); + e = sigprocmask(SIG_UNBLOCK, &asigset, &oldset); + AVER(e == 0); + kill(getpid(), PROT_SIGNAL); + e = sigprocmask(SIG_SETMASK, &oldset, NULL); + AVER(e == 0); + e = sigaction(PROT_SIGNAL, &sa, NULL); + AVER(e == 0); +} + + +/* ProtSetup -- global protection setup + * + * Under Linux, the global setup involves installing a signal handler + * on SIGSEGV 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(PROT_SIGNAL, &sa, &sigNext); + AVER(result == 0); +} + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2001-2002 Ravenbrook Limited . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/mps/code/ssixi6.c b/mps/code/ssixi6.c index 6732f850b3b..6b425bed804 100644 --- a/mps/code/ssixi6.c +++ b/mps/code/ssixi6.c @@ -1,4 +1,4 @@ -/* ssixi6.c: UNIX/INTEL STACK SCANNING +/* ssixi6.c: UNIX/x64 STACK SCANNING * * $Id$ * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. @@ -49,22 +49,21 @@ SRCID(ssixi6, "$Id$"); Res StackScan(ScanState ss, Addr *stackBot) { + Addr calleeSaveRegs[6]; Addr *stackTop; Res res; - ASMV("push %rbp"); - ASMV("push %rbx"); - ASMV("push %r12"); - ASMV("push %r13"); - ASMV("push %r14"); - ASMV("push %r15"); - ASMV("mov %%rsp, %0" : "=r" (stackTop) :); /* stackTop = esp */ + ASMV("mov %%rbp, %0" : "=m" (calleeSaveRegs[0])); + ASMV("mov %%rbx, %0" : "=m" (calleeSaveRegs[1])); + ASMV("mov %%r12, %0" : "=m" (calleeSaveRegs[2])); + ASMV("mov %%r13, %0" : "=m" (calleeSaveRegs[3])); + ASMV("mov %%r14, %0" : "=m" (calleeSaveRegs[4])); + ASMV("mov %%r15, %0" : "=m" (calleeSaveRegs[5])); + ASMV("mov %%rsp, %0" : "=r" (stackTop) :); /* stackTop = rsp */ AVER(AddrIsAligned((Addr)stackTop, sizeof(Addr))); /* .assume.align */ res = TraceScanArea(ss, stackTop, stackBot); - ASMV("add $48, %rsp"); /* pop 6 regs to restore the stack pointer */ - return res; } diff --git a/mps/code/thli.c b/mps/code/thli.c new file mode 100644 index 00000000000..a486e9ab9b6 --- /dev/null +++ b/mps/code/thli.c @@ -0,0 +1,350 @@ +/* thli.c: Threads Manager for LinuxThreads + * + * $Id$ + * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. + * + * .purpose: This is a pthreads implementation of the threads manager. + * This implements . + * + * .design: See . + * + * .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 uc_stack.ss_sp. + * .context.regroots: The root regs are + * assumed to be recorded in the context at pointer-aligned boundaries. + */ + +#include "prmcix.h" +#include "mpm.h" + +#if !defined(MPS_OS_LI) +#error "Compiling thli when MPS_OS_LI is not defined." +#endif + +#if !(defined(MPS_ARCH_I4) || defined(MPS_ARCH_I6)) +#error "Need to check assumptions for thli.c are true for this architecture" +#endif + +#include +#include "pthrdext.h" + +SRCID(thli, "$Id$"); + + +/* ThreadStruct -- thread desriptor */ + +typedef struct ThreadStruct { /* PThreads thread structure */ + Sig 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 . + */ + +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; + mcontext_t *mc; + 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_stack.ss_sp; /* .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. + */ + mc = &mfc->ucontext->uc_mcontext; + res = TraceScanAreaTagged(ss, (Addr *)mc, + (Addr *)((char *)mc + sizeof(*mc))); + 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; +} + + +/* C. COPYRIGHT AND LICENSE + * + * Copyright (C) 2001-2002 Ravenbrook Limited . + * All rights reserved. This is an open source license. Contact + * Ravenbrook for commercial licensing options. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Redistributions in any form must be accompanied by information on how + * to obtain complete source code for this software and any accompanying + * software that uses this software. The source code must either be + * included in the distribution or be available for no more than the cost + * of distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ From d67ef40046d1839e4d5a63871089dddb4e00376c Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Thu, 9 Aug 2012 16:09:07 +0100 Subject: [PATCH 2/2] Deleted no longer used thlii4.c -- renamed to thli.c Copied from Perforce Change: 178877 ServerID: perforce.ravenbrook.com --- mps/code/thlii4.c | 346 ---------------------------------------------- 1 file changed, 346 deletions(-) delete mode 100644 mps/code/thlii4.c diff --git a/mps/code/thlii4.c b/mps/code/thlii4.c deleted file mode 100644 index 4f96e9c5fb1..00000000000 --- a/mps/code/thlii4.c +++ /dev/null @@ -1,346 +0,0 @@ -/* thlii4.c: Threads Manager for Intel x86 systems with LinuxThreads - * - * $Id$ - * Copyright (c) 2001 Ravenbrook Limited. See end of file for license. - * - * .purpose: This is a pthreads implementation of the threads manager. - * This implements . - * - * .design: See . - * - * .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 "prmcix.h" -#include "mpm.h" - -#if !defined(MPS_OS_LI) || !defined(MPS_ARCH_I4) -#error "Compiling thlii4 when MPS_OS_LI or MPS_ARCH_I4 not defined." -#endif - -#include -#include "pthrdext.h" - -SRCID(thlii4, "$Id$"); - - -/* ThreadStruct -- thread desriptor */ - -typedef struct ThreadStruct { /* PThreads thread structure */ - Sig 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 . - */ - -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; - mcontext_t *mc; - 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_stack.ss_sp; /* .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. - */ - mc = &mfc->ucontext->uc_mcontext; - res = TraceScanAreaTagged(ss, (Addr *)mc, - (Addr *)((char *)mc + sizeof(*mc))); - 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; -} - - -/* C. COPYRIGHT AND LICENSE - * - * Copyright (C) 2001-2002 Ravenbrook Limited . - * All rights reserved. This is an open source license. Contact - * Ravenbrook for commercial licensing options. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * 3. Redistributions in any form must be accompanied by information on how - * to obtain complete source code for this software and any accompanying - * software that uses this software. The source code must either be - * included in the distribution or be available for no more than the cost - * of distribution plus a nominal fee, and must be freely redistributable - * under reasonable conditions. For an executable file, complete source - * code means the source code for all modules it contains. It does not - * include source code for modules or files that typically accompany the - * major components of the operating system on which the executable file - * runs. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */