📄 hurdsig.c
字号:
case SIGIO: case SIGURG: case SIGCHLD: case SIGWINCH: act = ignore; break; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGEMT: case SIGFPE: case SIGBUS: case SIGSEGV: case SIGSYS: act = core; break; case SIGINFO: if (_hurd_pgrp == _hurd_pid) { /* We are the process group leader. Since there is no user-specified handler for SIGINFO, we use a default one which prints something interesting. We use the normal handler mechanism instead of just doing it here to avoid the signal thread faulting or blocking in this potentially hairy operation. */ act = handle; handler = _hurd_siginfo_handler; } else act = ignore; break; default: act = term; break; } else if (handler == SIG_IGN) act = ignore; else act = handle; if (sigmask (signo) & STOPSIGS) /* Stop signals clear a pending SIGCONT even if they are handled or ignored (but not if preempted). */ ss->pending &= ~sigmask (SIGCONT); else if (signo == SIGCONT) { /* Even if handled or ignored (but not preempted), SIGCONT clears stop signals and resumes the process. */ ss->pending &= ~STOPSIGS; if (_hurd_stopped) { thread_t *threads; unsigned int nthreads, i; error_t err; /* Tell the proc server we are continuing. */ __USEPORT (PROC, __proc_mark_cont (port)); /* Fetch ports to all our threads and resume them. */ err = __task_threads (__mach_task_self (), &threads, &nthreads); assert_perror (err); for (i = 0; i < nthreads; ++i) { if (threads[i] != _hurd_msgport_thread && (act != handle || threads[i] != ss->thread)) __thread_resume (threads[i]); __mach_port_deallocate (__mach_task_self (), threads[i]); } __vm_deallocate (__mach_task_self (), (vm_address_t) threads, nthreads * sizeof *threads); _hurd_stopped = 0; /* The thread that will run the handler is already suspended. */ ss_suspended = 1; } } } if (_hurd_orphaned && act == stop && (signo & (__sigmask (SIGTTIN) | __sigmask (SIGTTOU) | __sigmask (SIGTSTP)))) { /* If we would ordinarily stop for a job control signal, but we are orphaned so noone would ever notice and continue us again, we just quietly die, alone and in the dark. */ sigcode = signo; signo = SIGKILL; act = term; } /* Handle receipt of a blocked signal. */ if ((__sigismember (&ss->blocked, signo) && act != ignore) || (signo != SIGKILL && _hurd_stopped)) { __sigaddset (&ss->pending, signo); /* Save the code to be given to the handler when SIGNO is unblocked. */ ss->pending_data[signo].code = sigcode; ss->pending_data[signo].error = sigerror; act = ignore; } /* Perform the chosen action for the signal. */ switch (act) { case stop: if (! _hurd_stopped) { /* Stop all other threads and mark ourselves stopped. */ __USEPORT (PROC, ({ /* Hold the siglock while stopping other threads to be sure it is not held by another thread afterwards. */ __mutex_unlock (&ss->lock); __mutex_lock (&_hurd_siglock); __proc_dostop (port, _hurd_msgport_thread); __mutex_unlock (&_hurd_siglock); abort_all_rpcs (signo, &thread_state); __proc_mark_stop (port, signo); })); _hurd_stopped = 1; } __mutex_lock (&ss->lock); sigwakeup (); /* Wake up sigsuspend. */ break; case ignore: /* Nobody cares about this signal. */ break; case term: /* Time to die. */ case core: /* And leave a rotting corpse. */ nirvana: __mutex_unlock (&ss->lock); /* Have the proc server stop all other threads in our task. */ __USEPORT (PROC, __proc_dostop (port, _hurd_msgport_thread)); /* No more user instructions will be executed. The signal can now be considered delivered. */ reply (); /* Abort all server operations now in progress. */ abort_all_rpcs (signo, &thread_state); { int status = W_EXITCODE (0, signo); /* Do a core dump if desired. Only set the wait status bit saying we in fact dumped core if the operation was actually successful. */ if (act == core && write_corefile (signo, sigcode, sigerror)) status |= WCOREFLAG; /* Tell proc how we died and then stick the saber in the gut. */ _hurd_exit (status); /* NOTREACHED */ } case handle: /* Call a handler for this signal. */ { struct sigcontext *scp; int wait_for_reply; /* Stop the thread and abort its pending RPC operations. */ if (! ss_suspended) __thread_suspend (ss->thread); wait_for_reply = (abort_rpcs (ss, signo, &thread_state, &reply_port, reply_port_type) != MACH_PORT_NULL); /* Call the machine-dependent function to set the thread up to run the signal handler, and preserve its old context. */ scp = _hurd_setup_sighandler (ss, handler, signo, sigcode, wait_for_reply, &thread_state); if (scp == NULL) { /* We got a fault setting up the stack frame for the handler. Nothing to do but die; BSD gets SIGILL in this case. */ sigcode = signo; /* XXX ? */ signo = SIGILL; act = core; goto nirvana; } /* Set the machine-independent parts of the signal context. */ scp->sc_error = sigerror; { /* Fetch the thread variable for the MiG reply port, and set it to MACH_PORT_NULL. */ mach_port_t *loc = interrupted_reply_port_location (&thread_state); if (loc) { scp->sc_reply_port = *loc; *loc = MACH_PORT_NULL; } else scp->sc_reply_port = MACH_PORT_NULL; } /* Block SIGNO and requested signals while running the handler. */ scp->sc_mask = ss->blocked; ss->blocked |= __sigmask (signo) | ss->actions[signo].sa_mask; /* Save the intr_port in use by the interrupted code, and clear the cell before running the trampoline. */ scp->sc_intr_port = ss->intr_port; ss->intr_port = MACH_PORT_NULL; /* Start the thread running the handler (or possibly waiting for an RPC reply before running the handler). */ __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR, (int *) &thread_state.basic, MACHINE_THREAD_STATE_COUNT); __thread_resume (ss->thread); thread_state.set = 0; /* Everything we know is now wrong. */ break; } } /* The signal has either been ignored or is now being handled. We can consider it delivered and reply to the killer. The exception is signal 0, which can be sent by a user thread to make us check for pending signals. In that case we want to deliver the pending signals before replying. */ if (signo != 0) reply (); /* We get here only if we are handling or ignoring the signal; otherwise we are stopped or dead by now. We still hold SS->lock. Check for pending signals, and loop to post them. */#define PENDING (!_hurd_stopped && (pending = ss->pending & ~ss->blocked)) if (PENDING) { pending: for (signo = 1; signo < NSIG; ++signo) if (__sigismember (&pending, signo)) { __sigdelset (&ss->pending, signo); sigcode = ss->pending_data[signo].code; sigerror = ss->pending_data[signo].error; goto post_signal; } } /* No more signals pending; SS->lock is still locked. */ sigwakeup (); /* No pending signals left undelivered for this thread. If we were sent signal 0, we need to check for pending signals for all threads. */ if (signo == 0) { __mutex_lock (&_hurd_siglock); for (ss = _hurd_sigstates; ss != NULL; ss = ss->next) { __mutex_lock (&ss->lock); if (PENDING) goto pending; __mutex_unlock (&ss->lock); } __mutex_unlock (&_hurd_siglock); } /* All pending signals delivered to all threads. Now we can send the reply message even for signal 0. */ reply ();}/* Implement the sig_post RPC from <hurd/msg.defs>; sent when someone wants us to get a signal. */kern_return_t_S_sig_post (mach_port_t me, mach_port_t reply_port, mach_msg_type_name_t reply_port_type, int signo, mach_port_t refport){ struct hurd_sigstate *ss; if (signo < 0 || signo >= NSIG) return EINVAL; if (refport == __mach_task_self ()) /* Can send any signal. */ goto win; /* Avoid needing to check for this below. */ if (refport == MACH_PORT_NULL) return EPERM; switch (signo) { case SIGINT: case SIGQUIT: case SIGTSTP: case SIGHUP: case SIGINFO: case SIGTTIN: case SIGTTOU: /* Job control signals can be sent by the controlling terminal. */ if (__USEPORT (CTTYID, port == refport)) goto win; break; case SIGCONT: { /* A continue signal can be sent by anyone in the session. */ mach_port_t sessport; if (! __USEPORT (PROC, __proc_getsidport (port, &sessport))) { __mach_port_deallocate (__mach_task_self (), sessport); if (refport == sessport) goto win; } } break; case SIGIO: case SIGURG: { /* Any io object a file descriptor refers to might send us one of these signals using its async ID port for REFPORT. This is pretty wide open; it is not unlikely that some random process can at least open for reading something we have open, get its async ID port, and send us a spurious SIGIO or SIGURG signal. But BSD is actually wider open than that!--you can set the owner of an io object to any process or process group whatsoever and send them gratuitous signals. Someday we could implement some reasonable scheme for authorizing SIGIO and SIGURG signals properly. */ int d; __mutex_lock (&_hurd_dtable_lock); for (d = 0; (unsigned int) d < (unsigned int) _hurd_dtablesize; ++d) { struct hurd_userlink ulink; io_t port; mach_port_t asyncid; if (_hurd_dtable[d] == NULL) continue; port = _hurd_port_get (&_hurd_dtable[d]->port, &ulink); if (! __io_get_icky_async_id (port, &asyncid)) { if (refport == asyncid) /* Break out of the loop on the next iteration. */ d = -1; __mach_port_deallocate (__mach_task_self (), asyncid); } _hurd_port_free (&_hurd_dtable[d]->port, &ulink, port); } /* If we found a lucky winner, we've set D to -1 in the loop. */ if (d < 0) goto win; } } /* If this signal is legit, we have done `goto win' by now. When we return the error, mig deallocates REFPORT. */ return EPERM; win: /* Deallocate the REFPORT send right; we are done with it. */ __mach_port_deallocate (__mach_task_self (), refport); /* Get a hold of the designated signal-receiving thread. */ ss = _hurd_thread_sigstate (_hurd_sigthread); /* Post the signal; this will reply when the signal can be considered delivered. */ _hurd_internal_post_signal (ss, signo, 0, 0, reply_port, reply_port_type); return MIG_NO_REPLY; /* Already replied. */}extern void __mig_init (void *);#include <mach/task_special_ports.h>/* Initialize the message port and _hurd_sigthread and start the signal thread. */void_hurdsig_init (void){ error_t err; vm_size_t stacksize; __mutex_init (&_hurd_siglock); if (err = __mach_port_allocate (__mach_task_self (), MACH_PORT_RIGHT_RECEIVE, &_hurd_msgport)) __libc_fatal ("hurd: Can't create message port receive right\n"); /* Make a send right to the signal port. */ if (err = __mach_port_insert_right (__mach_task_self (), _hurd_msgport, _hurd_msgport, MACH_MSG_TYPE_MAKE_SEND)) __libc_fatal ("hurd: Can't create send right to message port\n"); /* Set the default thread to receive task-global signals to this one, the main (first) user thread. */ _hurd_sigthread = __mach_thread_self (); /* Start the signal thread listening on the message port. */ if (err = __thread_create (__mach_task_self (), &_hurd_msgport_thread)) __libc_fatal ("hurd: Can't create signal thread\n"); stacksize = __vm_page_size * 4; /* Small stack for signal thread. */ if (err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread, _hurd_msgport_receive, (vm_address_t *) &__hurd_sigthread_stack_base, &stacksize)) __libc_fatal ("hurd: Can't setup signal thread\n"); __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize; __hurd_sigthread_variables = malloc (__hurd_threadvar_max * sizeof (unsigned long int)); if (__hurd_sigthread_variables == NULL) __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n"); /* Reinitialize the MiG support routines so they will use a per-thread variable for the cached reply port. */ __mig_init ((void *) __hurd_sigthread_stack_base); if (err = __thread_resume (_hurd_msgport_thread)) __libc_fatal ("hurd: Can't resume signal thread\n"); #if 0 /* Don't confuse poor gdb. */ /* Receive exceptions on the signal port. */ __task_set_special_port (__mach_task_self (), TASK_EXCEPTION_PORT, _hurd_msgport);#endif} /* XXXX *//* Reauthenticate with the proc server. */static voidreauth_proc (mach_port_t new){ mach_port_t ref, ignore; ref = __mach_reply_port (); if (! HURD_PORT_USE (&_hurd_ports[INIT_PORT_PROC], __proc_reauthenticate (port, ref, MACH_MSG_TYPE_MAKE_SEND) || __auth_user_authenticate (new, port, ref, MACH_MSG_TYPE_MAKE_SEND, &ignore)) && ignore != MACH_PORT_NULL) __mach_port_deallocate (__mach_task_self (), ignore); __mach_port_destroy (__mach_task_self (), ref); (void) &reauth_proc; /* Silence compiler warning. */}text_set_element (__hurd_reauth_hook, reauth_proc);/* Like `getenv', but safe for the signal thread to run. If the environment is trashed, this will just return NULL. */const char *_hurdsig_getenv (const char *variable){ if (_hurdsig_catch_fault (SIGSEGV)) /* We bombed in getenv. */ return NULL; else { const char *value = getenv (variable); /* Fault now if VALUE is a bogus string. */ (void) strlen (value); _hurdsig_end_catch_fault (); return value; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -