From be8a839d8344942f7e4ba8d22d2e1bdc63d3e002 Mon Sep 17 00:00:00 2001 From: David Lovemore Date: Thu, 9 Aug 2012 16:05:08 +0100 Subject: [PATCH] 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. + */