| /* Copyright (C) 1994-2016 Free Software Foundation, Inc. | 
 |    This file is part of the GNU C Library. | 
 |  | 
 |    The GNU C Library is free software; you can redistribute it and/or | 
 |    modify it under the terms of the GNU Lesser General Public | 
 |    License as published by the Free Software Foundation; either | 
 |    version 2.1 of the License, or (at your option) any later version. | 
 |  | 
 |    The GNU C Library 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 | 
 |    Lesser General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU Lesser General Public | 
 |    License along with the GNU C Library; if not, see | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <mach/exc_server.h> | 
 | #include <hurd/signal.h> | 
 | #include <assert.h> | 
 |  | 
 | /* Called by the microkernel when a thread gets an exception.  */ | 
 |  | 
 | kern_return_t | 
 | _S_catch_exception_raise (mach_port_t port, | 
 | 			  thread_t thread, | 
 | 			  task_t task, | 
 | #ifdef EXC_MASK_ALL		/* New interface flavor.  */ | 
 | 			  exception_type_t exception, | 
 | 			  exception_data_t code, | 
 | 			  mach_msg_type_number_t codeCnt | 
 | #else				/* Vanilla Mach 3.0 interface.  */ | 
 | 			  integer_t exception, | 
 | 			  integer_t code, integer_t subcode | 
 | #endif | 
 | 			  ) | 
 | { | 
 |   struct hurd_sigstate *ss; | 
 |   int signo; | 
 |   struct hurd_signal_detail d; | 
 |  | 
 |   if (task != __mach_task_self ()) | 
 |     /* The sender wasn't the kernel.  */ | 
 |     return EPERM; | 
 |  | 
 |   d.exc = exception; | 
 | #ifdef EXC_MASK_ALL | 
 |   assert (codeCnt >= 2); | 
 |   d.exc_code = code[0]; | 
 |   d.exc_subcode = code[1]; | 
 | #else | 
 |   d.exc_code = code; | 
 |   d.exc_subcode = subcode; | 
 | #endif | 
 |  | 
 |   /* Call the machine-dependent function to translate the Mach exception | 
 |      codes into a signal number and subcode.  */ | 
 |   _hurd_exception2signal (&d, &signo); | 
 |  | 
 |   /* Find the sigstate structure for the faulting thread.  */ | 
 |   __mutex_lock (&_hurd_siglock); | 
 |   for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) | 
 |     if (ss->thread == thread) | 
 |       break; | 
 |   __mutex_unlock (&_hurd_siglock); | 
 |   if (ss == NULL) | 
 |     ss = _hurd_thread_sigstate (thread); /* Allocate a fresh one.  */ | 
 |  | 
 |   if (__spin_lock_locked (&ss->lock)) | 
 |     { | 
 |       /* Loser.  The thread faulted with its sigstate lock held.  Its | 
 | 	 sigstate data is now suspect.  So we reset the parts of it which | 
 | 	 could cause trouble for the signal thread.  Anything else | 
 | 	 clobbered therein will just hose this user thread, but it's | 
 | 	 faulting already. | 
 |  | 
 | 	 This is almost certainly a library bug: unless random memory | 
 | 	 clobberation caused the sigstate lock to gratuitously appear held, | 
 | 	 no code should do anything that can fault while holding the | 
 | 	 sigstate lock.  */ | 
 |  | 
 |       __spin_unlock (&ss->critical_section_lock); | 
 |       ss->context = NULL; | 
 |       __spin_unlock (&ss->lock); | 
 |     } | 
 |  | 
 |   /* Post the signal.  */ | 
 |   _hurd_internal_post_signal (ss, signo, &d, | 
 | 			      MACH_PORT_NULL, MACH_MSG_TYPE_PORT_SEND, | 
 | 			      0); | 
 |  | 
 |   return KERN_SUCCESS; | 
 | } | 
 |  | 
 | #ifdef EXC_MASK_ALL | 
 | /* XXX New interface flavor has additional RPCs that we could be using | 
 |    instead.  These RPCs roll a thread_get_state/thread_set_state into | 
 |    the message, so the signal thread ought to use these to save some calls. | 
 |  */ | 
 | kern_return_t | 
 | _S_catch_exception_raise_state (mach_port_t port, | 
 | 				exception_type_t exception, | 
 | 				exception_data_t code, | 
 | 				mach_msg_type_number_t codeCnt, | 
 | 				int *flavor, | 
 | 				thread_state_t old_state, | 
 | 				mach_msg_type_number_t old_stateCnt, | 
 | 				thread_state_t new_state, | 
 | 				mach_msg_type_number_t *new_stateCnt) | 
 | { | 
 |   abort (); | 
 |   return KERN_FAILURE; | 
 | } | 
 |  | 
 | kern_return_t | 
 | _S_catch_exception_raise_state_identity (mach_port_t exception_port, | 
 | 					 thread_t thread, | 
 | 					 task_t task, | 
 | 					 exception_type_t exception, | 
 | 					 exception_data_t code, | 
 | 					 mach_msg_type_number_t codeCnt, | 
 | 					 int *flavor, | 
 | 					 thread_state_t old_state, | 
 | 					 mach_msg_type_number_t old_stateCnt, | 
 | 					 thread_state_t new_state, | 
 | 					 mach_msg_type_number_t *new_stateCnt) | 
 | { | 
 |   abort (); | 
 |   return KERN_FAILURE; | 
 | } | 
 | #endif |