Пример #1
0
kern_return_t
__mach_setup_thread (task_t task, thread_t thread, void *pc,
		     vm_address_t *stack_base, vm_size_t *stack_size)
{
  kern_return_t error;
  struct machine_thread_state ts;
  mach_msg_type_number_t tssize = MACHINE_THREAD_STATE_COUNT;
  vm_address_t stack;
  vm_size_t size;
  int anywhere;

  size = stack_size ? *stack_size ? : STACK_SIZE : STACK_SIZE;
  stack = stack_base ? *stack_base ? : 0 : 0;
  anywhere = !stack_base || !*stack_base;

  error = __vm_allocate (task, &stack, size + __vm_page_size, anywhere);
  if (error)
    return error;

  if (stack_size)
    *stack_size = size;

  memset (&ts, 0, sizeof (ts));
  MACHINE_THREAD_STATE_SET_PC (&ts, pc);
#ifdef STACK_GROWTH_DOWN
  if (stack_base)
    *stack_base = stack + __vm_page_size;
  ts.SP = stack + __vm_page_size + size;
#elif defined (STACK_GROWTH_UP)
  if (stack_base)
    *stack_base = stack;
  ts.SP = stack;
  stack += size;
#else
  #error stack direction unknown
#endif

  /* Create the red zone.  */
  if (error = __vm_protect (task, stack, __vm_page_size, 0, VM_PROT_NONE))
    return error;

  return __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
			     (natural_t *) &ts, tssize);
}
Пример #2
0
mach_port_t
_hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
		     struct machine_thread_all_state *state, int *state_change,
		     void (*reply) (void))
{
  extern const void _hurd_intr_rpc_msg_in_trap;
  mach_port_t rcv_port = MACH_PORT_NULL;
  mach_port_t intr_port;

  *state_change = 0;

  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);

  if (state->basic.PC < (natural_t) &_hurd_intr_rpc_msg_in_trap)
    {
      /* The thread is about to do the RPC, but hasn't yet entered
	 mach_msg.  Mutate the thread's state so it knows not to try
	 the RPC.  */
      INTR_MSG_BACK_OUT (&state->basic);
      MACHINE_THREAD_STATE_SET_PC (&state->basic,
				   &_hurd_intr_rpc_msg_in_trap);
      state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
      *state_change = 1;
    }
  else if (state->basic.PC == (natural_t) &_hurd_intr_rpc_msg_in_trap &&
	   /* The thread was blocked in the system call.  After thread_abort,
	      the return value register indicates what state the RPC was in
	      when interrupted.  */
	   state->basic.SYSRETURN == MACH_RCV_INTERRUPTED)
      {
	/* 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.  */

	mach_port_t *reply = interrupted_reply_port_location (ss->thread,
							      state,
							      sigthread);
	error_t err = __interrupt_operation (intr_port, _hurdsig_interrupt_timeout);

	if (err)
	  {
	    if (reply)
	      {
		/* The interrupt didn't work.
		   Destroy the receive right the thread is blocked on.  */
		__mach_port_destroy (__mach_task_self (), *reply);
		*reply = MACH_PORT_NULL;
	      }

	    /* 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;
	    *state_change = 1;
	  }
	else if (reply)
	  rcv_port = *reply;

	/* 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 (! signo || !(_hurd_sigstate_actions (ss) [signo].sa_flags & SA_RESTART))
	  ss->intr_port = MACH_PORT_NULL;
      }

  return rcv_port;
}
Пример #3
0
kern_return_t
__mach_setup_thread (task_t task, thread_t thread, void *pc,
                     vm_address_t *stack_base, vm_size_t *stack_size)
{
    kern_return_t error;
    struct machine_thread_state ts;
    mach_msg_type_number_t tssize = MACHINE_THREAD_STATE_COUNT;
    vm_address_t stack;
    vm_size_t size;
    int anywhere = 0;

    size = stack_size ? *stack_size ? : STACK_SIZE : STACK_SIZE;

    if (stack_base && *stack_base)
        stack = *stack_base;
    else if (size == STACK_SIZE)
    {
        /* Cthreads has a bug that makes its stack-probing code fail if
        the stack is too low in memory.  It's bad to try and fix it there
         until cthreads is integrated into libc, so we'll just do it here
         by requesting a high address.  When the cthreads bug is fixed,
         this assignment to STACK should be changed to 0, and the ANYWHERE
         argument to vm_allocate should be changed to 0.  This comment should
         be left, however, in order to confuse people who wonder why its
         here.  (Though perhaps that last sentence (and this one) should
         be deleted to maximize the effect.)  */
#ifdef STACK_GROWTH_DOWN
        stack = VM_MAX_ADDRESS - size - __vm_page_size;
#else
        stack = VM_MIN_ADDRESS;
#endif
    }
    else
        anywhere = 1;

    if (error = __vm_allocate (task, &stack, size + __vm_page_size, anywhere))
        return error;

    if (stack_size)
        *stack_size = size;

    memset (&ts, 0, sizeof (ts));
    MACHINE_THREAD_STATE_SET_PC (&ts, pc);
#ifdef STACK_GROWTH_DOWN
    if (stack_base)
        *stack_base = stack + __vm_page_size;
    ts.SP = stack + __vm_page_size + size;
#elif defined (STACK_GROWTH_UP)
    if (stack_base)
        *stack_base = stack;
    ts.SP = stack;
    stack += size;
#else
#error stack direction unknown
#endif

    /* Create the red zone.  */
    if (error = __vm_protect (task, stack, __vm_page_size, 0, VM_PROT_NONE))
        return error;

    return __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
                               (int *) &ts, tssize);
}
Пример #4
0
void
_hurdsig_fault_init (void)
{
  error_t err;
  struct machine_thread_state state;
  mach_port_t sigexc;

  /* Allocate a port to receive signal thread exceptions.
     We will move this receive right to the proc server.  */
  err = __mach_port_allocate (__mach_task_self (),
			      MACH_PORT_RIGHT_RECEIVE, &sigexc);
  assert_perror (err);
  err = __mach_port_allocate (__mach_task_self (),
			      MACH_PORT_RIGHT_RECEIVE, &forward_sigexc);
  assert_perror (err);

  /* Allocate a port to receive the exception msgs forwarded
     from the proc server.  */
  err = __mach_port_insert_right (__mach_task_self (), sigexc,
				  sigexc, MACH_MSG_TYPE_MAKE_SEND);
  assert_perror (err);

  /* Set the queue limit for this port to just one.  The proc server will
     notice if we ever get a second exception while one remains queued and
     unreceived, and decide we are hopelessly buggy.  */
#ifdef MACH_PORT_RECEIVE_STATUS_COUNT
  {
    const mach_port_limits_t lim = { mpl_qlimit: 1 };
    assert (MACH_PORT_RECEIVE_STATUS_COUNT == sizeof lim / sizeof (natural_t));
    err = __mach_port_set_attributes (__mach_task_self (), forward_sigexc,
				      MACH_PORT_RECEIVE_STATUS,
				      (mach_port_info_t) &lim,
				      MACH_PORT_RECEIVE_STATUS_COUNT);
  }
#else
  err = __mach_port_set_qlimit (__mach_task_self (), forward_sigexc, 1);
#endif
  assert_perror (err);

  /* This state will be restored when we fault.
     It runs the function above.  */
  memset (&state, 0, sizeof state);
  MACHINE_THREAD_STATE_SET_PC (&state, faulted);
  MACHINE_THREAD_STATE_SET_SP (&state, faultstack, sizeof faultstack);

  err = __USEPORT
    (PROC,
     __proc_handle_exceptions (port,
			       sigexc,
			       forward_sigexc, MACH_MSG_TYPE_MAKE_SEND,
			       MACHINE_THREAD_STATE_FLAVOR,
			       (natural_t *) &state,
			       MACHINE_THREAD_STATE_COUNT));
  assert_perror (err);

  /* Direct signal thread exceptions to the proc server.  */
#ifdef THREAD_EXCEPTION_PORT
  err = __thread_set_special_port (_hurd_msgport_thread,
				   THREAD_EXCEPTION_PORT, sigexc);
#elif defined (EXC_MASK_ALL)
  __thread_set_exception_ports (_hurd_msgport_thread,
				EXC_MASK_ALL & ~(EXC_MASK_SYSCALL
						 | EXC_MASK_MACH_SYSCALL
						 | EXC_MASK_RPC_ALERT),
				sigexc,
				EXCEPTION_STATE_IDENTITY,
				MACHINE_THREAD_STATE);
#else
# error thread_set_exception_ports?
#endif
  __mach_port_deallocate (__mach_task_self (), sigexc);
  assert_perror (err);
}