⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hurdsig.c

📁 一个C源代码分析器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Copyright (C) 1991, 1992, 1993, 1994 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/ormodify it under the terms of the GNU Library General Public License aspublished by the Free Software Foundation; either version 2 of theLicense, 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULibrary General Public License for more details.You should have received a copy of the GNU Library General PublicLicense along with the GNU C Library; see the file COPYING.LIB.  Ifnot, write to the Free Software Foundation, Inc., 675 Mass Ave,Cambridge, MA 02139, USA.  */#include <stdlib.h>#include <stdio.h>#include <gnu-stabs.h>#include <hurd.h>#include <hurd/signal.h>#include <cthreads.h>		/* For `struct mutex'.  */#include <string.h>#include "hurdfault.h"#include "hurdmalloc.h"		/* XXX */const char *_hurdsig_getenv (const char *);struct mutex _hurd_siglock;int _hurd_stopped;/* Port that receives signals and other miscellaneous messages.  */mach_port_t _hurd_msgport;/* Thread listening on it.  */thread_t _hurd_msgport_thread;/* Thread which receives task-global signals.  */thread_t _hurd_sigthread;/* Linked-list of per-thread signal state.  */struct hurd_sigstate *_hurd_sigstates;static voiddefault_sigaction (struct sigaction actions[NSIG]){  int signo;  __sigemptyset (&actions[0].sa_mask);  actions[0].sa_flags = SA_RESTART;  actions[0].sa_handler = SIG_DFL;  for (signo = 1; signo < NSIG; ++signo)    actions[signo] = actions[0];}struct hurd_sigstate *_hurd_thread_sigstate (thread_t thread){  struct hurd_sigstate *ss;  __mutex_lock (&_hurd_siglock);  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)    if (ss->thread == thread)      break;  if (ss == NULL)    {      ss = malloc (sizeof (*ss));      if (ss == NULL)	__libc_fatal ("hurd: Can't allocate thread sigstate\n");      ss->thread = thread;      __mutex_init (&ss->lock);      /* Initialze default state.  */      __sigemptyset (&ss->blocked);      __sigemptyset (&ss->pending);      memset (&ss->sigaltstack, 0, sizeof (ss->sigaltstack));      ss->suspended = 0;#ifdef noteven      __condition_init (&ss->arrived);#endif      ss->intr_port = MACH_PORT_NULL;      ss->context = NULL;      /* Initialize the sigaction vector from the default signal receiving	 thread's state, and its from the system defaults.  */      if (thread == _hurd_sigthread)	default_sigaction (ss->actions);      else	{	  struct hurd_sigstate *s;	  for (s = _hurd_sigstates; s != NULL; s = s->next)	    if (s->thread == _hurd_sigthread)	      break;	  if (s)	    {	      __mutex_lock (&s->lock);	      memcpy (ss->actions, s->actions, sizeof (s->actions));	      __mutex_unlock (&s->lock);	    }	  else	    default_sigaction (ss->actions);	}      ss->next = _hurd_sigstates;      _hurd_sigstates = ss;    }  __mutex_lock (&ss->lock);  __mutex_unlock (&_hurd_siglock);  return ss;}/* Signal delivery itself is on this page.  */#include <hurd/fd.h>#include <hurd/core.h>#include <hurd/paths.h>#include <setjmp.h>#include <fcntl.h>#include <sys/wait.h>#include "thread_state.h"#include <hurd/msg_server.h>#include <hurd/msg_reply.h>	/* For __sig_post_reply.  */#include <assert.h>#include <hurd/interrupt.h>int _hurd_core_limit;	/* XXX *//* Call the core server to mummify us before we die.   Returns nonzero if a core file was written.  */static intwrite_corefile (int signo, int sigcode, int sigerror){  error_t err;  mach_port_t coreserver;  file_t file, coredir;  const char *name;  /* XXX RLIMIT_CORE:     When we have a protocol to make the server return an error     for RLIMIT_FSIZE, then tell the corefile fs server the RLIMIT_CORE     value in place of the RLIMIT_FSIZE value.  */  /* First get a port to the core dumping server.  */  coreserver = MACH_PORT_NULL;  name = _hurdsig_getenv ("CORESERVER");  if (name != NULL)    coreserver = __file_name_lookup (name, 0, 0);  if (coreserver == MACH_PORT_NULL)    coreserver = __file_name_lookup (_SERVERS_CORE, 0, 0);  if (coreserver == MACH_PORT_NULL)    return 0;  /* Get a port to the directory where the new core file will reside.  */  name = _hurdsig_getenv ("COREFILE");  if (name == NULL)    name = "core";  coredir = __file_name_split (name, (char **) &name);  if (coredir == MACH_PORT_NULL)    return 0;  /* Create the new file, but don't link it into the directory yet.  */  if (err = __dir_mkfile (coredir, O_WRONLY|O_CREAT,			  0600 & ~_hurd_umask, /* XXX ? */			  &file))    return 0;  /* Call the core dumping server to write the core file.  */  err = __core_dump_task (coreserver,			  __mach_task_self (),			  file, _hurdsig_getenv ("GNUTARGET"),			  signo, sigcode, sigerror);  __mach_port_deallocate (__mach_task_self (), coreserver);  if (! err)    /* The core dump into FILE succeeded, so now link it into the       directory.  */    err = __dir_link (file, coredir, name);  __mach_port_deallocate (__mach_task_self (), file);  __mach_port_deallocate (__mach_task_self (), coredir);  return !err;}/* Send a sig_post reply message if it hasn't already been sent.  */static inline voidpost_reply (mach_port_t *reply_port, mach_msg_type_name_t reply_port_type,	    error_t result){  if (reply_port == NULL || *reply_port == MACH_PORT_NULL)    return;  __sig_post_reply (*reply_port, reply_port_type, result);  *reply_port = MACH_PORT_NULL;}/* The lowest-numbered thread state flavor value is 1,   so we use bit 0 in machine_thread_all_state.set to   record whether we have done thread_abort.  */#define THREAD_ABORTED 1/* SS->thread is suspended.  Abort the thread and get its basic state.  If   REPLY_PORT is not NULL, send a reply on *REPLY_PORT after aborting the   thread.  */static voidabort_thread (struct hurd_sigstate *ss, struct machine_thread_all_state *state,	      mach_port_t *reply_port, mach_msg_type_name_t reply_port_type){  if (!(state->set & THREAD_ABORTED))    {      __thread_abort (ss->thread);      /* Clear all thread state flavor set bits, because thread_abort may	 have changed the state.  */      state->set = THREAD_ABORTED;    }  if (reply_port)    post_reply (reply_port, reply_port_type, 0);  machine_get_basic_state (ss->thread, state);}/* Find the location of the MiG reply port cell in use by the thread whose   state is described by THREAD_STATE.  Make sure that this location can be   set without faulting, or else return NULL.  */static mach_port_t *interrupted_reply_port_location (struct machine_thread_all_state *thread_state){  mach_port_t *portloc = (mach_port_t *) __hurd_threadvar_location_from_sp    (_HURD_THREADVAR_MIG_REPLY, (void *) thread_state->basic.SP);  if (_hurdsig_catch_fault (SIGSEGV))    {      assert (_hurdsig_fault_sigcode == (int) portloc);      /* Faulted trying to read the stack.  */      return NULL;    }  /* Fault now if this pointer is bogus.  */  *(volatile mach_port_t *) portloc = *portloc;  _hurdsig_end_catch_fault ();  return portloc;}/* SS->thread is suspended.   Abort any interruptible RPC operation the thread is doing.   This uses only the constant member SS->thread and the unlocked, atomically   set member SS->intr_port, so no locking is needed.   If successfully sent an interrupt_operation and therefore the thread should   wait for its pending RPC to return (possibly EINTR) before taking the   incoming signal, returns the reply port to be received on.  Otherwise   returns MACH_PORT_NULL.  */static mach_port_tabort_rpcs (struct hurd_sigstate *ss, int signo,	    struct machine_thread_all_state *state,	    mach_port_t *reply_port, mach_msg_type_name_t reply_port_type){  mach_port_t msging_port;  mach_port_t intr_port;  intr_port = ss->intr_port;  if (intr_port == MACH_PORT_NULL)    /* No interruption needs done.  */    return MACH_PORT_NULL;  /* Abort the thread's kernel context, so any pending message send or     receive completes immediately or aborts.  */  abort_thread (ss, state, reply_port, reply_port_type);  if (_hurdsig_rcv_interrupted_p (state, &msging_port))    {      error_t err;      /* The RPC request message was sent and the thread was waiting for	 the reply message; now the message receive has been aborted, so	 the mach_msg_call will return MACH_RCV_INTERRUPTED.  We must tell	 the server to interrupt the pending operation.  The thread must	 wait for the reply message before running the signal handler (to	 guarantee that the operation has finished being interrupted), so	 our nonzero return tells the trampoline code to finish the message	 receive operation before running the handler.  */      err = __interrupt_operation (intr_port);      if (err)	{	  mach_port_t *reply;	  /* The interrupt didn't work.	     Destroy the receive right the thread is blocked on.  */	  __mach_port_destroy (__mach_task_self (), msging_port);	  /* The system call return value register now contains	     MACH_RCV_INTERRUPTED; when mach_msg resumes, it will retry the	     call.  Since we have just destroyed the receive right, the	     retry will fail with MACH_RCV_INVALID_NAME.  Instead, just	     change the return value here to EINTR so mach_msg will not	     retry and the EINTR error code will propagate up.  */	  state->basic.SYSRETURN = EINTR;	  /* If that was the thread's MiG reply port (which I think should	     always be the case), clear the reply port cell so it won't be	     reused.  */	  reply = interrupted_reply_port_location (state);	  if (reply != NULL && *reply == msging_port)	    *reply = MACH_PORT_NULL;	}      /* All threads whose RPCs were interrupted by the interrupt_operation	 call above will retry their RPCs unless we clear SS->intr_port.	 So we clear it for the thread taking a signal when SA_RESTART is	 clear, so that its call returns EINTR.  */      if (!(ss->actions[signo].sa_flags & SA_RESTART))	ss->intr_port = MACH_PORT_NULL;      return err ? MACH_PORT_NULL : msging_port;    }  /* One of the following is true:     1. The RPC has not yet been sent.  The thread will start its operation     after the signal has been handled.     2. The RPC has finished, but not yet cleared SS->intr_port.     The thread will clear SS->intr_port after running the handler.     3. The RPC request message was being sent was aborted.  The mach_msg     system call will return MACH_SEND_INTERRUPTED, and HURD_EINTR_RPC will     notice the interruption (either retrying the RPC or returning EINTR).  */  return MACH_PORT_NULL;}/* Abort the RPCs being run by all threads but this one;   all other threads should be suspended.  */static voidabort_all_rpcs (int signo, struct machine_thread_all_state *state){  /* We can just loop over the sigstates.  Any thread doing something     interruptible must have one.  We needn't bother locking because all     other threads are stopped.  */  struct hurd_sigstate *ss;  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)    if (ss->thread != _hurd_msgport_thread)      /* Abort any operation in progress with interrupt_operation.  We	 record this by putting the reply port into SS->intr_port, or	 MACH_PORT_NULL if no interruption was done.  We will wait for	 all the replies below.  */      ss->intr_port = abort_rpcs (ss, signo, state, NULL, 0);  /* Wait for replies from all the successfully interrupted RPCs.  */  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)    if (ss->intr_port != MACH_PORT_NULL)      {	error_t err;	mach_msg_header_t head;	err = __mach_msg (&head, MACH_RCV_MSG, 0, sizeof head, ss->intr_port,			  MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);	if (err != MACH_RCV_TOO_LARGE)	  assert_perror (err);      }}struct hurd_signal_preempt *_hurd_signal_preempt[NSIG];struct mutex _hurd_signal_preempt_lock;/* Mask of stop signals.  */#define STOPSIGS (sigmask (SIGTTIN) | sigmask (SIGTTOU) | \		  sigmask (SIGSTOP) | sigmask (SIGTSTP))/* Deliver a signal.   SS->lock is held on entry and released before return.  */void_hurd_internal_post_signal (struct hurd_sigstate *ss,			    int signo, int sigcode, int sigerror,			    mach_port_t reply_port,			    mach_msg_type_name_t reply_port_type){  struct machine_thread_all_state thread_state;  enum { stop, ignore, core, term, handle } act;  sighandler_t handler;  struct hurd_signal_preempt *pe;  sighandler_t (*preempt) (thread_t, int, int) = NULL;  sigset_t pending;  int ss_suspended;  /* Reply to this sig_post message.  */  inline void reply ()    {      post_reply (&reply_port, reply_port_type, 0);    }  /* Wake up a sigsuspend call that is blocking SS->thread.  */  inline void sigwakeup (void)    {      if (ss->suspended != MACH_PORT_NULL)	{	  /* There is a sigsuspend waiting.  Tell it to wake up.  */	  error_t err;	  mach_msg_header_t msg;	  err = __mach_port_insert_right (__mach_task_self (),					  ss->suspended, ss->suspended,					  MACH_MSG_TYPE_MAKE_SEND);	  assert_perror (err);	  msg.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_MOVE_SEND, 0);	  msg.msgh_remote_port = ss->suspended;	  msg.msgh_local_port = MACH_PORT_NULL;	  /* These values do not matter.  */	  msg.msgh_id = 8675309; /* Jenny, Jenny.  */	  msg.msgh_seqno = 17;	/* Random.  */	  ss->suspended = MACH_PORT_NULL;	  err = __mach_msg (&msg, MACH_SEND_MSG, sizeof msg, 0,			    MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,			    MACH_PORT_NULL);	  assert_perror (err);	}      __mutex_unlock (&ss->lock);    } post_signal:  thread_state.set = 0;		/* We know nothing.  */  /* Check for a preempted signal.  */  __mutex_lock (&_hurd_signal_preempt_lock);  for (pe = _hurd_signal_preempt[signo]; pe != NULL; pe = pe->next)    if (sigcode >= pe->first && sigcode <= pe->last)      {	preempt = pe->handler;	break;      }  __mutex_unlock (&_hurd_signal_preempt_lock);  handler = SIG_DFL;  if (preempt)    /* Let the preempting handler examine the thread.       If it returns SIG_DFL, we run the normal handler;       otherwise we use the handler it returns.  */    handler = (*preempt) (ss->thread, signo, sigcode);  ss_suspended = 0;  if (handler != SIG_DFL)    /* Run the preemption-provided handler.  */    act = handle;  else    {      /* No preemption.  Do normal handling.  */      handler = ss->actions[signo].sa_handler;      if (handler == SIG_DFL)	/* Figure out the default action for this signal.  */	switch (signo)	  {	  case 0:	    /* A sig_post msg with SIGNO==0 is sent to	       tell us to check for pending signals.  */	    act = ignore;	    break;	  case SIGTTIN:	  case SIGTTOU:	  case SIGSTOP:	  case SIGTSTP:	    act = stop;	    break;	  case SIGCONT:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -