From d82fc68bde6bbec323f58719d2d4cabda000039d Mon Sep 17 00:00:00 2001 From: Gareth Rees Date: Thu, 13 Oct 2016 21:24:04 +0100 Subject: [PATCH] Use protsgix.c on linux and delete protli.c. Copied from Perforce Change: 192556 ServerID: perforce.ravenbrook.com --- mps/code/lii3gc.gmk | 2 +- mps/code/lii6gc.gmk | 2 +- mps/code/lii6ll.gmk | 2 +- mps/code/mps.c | 4 +- mps/code/protli.c | 180 -------------------------- mps/design/index.txt | 4 +- mps/design/prot.txt | 6 +- mps/design/{protli.txt => protix.txt} | 120 +++++++---------- mps/manual/source/code-index.rst | 1 - mps/manual/source/design/index.rst | 1 + mps/manual/source/design/old.rst | 1 - mps/manual/source/topic/porting.rst | 8 +- 12 files changed, 57 insertions(+), 274 deletions(-) delete mode 100644 mps/code/protli.c rename mps/design/{protli.txt => protix.txt} (63%) diff --git a/mps/code/lii3gc.gmk b/mps/code/lii3gc.gmk index dcddc25f53c..5a0b073ca9f 100644 --- a/mps/code/lii3gc.gmk +++ b/mps/code/lii3gc.gmk @@ -12,7 +12,7 @@ MPMPF = \ prmci3.c \ prmclii3.c \ protix.c \ - protli.c \ + protsgix.c \ pthrdext.c \ span.c \ ssixi3.c \ diff --git a/mps/code/lii6gc.gmk b/mps/code/lii6gc.gmk index 6bbdcc79e83..7c938a24197 100644 --- a/mps/code/lii6gc.gmk +++ b/mps/code/lii6gc.gmk @@ -12,7 +12,7 @@ MPMPF = \ prmci6.c \ prmclii6.c \ protix.c \ - protli.c \ + protsgix.c \ pthrdext.c \ span.c \ ssixi6.c \ diff --git a/mps/code/lii6ll.gmk b/mps/code/lii6ll.gmk index f9cd4d45cb1..9cc8fad72bf 100644 --- a/mps/code/lii6ll.gmk +++ b/mps/code/lii6ll.gmk @@ -12,7 +12,7 @@ MPMPF = \ prmci6.c \ prmclii6.c \ protix.c \ - protli.c \ + protsgix.c \ pthrdext.c \ span.c \ ssixi6.c \ diff --git a/mps/code/mps.c b/mps/code/mps.c index 64e6fe85699..ce116a53e8e 100644 --- a/mps/code/mps.c +++ b/mps/code/mps.c @@ -177,7 +177,7 @@ #include "pthrdext.c" /* Posix thread extensions */ #include "vmix.c" /* Posix virtual memory */ #include "protix.c" /* Posix protection */ -#include "protli.c" /* Linux protection */ +#include "protsgix.c" /* Posix signal handling */ #include "prmci3.c" /* 32-bit Intel mutator context */ #include "prmclii3.c" /* 32-bit Intel for Linux mutator context */ #include "span.c" /* generic stack probe */ @@ -192,7 +192,7 @@ #include "pthrdext.c" /* Posix thread extensions */ #include "vmix.c" /* Posix virtual memory */ #include "protix.c" /* Posix protection */ -#include "protli.c" /* Linux protection */ +#include "protsgix.c" /* Posix signal handling */ #include "prmci6.c" /* 64-bit Intel mutator context */ #include "prmclii6.c" /* 64-bit Intel for Linux mutator context */ #include "span.c" /* generic stack probe */ diff --git a/mps/code/protli.c b/mps/code/protli.c deleted file mode 100644 index e3583e246ed..00000000000 --- a/mps/code/protli.c +++ /dev/null @@ -1,180 +0,0 @@ -/* protli.c: PROTECTION FOR LINUX - * - * $Id$ - * Copyright (c) 2001-2016 Ravenbrook Limited. See end of file for license. - * - * SOURCES - * - * .source.linux.kernel: Linux kernel source files. - */ - -#include "prmcix.h" - -#ifndef MPS_OS_LI -#error "protli.c is Linux-specific, but MPS_OS_LI is not set" -#endif - -#include -#include -#include -#include -#include - -SRCID(protli, "$Id$"); - -#if !defined(MPS_OS_LI) -#error "protli.c is specific to MPS_OS_LI" -#endif - - -/* 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/i386/mm/fault.c and - * 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 *uap) /* .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; - MutatorContextStruct context; - - ucontext = (ucontext_t *)uap; - context.ucontext = ucontext; - context.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, &context)) - 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-2016 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/design/index.txt b/mps/design/index.txt index 66530dc7a63..5433e9a8be8 100644 --- a/mps/design/index.txt +++ b/mps/design/index.txt @@ -87,7 +87,7 @@ poolmvt_ Manual Variable Temporal pool class poolmvff_ Manual Variable First-Fit pool class prmc_ Mutator context prot_ Memory protection -protli_ Linux implementation of protection module +protix_ POSIX implementation of protection module protocol_ Protocol inheritance protsu_ SunOS 4 implementation of protection module pthreadext_ POSIX thread extensions @@ -167,7 +167,7 @@ writef_ The WriteF function .. _poolmvff: poolmvff .. _prmc: prmc .. _prot: prot -.. _protli: protli +.. _protix: protix .. _protocol: protocol .. _protsu: protsu .. _pthreadext: pthreadext diff --git a/mps/design/prot.txt b/mps/design/prot.txt index 2190eb1c3c4..57db7ba3718 100644 --- a/mps/design/prot.txt +++ b/mps/design/prot.txt @@ -133,11 +133,7 @@ mutator context module that support single-stepping of accesses (see design.mps. .. _design.mps.prmc.req.fault.step: prmc#req.fault.step -_`.impl.ix`: POSIX implementation. - -_`.impl.li`: Linux implementation. See design.mps.protli_. - -.. _design.mps.protli: protli +_`.impl.ix`: POSIX implementation. See design.mps.protix_. _`.impl.w3`: Windows implementation. diff --git a/mps/design/protli.txt b/mps/design/protix.txt similarity index 63% rename from mps/design/protli.txt rename to mps/design/protix.txt index d07ee96065e..bcb4f619cf0 100644 --- a/mps/design/protli.txt +++ b/mps/design/protix.txt @@ -1,17 +1,17 @@ .. mode: -*- rst -*- -Linux implementation of protection module +POSIX implementation of protection module ========================================= -:Tag: design.mps.protli +:Tag: design.mps.protix :Author: Tony Mann :Date: 2000-02-03 :Status: incomplete document :Revision: $Id$ :Copyright: See `Copyright and License`_. :Index terms: - pair: Linux; protection interface design - pair: Linux protection interface; design + pair: POSIX; protection interface design + pair: POSIX protection interface; design Introduction @@ -19,9 +19,9 @@ Introduction _`.readership`: Any MPS developer -_`.intro`: This is the design of the Linux implementation of the -protection module. It makes use of various services provided by Linux. -It is intended to work with LinuxThreads. +_`.intro`: This is the design of the POSIX implementation of the +protection module. It makes use of various services provided by POSIX. +It is intended to work with POSIX Threads. Requirements @@ -36,12 +36,13 @@ interface defined in design.mps.prot.if_. Data structures --------------- -_`.data.signext`: This is static. Because that is the only -communications channel available to signal handlers. - -.. note:: - - Write a little more here. +_`.data.signext`: If the SIGSEGV signal is not handled by any MPS +arena, ``sigHandle()`` needs to forward the signal to the next signal +handler in the chain (the signal handler that was installed when the +``ProtSetup()`` was called), by temporarily reinstalling the old +signal handler and calling ``kill()``. The only way to pass the next +signal handler to the current signal handler is via a global variable, +in this case the variable ``sigNext``. Functions @@ -53,19 +54,6 @@ is the function ``sigHandle()``). The previous handler is recorded (in the variable ``sigNext``, see `.data.signext`_) so that it can be reached from ``sigHandle()`` if it fails to handle the fault. -_`.fun.setup.problem`: The problem with this approach is that we can't -honour the wishes of the ``sigvec(2)`` entry for the previous handler -(in terms of masks in particular). - -_`.improve.sigvec`: What if when we want to pass on the signal instead -of calling the handler we call ``sigvec()`` with the old entry and use -``kill()`` to send the signal to ourselves and then restore our -handler using ``sigvec()`` again? - -.. note:: - - Need more detail and analysis here. - _`.fun.set`: ``ProtSet()`` uses ``mprotect()`` to adjust the protection for pages. @@ -97,7 +85,7 @@ Threads ------- _`.threads`: The design must operate in a multi-threaded environment -(with LinuxThreads) and cooperate with the Linux support for locks +(with POSIX Threads) and cooperate with the POSIX support for locks (see design.mps.lock_) and the thread suspension mechanism (see design.mps.pthreadext_ ). @@ -112,14 +100,13 @@ simply nest at top of stack. .. _design.mps.pthreadext.req.suspend.protection: pthreadext#req.suspend.protection -_`.threads.async`: POSIX (and hence Linux) imposes some restrictions -on signal handler functions (see -design.mps.pthreadext.anal.signal.safety_). Basically the rules say the -behaviour of almost all POSIX functions inside a signal handler is -undefined, except for a handful of functions which are known to be -"async-signal safe". However, if it's known that the signal didn't -happen inside a POSIX function, then it is safe to call arbitrary -POSIX functions inside a handler. +_`.threads.async`: POSIX imposes some restrictions on signal handler +functions (see design.mps.pthreadext.anal.signal.safety_). Basically +the rules say the behaviour of almost all POSIX functions inside a +signal handler is undefined, except for a handful of functions which +are known to be "async-signal safe". However, if it's known that the +signal didn't happen inside a POSIX function, then it is safe to call +arbitrary POSIX functions inside a handler. .. _design.mps.pthreadext.anal.signal.safety: pthreadext#anal.signal.safety @@ -136,55 +123,34 @@ it's OK to call arbitrary POSIX functions inside the handler. _`.threads.async.other`: If the signal handler is invoked for some other reason (that is, one we are not prepared to handle) then there -is less we can say about what might have caused the SEGV. In general -it is not safe to call arbitrary POSIX functions inside the handler in -this case. +is less we can say about what might have caused the SIGSEGV. In +general it is not safe to call arbitrary POSIX functions inside the +handler in this case. _`.threads.async.choice`: The signal handler calls ``ArenaAccess()`` to determine whether the segmentation fault was the result of an MPS -access. ArenaAccess will claim various MPS locks (that is, the arena -ring lock and some arena locks). The code calls no other POSIX +access. ``ArenaAccess()`` will claim various MPS locks (that is, the +arena ring lock and some arena locks). The code calls no other POSIX functions in the case where the segmentation fault is not an MPS access. The locks are implemented as mutexes and are claimed by calling ``pthread_mutex_lock()``, which is not defined to be async-signal safe. -_`.threads.async.choice.ok`: However, despite the fact that PThreads -documentation doesn't define the behaviour of ``pthread_mutex_lock()`` -in these circumstances, we expect the LinuxThreads implementation will -be well-behaved unless the segmentation fault occurs while while in -the process of locking or unlocking one of the MPS locks (see -`.threads.async.linux-mutex`_). But we can assume that a segmentation -fault will not happen then (because we use the locks correctly, and -generally must assume that they work). Hence we conclude that it is OK -to call ``ArenaAccess()`` directly from the signal handler. - -_`.threads.async.linux-mutex`: A study of the LinuxThreads source code -reveals that mutex lock and unlock functions are implemented as a -spinlock (using a locked compare-and-exchange instruction) with a -backup suspension mechanism using ``sigsuspend()``. On locking, the -spinlock code performs a loop which examines the state of the lock, -and then atomically tests that the state is unchanged while attempting -to modify it. This part of the code is reentrant (and hence -async-signal safe). Eventually, when locking, the spinlock code may -need to block, in which case it calls ``sigsuspend()``, waiting for -the manager thread to unblock it. The unlocking code is similar, -except that this code may need to release another thread, in which -case it calls ``kill()``. The functions ``sigsuspend()`` and -``kill()`` are both defined to be async-signal safe by POSIX. In -summary, the mutex locking functions use primitives which are entirely -async-signal safe. They perform side-effects which modify the fields -of the lock structure only. This code may be safely invoked inside a -signal handler unless the interrupted function is in the process of -manipulating the fields of that lock structure. +_`.threads.async.choice.ok`: However, despite the fact that POSIX +Threads documentation doesn't define the behaviour of +``pthread_mutex_lock()`` in these circumstances, we expect the POSIX +Threads implementation will be well-behaved unless the segmentation +fault occurs while while in the process of locking or unlocking one of +the MPS locks. But we can assume that a segmentation fault will not +happen then (because we use the locks correctly, and generally must +assume that they work). Hence we conclude that it is OK to call +``ArenaAccess()`` directly from the signal handler. _`.threads.async.improve`: In future it would be preferable to not -have to assume reentrant mutex locking and unlocking functions. By -making the assumption we also assume that the implementation of -mutexes in LinuxThreads will not be completely re-designed in future -(which is not wise for the long term). An alternative approach would -be necessary anyway when supporting another platform which doesn't -offer reentrant locks (if such a platform does exist). +have to assume reentrant mutex locking and unlocking functions. An +alternative approach would be necessary anyway when supporting another +platform which doesn't offer reentrant locks (if such a platform does +exist). _`.threads.async.improve.how`: We could avoid the assumption if we had a means of testing whether an address lies within an arena chunk @@ -198,7 +164,7 @@ datastructure. _`.threads.sig-stack`: We do not handle signals on a separate signal stack. Separate signal stacks apparently don't work properly with -Pthreads. +POSIX Threads. Document History @@ -210,6 +176,8 @@ Document History - 2013-05-23 GDR_ Converted to reStructuredText. +- 2016-10-13 GDR_ Generalise to POSIX, not just Linux. + .. _RB: http://www.ravenbrook.com/consultants/rb/ .. _GDR: http://www.ravenbrook.com/consultants/gdr/ @@ -217,7 +185,7 @@ Document History Copyright and License --------------------- -Copyright © 2013-2014 Ravenbrook Limited . +Copyright © 2013-2016 Ravenbrook Limited . All rights reserved. This is an open source license. Contact Ravenbrook for commercial licensing options. diff --git a/mps/manual/source/code-index.rst b/mps/manual/source/code-index.rst index 6d510059563..5b754e92fdf 100644 --- a/mps/manual/source/code-index.rst +++ b/mps/manual/source/code-index.rst @@ -183,7 +183,6 @@ prmcxci6.c Mutator context implementation for OS X, x86-64. prot.h Protection interface. See design.mps.prot_. protan.c Protection implementation for standard C. protix.c Protection implementation for POSIX. -protli.c Protection implementation for Linux. protsgix.c Protection implementation for POSIX (signals part). protw3.c Protection implementation for Windows. protxc.c Protection implementation for OS X. diff --git a/mps/manual/source/design/index.rst b/mps/manual/source/design/index.rst index 0b389160d65..0112433044a 100644 --- a/mps/manual/source/design/index.rst +++ b/mps/manual/source/design/index.rst @@ -27,6 +27,7 @@ Design nailboard prmc prot + protix range ring shield diff --git a/mps/manual/source/design/old.rst b/mps/manual/source/design/old.rst index 28b115e2335..9a2f695ab7f 100644 --- a/mps/manual/source/design/old.rst +++ b/mps/manual/source/design/old.rst @@ -41,7 +41,6 @@ Old design poolmv poolmvt poolmvff - protli protsu protocol pthreadext diff --git a/mps/manual/source/topic/porting.rst b/mps/manual/source/topic/porting.rst index bfe3c1adef3..aa2fe5de03d 100644 --- a/mps/manual/source/topic/porting.rst +++ b/mps/manual/source/topic/porting.rst @@ -61,8 +61,8 @@ usable. See :ref:`design-prot` for the design, and ``prot.h`` for the interface. There are implementations for POSIX in ``protix.c`` plus - ``protsgix.c``, Linux in ``protli.c``, Windows in ``protw3.c``, and - OS X using Mach in ``protxc.c``. + ``protsgix.c``, Windows in ``protw3.c``, and OS X using Mach in + ``protix.c`` plus ``protxc.c``. There is a generic implementation in ``protan.c``, which can't provide memory protection, so it forces memory to be scanned until @@ -200,7 +200,7 @@ For example:: #include "pthrdext.c" /* Posix thread extensions */ #include "vmix.c" /* Posix virtual memory */ #include "protix.c" /* Posix protection */ - #include "protli.c" /* Linux protection */ + #include "protsgix.c" /* Posix signal handling */ #include "prmci6.c" /* 64-bit Intel mutator context */ #include "prmclii6.c" /* 64-bit Intel for Linux mutator context */ #include "span.c" /* generic stack probe */ @@ -232,7 +232,7 @@ For example, ``lii6ll.gmk`` looks like this: prmci6.c \ prmclii6.c \ protix.c \ - protli.c \ + protsgix.c \ pthrdext.c \ span.c \ ssixi6.c \