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