| /* Copyright (C) 1994-2014 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 |