Esempio n. 1
0
error_t
hurd_thread_cancel (thread_t thread)
{
    struct hurd_sigstate *ss = _hurd_thread_sigstate (thread);
    struct machine_thread_all_state state;
    int state_change;
    error_t err;

    if (! ss)
        return EINVAL;
    if (ss == _hurd_self_sigstate ())
    {
        /* We are cancelling ourselves, so it is easy to succeed
        quickly.  Since this function is not a cancellation point, we
         just leave the flag set pending the next cancellation point
         (hurd_check_cancel or RPC) and return success.  */
        ss->cancel = 1;
        return 0;
    }

    assert (! __spin_lock_locked (&ss->critical_section_lock));
    __spin_lock (&ss->critical_section_lock);
    __spin_lock (&ss->lock);
    err = __thread_suspend (thread);
    __spin_unlock (&ss->lock);

    if (! err)
    {
        /* Set the flag telling the thread its operation is being cancelled.  */
        ss->cancel = 1;

        /* Interrupt any interruptible RPC now in progress.  */
        state.set = 0;
        _hurdsig_abort_rpcs (ss, 0, 0, &state, &state_change, NULL, 0, 0);
        if (state_change)
            err = __thread_set_state (thread, MACHINE_THREAD_STATE_FLAVOR,
                                      (natural_t *) &state.basic,
                                      MACHINE_THREAD_STATE_COUNT);

        if (ss->cancel_hook)
            /* The code being cancelled has a special wakeup function.
               Calling this should make the thread wake up and check the
               cancellation flag.  */
            (*ss->cancel_hook) ();

        __thread_resume (thread);
    }

    _hurd_critical_section_unlock (ss);
    return err;
}
Esempio n. 2
0
static void
abort_all_rpcs (int signo, struct machine_thread_all_state *state, int live)
{
  /* 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;
  size_t nthreads;
  mach_port_t *reply_ports;

  /* First loop over the sigstates to count them.
     We need to know how big a vector we will need for REPLY_PORTS.  */
  nthreads = 0;
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next)
    ++nthreads;

  reply_ports = alloca (nthreads * sizeof *reply_ports);

  nthreads = 0;
  for (ss = _hurd_sigstates; ss != NULL; ss = ss->next, ++nthreads)
    if (ss->thread == _hurd_msgport_thread)
      reply_ports[nthreads] = MACH_PORT_NULL;
    else
      {
	int state_changed;
	state->set = 0;		/* Reset scratch area.  */

	/* Abort any operation in progress with interrupt_operation.
	   Record the reply port the thread is waiting on.
	   We will wait for all the replies below.  */
	reply_ports[nthreads] = _hurdsig_abort_rpcs (ss, signo, 1,
						     state, &state_changed,
						     NULL);
	if (live)
	  {
	    if (reply_ports[nthreads] != MACH_PORT_NULL)
	      {
		/* We will wait for the reply to this RPC below, so the
		   thread must issue a new RPC rather than waiting for the
		   reply to the one it sent.  */
		state->basic.SYSRETURN = EINTR;
		state_changed = 1;
	      }
	    if (state_changed)
	      /* Aborting the RPC needed to change this thread's state,
		 and it might ever run again.  So write back its state.  */
	      __thread_set_state (ss->thread, MACHINE_THREAD_STATE_FLAVOR,
				  (natural_t *) &state->basic,
				  MACHINE_THREAD_STATE_COUNT);
	  }
      }

  /* Wait for replies from all the successfully interrupted RPCs.  */
  while (nthreads-- > 0)
    if (reply_ports[nthreads] != MACH_PORT_NULL)
      {
	error_t err;
	mach_msg_header_t head;
	err = __mach_msg (&head, MACH_RCV_MSG|MACH_RCV_TIMEOUT, 0, sizeof head,
			  reply_ports[nthreads],
			  _hurd_interrupted_rpc_timeout, MACH_PORT_NULL);
	switch (err)
	  {
	  case MACH_RCV_TIMED_OUT:
	  case MACH_RCV_TOO_LARGE:
	    break;

	  default:
	    assert_perror (err);
	  }
      }
}