diff src/vdb-mach.c @ 3092:141c2920ea48

[xemacs-hg @ 2005-11-25 01:41:31 by crestani] Incremental Garbage Collector
author crestani
date Fri, 25 Nov 2005 01:42:08 +0000
parents
children 308d34e9f07d
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/vdb-mach.c	Fri Nov 25 01:42:08 2005 +0000
@@ -0,0 +1,261 @@
+/* Virtual diry bit implementation for XEmacs.
+   Copyright (C) 2005 Marcus Crestani.
+
+This file is part of XEmacs.
+
+XEmacs is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+XEmacs is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with XEmacs; see the file COPYING.  If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Synched up with: Not in FSF. */
+
+#include <config.h>
+#include "lisp.h"
+#include "gc.h"
+#include "mc-alloc.h"
+#include "vdb.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <architecture/ppc/cframe.h>
+
+
+/* the structure of an exception msg and its reply */
+typedef struct rep_msg {
+  mach_msg_header_t head;
+  NDR_record_t NDR;
+  kern_return_t ret_code;
+} mach_reply_msg_t;
+
+typedef struct exc_msg {
+  mach_msg_header_t head;
+  /* start of the kernel processed data */
+  mach_msg_body_t msgh_body;
+  mach_msg_port_descriptor_t thread;
+  mach_msg_port_descriptor_t task;
+  /* end of the kernel processed data */
+  NDR_record_t NDR;
+  exception_type_t exception;
+  mach_msg_type_number_t code_cnt;
+  exception_data_t code;
+  /* some padding */
+  char pad[512];
+} mach_exc_msg_t;
+
+/* this is a neat little mach callback */
+extern boolean_t exc_server(mach_msg_header_t *in, mach_msg_header_t *out);
+
+/* these are the globals everyone needs */
+static size_t page_size = 16384;
+static mach_port_t task_self = NULL;
+static mach_port_t exc_port = NULL;
+
+/* these are some less neat mach callbacks */
+kern_return_t
+catch_exception_raise_state 
+(mach_port_t UNUSED (port),
+ exception_type_t UNUSED (exception_type),
+ exception_data_t UNUSED (exception_data),
+ mach_msg_type_number_t UNUSED (data_cnt),
+ thread_state_flavor_t *UNUSED (flavor),
+ thread_state_t UNUSED (in_state),
+ mach_msg_type_number_t UNUSED (is_cnt),
+ thread_state_t UNUSED (out_state),
+ mach_msg_type_number_t UNUSED (os_cnt))
+{
+  return KERN_FAILURE;
+}
+
+kern_return_t 
+catch_exception_raise_state_identitity 
+(mach_port_t UNUSED (port),
+ mach_port_t UNUSED (thread_port),
+ mach_port_t UNUSED (task_port),
+ exception_type_t UNUSED (exception_type),
+ exception_data_t UNUSED (exception_data),
+ mach_msg_type_number_t UNUSED (data_count),
+ thread_state_flavor_t *UNUSED (state_flavor),
+ thread_state_t UNUSED (in_state),
+ mach_msg_type_number_t UNUSED (in_state_count),
+ thread_state_t UNUSED (out_state),
+ mach_msg_type_number_t UNUSED (out_state_count))
+{
+  return KERN_FAILURE;
+}
+
+kern_return_t 
+catch_exception_raise
+(mach_port_t UNUSED (port),
+ mach_port_t UNUSED (thread_port),
+ mach_port_t UNUSED (task_port),
+ exception_type_t UNUSED (exception_type),
+ exception_data_t exception_data,
+ mach_msg_type_number_t UNUSED (data_count))
+{
+  /* kernel return value is in exception_data[0], faulting address in
+     exception_data[1] */
+  if (write_barrier_enabled
+      && (fault_on_protected_page ((void *) exception_data[1]))
+      && exception_data[0] == KERN_PROTECTION_FAILURE)
+    {
+      vdb_designate_modified ((void *) exception_data[1]);
+      unprotect_page_and_mark_dirty ((void *) exception_data[1]);
+      return KERN_SUCCESS;
+    }
+  else  /* default sigsegv handler */
+    {
+      fprintf (stderr, "\n\nFatal Error: Received %s (%d) for address 0x%x\n",
+	       "EXC_BAD_ACCESS", exception_data[0], (int) exception_data[1]);
+      return KERN_FAILURE;
+    }
+}
+
+/* this is the thread which forwards of exceptions read from the exception
+   server off to our exception catchers and then back out to the other
+   thread */
+void 
+exception_thread(void)
+{
+  mach_msg_header_t *message;
+  mach_msg_header_t *reply;
+  kern_return_t retval;
+  
+  /* allocate the space for the message and reply */
+  message = (mach_msg_header_t *) malloc (sizeof (mach_exc_msg_t));
+  reply = (mach_msg_header_t *) malloc (sizeof (mach_reply_msg_t));
+  /* do this loop forever */
+  while (1) 
+    {
+      /* block until we get an exception message */
+      retval = mach_msg (message, MACH_RCV_MSG, 0, sizeof (mach_exc_msg_t), 
+			 exc_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
+      /* forward off the handling of this message */
+      if (!exc_server (message, reply)) 
+	{
+	  fprintf (stderr, "INTERNAL ERROR: exc_server() failed.\n");
+	  ABORT ();
+	}
+      /* send the message back out to the thread */
+      retval = mach_msg (reply, MACH_SEND_MSG, sizeof (mach_reply_msg_t), 0, 
+			 MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
+			 MACH_PORT_NULL);
+    }
+}
+
+/* this initializes the subsystem (sets the exception port, starts the
+   exception handling thread, etc) */
+void 
+vdb_install_signal_handler (void) 
+{
+  mach_port_t thread_self, exc_port_s, exc_thread;
+  ppc_thread_state_t *exc_thread_state;
+  mach_msg_type_name_t type;
+  void *subthread_stack;
+  kern_return_t retval;
+
+  /* get ids for ourself */
+  if (!task_self) 
+    task_self = mach_task_self ();
+  thread_self = mach_thread_self ();
+
+  /* allocate the port we're going to get exceptions on */
+  retval = mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &exc_port);
+  if (retval != KERN_SUCCESS) 
+    {
+      fprintf (stderr, "Couldn't allocate exception port: %s\n", 
+	       mach_error_string (retval));
+      ABORT ();
+    }
+
+  /* extract out the send rights for that port, which the OS needs */
+  retval = mach_port_extract_right (task_self, exc_port, 
+				    MACH_MSG_TYPE_MAKE_SEND,
+				    &exc_port_s, &type);
+  if(retval != KERN_SUCCESS)
+    {
+      fprintf (stderr, "Couldn't extract send rights: %s\n",
+	       mach_error_string (retval));
+      ABORT ();
+    }
+
+  /* set the exception ports for this thread to the above */
+  retval = thread_set_exception_ports(thread_self, EXC_MASK_BAD_ACCESS, 
+				      exc_port_s, EXCEPTION_DEFAULT, 
+				      PPC_THREAD_STATE);
+  if(retval != KERN_SUCCESS)
+    {
+      fprintf (stderr, "Couldn't set exception ports: %s\n",
+	       mach_error_string (retval));
+      ABORT ();
+    }
+
+  /* set up the subthread */
+  retval = thread_create(task_self, &exc_thread);
+  if(retval != KERN_SUCCESS) 
+    {
+      fprintf (stderr , "Couldn't create exception thread: %s\n",
+	       mach_error_string (retval));
+      ABORT ();
+    }
+  subthread_stack = (void *) malloc (page_size);
+  subthread_stack = 
+    (char *) subthread_stack + (page_size - C_ARGSAVE_LEN - C_RED_ZONE);
+  exc_thread_state = 
+    (ppc_thread_state_t *) malloc (sizeof (ppc_thread_state_t));
+  exc_thread_state->srr0 = (unsigned int) exception_thread;
+  exc_thread_state->r1 = (unsigned int) subthread_stack;
+  retval = thread_set_state (exc_thread, PPC_THREAD_STATE,
+			     (thread_state_t) exc_thread_state,
+			     PPC_THREAD_STATE_COUNT);
+  if (retval != KERN_SUCCESS)
+    {
+      fprintf (stderr, "Couldn't set subthread state: %s\n",
+	       mach_error_string (retval));
+      ABORT ();
+    }
+  retval = thread_resume (exc_thread);
+  if (retval != KERN_SUCCESS) 
+    {
+      fprintf (stderr, "Couldn't resume subthread: %s\n",
+	       mach_error_string (retval));
+      ABORT ();
+    }
+  allow_incremental_gc = 1;
+}
+
+void
+vdb_protect (void *ptr, EMACS_INT len)
+{
+  if (mprotect (ptr, len, PROT_READ))
+    {
+      perror ("Couldn't mprotect");
+      ABORT ();
+    }
+}
+
+void
+vdb_unprotect (void *ptr, EMACS_INT len)
+{
+  if (mprotect (ptr, len, PROT_READ | PROT_WRITE))
+    {
+      perror ("Couldn't mprotect");
+      ABORT ();
+    }
+}