mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-24 06:20:43 -08:00
Small fixes following review <https://info.ravenbrook.com/mail/2013/07/11/13-17-56/0/>.
Copied from Perforce Change: 182993 ServerID: perforce.ravenbrook.com
This commit is contained in:
parent
f8c90b565e
commit
f19d112a1a
1 changed files with 47 additions and 35 deletions
|
|
@ -1,22 +1,24 @@
|
|||
/* protxc.c: PROTECTION EXCPETION HANDLER FOR OS X MACH
|
||||
/* protxc.c: PROTECTION EXCEPTION HANDLER FOR OS X MACH
|
||||
*
|
||||
* $Id$
|
||||
* Copyright (c) 2013 Ravenbrook Limited. See end of file for license.
|
||||
*
|
||||
* This is the protection exception handling code for Mac OS X using the
|
||||
* This is the protection exception handling code for OS X using the
|
||||
* Mach interface (not pthreads).
|
||||
*
|
||||
* In Mach, a thread that hits protected memory is suspended, and a message
|
||||
* is sent to a separate handler thread.
|
||||
*
|
||||
* The handler thread can fix things up and continue the suspended thread by
|
||||
* sending back a "success" reply. It can forward the message to another
|
||||
* handler of the same kind, or it can forward the message to another handler
|
||||
* at the next level out (the levels are thread, task, host) by sending a
|
||||
* "fail" reply.
|
||||
*
|
||||
* In Mac OS X, pthreads are implemented by Mach threads. (The implementation
|
||||
* is part of the XNU source code at opensource.apple.com. [copy to import?])
|
||||
* So we can use some pthread interfaces for convenience in setting up threads.
|
||||
* In OS X, pthreads are implemented by Mach threads. (The implementation is
|
||||
* part of the XNU source code at opensource.apple.com. [copy to import?]) So
|
||||
* we can use some pthread interfaces (pthread_create, pthread_once) for
|
||||
* convenience in setting up threads.
|
||||
*
|
||||
* This module sets up an exception handling thread for the EXC_BAD_ACCESS
|
||||
* exceptions that will be caused by the MPS shield (read/write barriers).
|
||||
|
|
@ -58,6 +60,7 @@
|
|||
#include "protxc.h"
|
||||
|
||||
#include <stdlib.h> /* see .trans.stdlib */
|
||||
#include <stdio.h> /* see .trans.stdlib */
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
|
@ -73,8 +76,8 @@
|
|||
#if !defined(MPS_OS_XC)
|
||||
#error "protxc.c is OS X specific"
|
||||
#endif
|
||||
#ifndef PROTECTION
|
||||
#error "protxc.c implements protection, but PROTECTION is not set"
|
||||
#if !defined(PROTECTION)
|
||||
#error "protxc.c implements protection, but PROTECTION is not defined"
|
||||
#endif
|
||||
|
||||
SRCID(protxc, "$Id$");
|
||||
|
|
@ -124,7 +127,7 @@ typedef __Reply__exception_raise_state_identity_t protReplyStruct;
|
|||
/* protExcPort -- exception message receiving Mach port
|
||||
*
|
||||
* This will be the port that will receive messages for our exception
|
||||
* handler, initialized by protSetup.
|
||||
* handler, initialized by protSetupInner.
|
||||
*/
|
||||
|
||||
static mach_port_name_t protExcPort = MACH_PORT_NULL;
|
||||
|
|
@ -176,7 +179,7 @@ static void protMustSend(mach_msg_header_t *head)
|
|||
|
||||
/* protCatchOne -- catch one EXC_BAD_ACCESS exception message.
|
||||
*
|
||||
* Mac OS X provides a function exc_server (in
|
||||
* OS X provides a function exc_server (in
|
||||
* /usr/lib/system/libsystem_kernel.dylib) that's documented in the XNU
|
||||
* sources <http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/osfmk/man/exc_server.html>
|
||||
* and generated by the Mach Interface Generator (mig). It unpacks
|
||||
|
|
@ -187,7 +190,7 @@ static void protMustSend(mach_msg_header_t *head)
|
|||
* steal those names in case the client program is using them too.
|
||||
*
|
||||
* 2. It fails anyway in Xcode's default "Release" build with hidden
|
||||
* symbols, because it uses dlsym to find those handler functins, and
|
||||
* symbols, because it uses dlsym to find those handler functions, and
|
||||
* dlsym can't find them.
|
||||
*
|
||||
* So instead this function duplicates the work of exc_server, and is shorter
|
||||
|
|
@ -203,12 +206,13 @@ static void protCatchOne(void)
|
|||
mach_msg_return_t mr;
|
||||
protReplyStruct reply;
|
||||
|
||||
AVER(MACH_PORT_VALID(protExcPort));
|
||||
mr = mach_msg(&request.Head,
|
||||
MACH_RCV_MSG,
|
||||
/* option */ MACH_RCV_MSG,
|
||||
/* send_size */ 0,
|
||||
/* receive_size */ sizeof(request),
|
||||
protExcPort,
|
||||
/* timeout */ 0,
|
||||
/* receive_limit */ sizeof(request),
|
||||
/* receive_name */ protExcPort,
|
||||
/* timeout */ MACH_MSG_TIMEOUT_NONE,
|
||||
/* notify */ MACH_PORT_NULL);
|
||||
AVER(mr == MACH_MSG_SUCCESS);
|
||||
if (mr != MACH_MSG_SUCCESS)
|
||||
|
|
@ -284,16 +288,17 @@ static void *protCatchThread(void *p) {
|
|||
extern void ProtThreadRegister(Bool setup)
|
||||
{
|
||||
kern_return_t kr;
|
||||
mach_msg_type_number_t old_cnt;
|
||||
exception_mask_t old_mask;
|
||||
exception_behavior_t behaviour;
|
||||
mach_port_t old_port;
|
||||
exception_behavior_t old_behaviour;
|
||||
thread_state_flavor_t old_flavor;
|
||||
mach_msg_type_number_t old_exception_count;
|
||||
exception_mask_t old_exception_masks;
|
||||
exception_behavior_t behavior;
|
||||
mach_port_t old_exception_ports;
|
||||
exception_behavior_t old_behaviors;
|
||||
thread_state_flavor_t old_flavors;
|
||||
mach_port_t self;
|
||||
static mach_port_t setupThread = MACH_PORT_NULL;
|
||||
|
||||
self = mach_thread_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
|
||||
/* Avoid setting up the exception handler for the setup thread twice,
|
||||
in the case where the mutator registers that thread twice. */
|
||||
|
|
@ -310,46 +315,53 @@ extern void ProtThreadRegister(Bool setup)
|
|||
with thread state and identity information in the message.
|
||||
The MACH_EXCEPTION_CODES flag causes the code fields to be
|
||||
passed 64-bits wide, matching protRequestStruct. */
|
||||
behaviour = (exception_behavior_t)(EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES);
|
||||
behavior = (exception_behavior_t)(EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES);
|
||||
AVER(MACH_PORT_VALID(protExcPort));
|
||||
kr = thread_swap_exception_ports(self,
|
||||
EXC_MASK_BAD_ACCESS,
|
||||
protExcPort,
|
||||
behaviour,
|
||||
behavior,
|
||||
THREAD_STATE_FLAVOR,
|
||||
&old_mask,
|
||||
&old_cnt,
|
||||
&old_port,
|
||||
&old_behaviour,
|
||||
&old_flavor);
|
||||
&old_exception_masks,
|
||||
&old_exception_count,
|
||||
&old_exception_ports,
|
||||
&old_behaviors,
|
||||
&old_flavors);
|
||||
AVER(kr == KERN_SUCCESS);
|
||||
if (kr != KERN_SUCCESS)
|
||||
mach_error("ERROR: MPS thread_swap_exception_ports", kr); /* .trans.must */
|
||||
AVER(old_mask == EXC_MASK_BAD_ACCESS);
|
||||
AVER(old_cnt == 1);
|
||||
AVER(old_port == MACH_PORT_NULL); /* .assume.only-port */
|
||||
AVER(old_exception_masks == EXC_MASK_BAD_ACCESS);
|
||||
AVER(old_exception_count == 1);
|
||||
AVER(old_exception_ports == MACH_PORT_NULL); /* .assume.only-port */
|
||||
}
|
||||
|
||||
|
||||
/* ProtSetup -- set up protection exception handling */
|
||||
|
||||
static void protSetup(void)
|
||||
static void protSetupInner(void)
|
||||
{
|
||||
kern_return_t kr;
|
||||
int pr;
|
||||
pthread_t excThread;
|
||||
mach_port_t self;
|
||||
|
||||
/* Create a port to send and receive exceptions. */
|
||||
kr = mach_port_allocate(mach_task_self(),
|
||||
self = mach_task_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
kr = mach_port_allocate(self,
|
||||
MACH_PORT_RIGHT_RECEIVE,
|
||||
&protExcPort);
|
||||
AVER(kr == KERN_SUCCESS);
|
||||
if (kr != KERN_SUCCESS)
|
||||
mach_error("ERROR: MPS mach_port_allocate", kr); /* .trans.must */
|
||||
AVER(MACH_PORT_VALID(protExcPort));
|
||||
|
||||
/* Allow me to send exceptions on this port. */
|
||||
/* TODO: Find out why this is necessary. */
|
||||
kr = mach_port_insert_right(mach_task_self(),
|
||||
protExcPort, protExcPort ,
|
||||
self = mach_task_self();
|
||||
AVER(MACH_PORT_VALID(self));
|
||||
kr = mach_port_insert_right(self,
|
||||
protExcPort, protExcPort,
|
||||
MACH_MSG_TYPE_MAKE_SEND);
|
||||
AVER(kr == KERN_SUCCESS);
|
||||
if (kr != KERN_SUCCESS)
|
||||
|
|
@ -374,7 +386,7 @@ void ProtSetup(void)
|
|||
|
||||
/* ProtSetup may be called several times if the client creates more than
|
||||
one arena, but we still only want one exception handling thread. */
|
||||
pr = pthread_once(&prot_setup_once, protSetup);
|
||||
pr = pthread_once(&prot_setup_once, protSetupInner);
|
||||
AVER(pr == 0);
|
||||
if (pr != 0)
|
||||
fprintf(stderr, "ERROR: MPS pthread_once: %d\n", pr); /* .trans.must */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue