Ejemplo n.º 1
0
void pthread_exit(FAR void *exit_value)
{
  struct tcb_s *tcb = (struct tcb_s*)g_readytorun.head;
  int status;

  sdbg("exit_value=%p\n", exit_value);

  /* Block any signal actions that would awaken us while were
   * are performing the JOIN handshake.
   */

#ifndef CONFIG_DISABLE_SIGNALS
  {
    sigset_t set = ALL_SIGNAL_SET;
    (void)sigprocmask(SIG_SETMASK, &set, NULL);
  }
#endif

  /* Complete pending join operations */

  status = pthread_completejoin(getpid(), exit_value);
  if (status != OK)
    {
      /* Assume that the join completion failured because this
       * not really a pthread.  Exit by calling exit().
       */

      exit(EXIT_FAILURE);
    }

  /* Perform common task termination logic.  This will get called again later
   * through logic kicked off by _exit().  However, we need to call it before
   * calling _exit() in order certain operations if this is the last thread
   * of a task group:  (2) To handle atexit() and on_exit() callbacks and
   * (2) so that we can flush buffered I/O (which may required suspending).
   */

  task_exithook(tcb, EXIT_SUCCESS, false);

  /* Then just exit, retaining all file descriptors and without
   * calling atexit() functions.
   */

  _exit(EXIT_SUCCESS);
}
Ejemplo n.º 2
0
void pthread_exit(FAR void *exit_value)
{
  int error_code = (int)exit_value;
  int status;

  sdbg("exit_value=%p\n", exit_value);

  /* Block any signal actions that would awaken us while were
   * are performing the JOIN handshake.
   */

#ifndef CONFIG_DISABLE_SIGNALS
  {
    sigset_t set = ALL_SIGNAL_SET;
    (void)sigprocmask(SIG_SETMASK, &set, NULL);
  }
#endif

  /* Complete pending join operations */

  status = pthread_completejoin(getpid(), exit_value);
  if (status != OK)
    {
      /* Assume that the join completion failured becuase this
       * not really a pthread.  Exit by calling exit() to flush
       * and close all file descriptors and calling atexit()
       * functions.
       */

      if (error_code == EXIT_SUCCESS)
        {
           error_code = EXIT_FAILURE;
        }
      exit(error_code);
    }

  /* Then just exit, retaining all file descriptors and without
   * calling atexit() functions.
   */

  _exit(error_code);
}
Ejemplo n.º 3
0
int pthread_cancel(pthread_t thread)
{
  FAR struct tcb_s *tcb;

  /* First, make sure that the handle references a valid thread */

  if (!thread)
    {
      /* pid == 0 is the IDLE task.  Callers cannot cancel the
       * IDLE task.
       */

      return ESRCH;
    }

  tcb = sched_gettcb((pid_t)thread);
  if (!tcb)
    {
      /* The pid does not correspond to any known thread.  The thread
       * has probably already exited.
       */

      return ESRCH;
    }

  /* Check to see if this thread has the non-cancelable bit set in its
   * flags. Suppress context changes for a bit so that the flags are stable.
   * (the flags should not change in interrupt handling.
   */

  sched_lock();
  if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
    {
      /* Then we cannot cancel the thread now.  Here is how this is
       * supposed to work:
       *
       * "When cancelability is disabled, all cancels are held pending
       *  in the target thread until the thread changes the cancelability.
       *  When cancelability is deferred, all cancels are held pending in
       *  the target thread until the thread changes the cancelability, calls
       *  a function which is a cancellation point or calls pthread_testcancel(),
       *  thus creating a cancellation point. When cancelability is asynchronous,
       *  all cancels are acted upon immediately, interrupting the thread with its
       *  processing."
       */

      tcb->flags |= TCB_FLAG_CANCEL_PENDING;
      sched_unlock();
      return OK;
    }

  sched_unlock();

  /* Check to see if the ID refers to ourselves.. this would be the
   * same as pthread_exit(PTHREAD_CANCELED).
   */

  if (tcb == this_task())
    {
      pthread_exit(PTHREAD_CANCELED);
    }

  /* Complete pending join operations */

  (void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);

  /* Then let pthread_delete do the real work */

  task_delete((pid_t)thread);
  return OK;
}
Ejemplo n.º 4
0
int pthread_cancel(pthread_t thread)
{
  FAR struct pthread_tcb_s *tcb;

  /* First, make sure that the handle references a valid thread */

  if (thread == 0)
    {
      /* pid == 0 is the IDLE task.  Callers cannot cancel the
       * IDLE task.
       */

      return ESRCH;
    }

  tcb = (FAR struct pthread_tcb_s *)sched_gettcb((pid_t)thread);
  if (tcb == NULL)
    {
      /* The pid does not correspond to any known thread.  The thread
       * has probably already exited.
       */

      return ESRCH;
    }

  /* Only pthreads should use this interface */

  DEBUGASSERT((tcb->cmn.flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD);

  /* Check to see if this thread has the non-cancelable bit set in its
   * flags. Suppress context changes for a bit so that the flags are stable.
   * (the flags should not change in interrupt handling).
   */

  sched_lock();
  if ((tcb->cmn.flags & TCB_FLAG_NONCANCELABLE) != 0)
    {
      /* Then we cannot cancel the thread now.  Here is how this is
       * supposed to work:
       *
       * "When cancelability is disabled, all cancels are held pending
       *  in the target thread until the thread changes the cancelability.
       *  When cancelability is deferred, all cancels are held pending in
       *  the target thread until the thread changes the cancelability, calls
       *  a function which is a cancellation point or calls pthread_testcancel(),
       *  thus creating a cancellation point. When cancelability is asynchronous,
       *  all cancels are acted upon immediately, interrupting the thread with its
       *  processing."
       */

      tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;
      sched_unlock();
      return OK;
    }

#ifdef CONFIG_CANCELLATION_POINTS
  /* Check if this thread supports deferred cancellation */

  if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
    {
      /* Then we cannot cancel the thread asynchronously.  Mark the cancellation
       * as pending.
       */

      tcb->cmn.flags |= TCB_FLAG_CANCEL_PENDING;

      /* If the thread is waiting at a cancellation point, then notify of the
       * cancellation thereby waking the task up with an ECANCELED error.
       *
       * REVISIT: is locking the scheduler sufficent in SMP mode?
       */

      if (tcb->cmn.cpcount > 0)
        {
          notify_cancellation(&tcb->cmn);
        }

      sched_unlock();
      return OK;
    }
#endif

  /* Otherwise, perform the asyncrhonous cancellation */

  sched_unlock();

  /* Check to see if the ID refers to ourselves.. this would be the
   * same as pthread_exit(PTHREAD_CANCELED).
   */

  if (tcb == (FAR struct pthread_tcb_s *)this_task())
    {
      pthread_exit(PTHREAD_CANCELED);
    }

#ifdef CONFIG_PTHREAD_CLEANUP
  /* Perform any stack pthread clean-up callbacks.
   *
   * REVISIT: In this case, the clean-up callback will execute on the
   * thread of the caller of pthread cancel, not on the thread of
   * the thread-to-be-canceled.  Is that an issue?  Presumably they
   * are both within the same group and within the same process address
   * space.
   */

  pthread_cleanup_popall(tcb);
#endif

  /* Complete pending join operations */

  (void)pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);

  /* Then let task_terminate do the real work */

  return task_terminate((pid_t)thread, false);
}