1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-24 06:20:43 -08:00
Copied from Perforce
 Change: 182993
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2013-07-11 14:17:17 +01:00
parent f8c90b565e
commit f19d112a1a

View file

@ -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 */