void exit(int status) { _TCB *tcb = (_TCB*)g_readytorun.head; /* Only the lower 8-bits of status are used */ status &= 0xff; /* Perform common task termination logic */ task_exithook(tcb, status); /* Then "really" exit. Only the lower 8 bits of the exit status are used. */ _exit(status); }
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 exit(int status) { struct tcb_s *tcb = (struct tcb_s*)g_readytorun.head; /* Only the lower 8-bits of status are used */ status &= 0xff; /* 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 to handle atexit() and on_exit() callbacks and * so that we can flush buffered I/O (both of which may required suspending). */ task_exithook(tcb, status, false); /* Then "really" exit. Only the lower 8 bits of the exit status are used. */ _exit(status); }
int task_terminate(pid_t pid, bool nonblocking) { FAR struct tcb_s *dtcb; FAR dq_queue_t *tasklist; irqstate_t flags; #ifdef CONFIG_SMP int cpu; #endif int ret; /* Make sure the task does not become ready-to-run while we are futzing * with its TCB. Within the critical section, no new task may be started * or terminated (even in the SMP case). */ flags = enter_critical_section(); /* Find for the TCB associated with matching PID */ dtcb = sched_gettcb(pid); if (!dtcb) { /* This PID does not correspond to any known task */ ret = -ESRCH; goto errout_with_lock; } /* Verify our internal sanity */ #ifdef CONFIG_SMP DEBUGASSERT(dtcb->task_state < NUM_TASK_STATES); #else DEBUGASSERT(dtcb->task_state != TSTATE_TASK_RUNNING && dtcb->task_state < NUM_TASK_STATES); #endif /* Remove the task from the OS's task lists. We must be in a critical * section and the must must not be running to do this. */ #ifdef CONFIG_SMP /* In the SMP case, the thread may be running on another CPU. If that is * the case, then we will pause the CPU that the thread is running on. */ cpu = sched_cpu_pause(dtcb); /* Get the task list associated with the the thread's state and CPU */ tasklist = TLIST_HEAD(dtcb->task_state, cpu); #else /* In the non-SMP case, we can be assured that the task to be terminated * is not running. get the task list associated with the task state. */ tasklist = TLIST_HEAD(dtcb->task_state); #endif /* Remove the task from the task list */ dq_rem((FAR dq_entry_t *)dtcb, tasklist); dtcb->task_state = TSTATE_TASK_INVALID; /* At this point, the TCB should no longer be accessible to the system */ #ifdef CONFIG_SMP /* Resume the paused CPU (if any) */ if (cpu >= 0) { /* I am not yet sure how to handle a failure here. */ DEBUGVERIFY(up_cpu_resume(cpu)); } #endif /* CONFIG_SMP */ leave_critical_section(flags); /* Perform common task termination logic (flushing streams, calling * functions registered by at_exit/on_exit, etc.). We need to do * this as early as possible so that higher level clean-up logic * can run in a healthy tasking environment. * * In the case where the task exits via exit(), task_exithook() * may be called twice. * * I suppose EXIT_SUCCESS is an appropriate return value??? */ task_exithook(dtcb, EXIT_SUCCESS, nonblocking); /* Since all tasks pass through this function as the final step in their * exit sequence, this is an appropriate place to inform any instrumentation * layer that the task no longer exists. */ sched_note_stop(dtcb); /* Deallocate its TCB */ return sched_releasetcb(dtcb, dtcb->flags & TCB_FLAG_TTYPE_MASK); errout_with_lock: leave_critical_section(flags); return ret; }