/**************************************************************************** * Name: up_unblock_task * * Description: * A task is currently in an inactive task list * but has been prepped to execute. Move the TCB to the * ready-to-run list, restore its context, and start execution. * * Inputs: * tcb: Refers to the tcb to be unblocked. This tcb is * in one of the waiting tasks lists. It must be moved to * the ready-to-run list and, if it is the highest priority * ready to run taks, executed. * ****************************************************************************/ void up_unblock_task(struct tcb_s *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { warn("%s: task sched error\n", __func__); return; } else { struct tcb_s *rtcb = current_task; /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; #endif // Add the task in the correct location in the prioritized // g_readytorun task list. if (sched_addreadytorun(tcb) && !up_interrupt_context()) { /* The currently active task has changed! */ struct tcb_s *nexttcb = (struct tcb_s*)g_readytorun.head; // context switch up_switchcontext(rtcb, nexttcb); } } }
void up_unblock_task(struct tcb_s *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { warn("%s: task sched error\n", __func__); return; } else { struct tcb_s *rtcb = current_task; /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Add the task in the correct location in the prioritized * ready-to-run task list. */ if (sched_addreadytorun(tcb) && !up_interrupt_context()) { /* The currently active task has changed! */ /* Update scheduler parameters */ sched_suspend_scheduler(rtcb); /* Are we in an interrupt handler? */ struct tcb_s *nexttcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. (void)group_addrenv(nexttcb); #endif /* Update scheduler parameters */ sched_resume_scheduler(nexttcb); /* context switch */ up_switchcontext(rtcb, nexttcb); } } }
void up_unblock_task(struct tcb_s *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { PANIC(OSERR_BADUNBLOCKSTATE); } else { struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head; /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. * * Are we in an interrupt handler? */ if (current_regs) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. */ up_savestate(rtcb->xcp.regs); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; /* Then switch contexts */ up_restorestate(rtcb->xcp.regs); } /* No, then we will need to perform the user context switch */ else { /* Switch context to the context of the task at the head of the * ready to run list. */ struct tcb_s *nexttcb = (struct tcb_s*)g_readytorun.head; up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); /* up_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the * normal sense. When it does return, it is because the blocked * task is again ready to run and has execution priority. */ } } } }
void up_unblock_task(struct tcb_s *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { PANIC(OSERR_BADUNBLOCKSTATE); } else { struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head; /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. * * Are we in an interrupt handler? */ if (current_regs) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. */ up_copystate(rtcb->xcp.regs, current_regs); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; /* Then switch contexts */ current_regs = rtcb->xcp.regs; } /* We are not in an interrupt handler. Copy the user C context * into the TCB of the task that was previously active. if * up_saveusercontext returns a non-zero value, then this is really the * previously running task restarting! */ else if (!up_saveusercontext(rtcb->xcp.regs)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; /* Then switch contexts */ up_fullcontextrestore(rtcb->xcp.regs); } } } }
void up_unblock_task(struct tcb_s *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { PANIC(OSERR_BADUNBLOCKSTATE); } else { struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head; sdbg("Unblocking TCB=%p\n", tcb); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! Copy the exception context * into the TCB of the task that was previously active. if * up_setjmp returns a non-zero value, then this is really the * previously running task restarting! */ if (!up_setjmp(rtcb->xcp.regs)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; sdbg("New Active Task TCB=%p\n", rtcb); /* The way that we handle signals in the simulation is kind of * a kludge. This would be unsafe in a truly multi-threaded, interrupt * driven environment. */ if (rtcb->xcp.sigdeliver) { sdbg("Delivering signals TCB=%p\n", rtcb); ((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb); rtcb->xcp.sigdeliver = NULL; } /* Then switch contexts */ up_longjmp(rtcb->xcp.regs, 1); } } } }
void up_unblock_task(struct tcb_s *tcb) { struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head; /* Verify that the context switch can be performed */ ASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && (tcb->task_state <= LAST_BLOCKED_STATE)); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL); #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. * * Are we in an interrupt handler? */ if (current_regs) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. */ up_savestate(rtcb->xcp.regs); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; /* Then switch contexts */ up_restorestate(rtcb->xcp.regs); #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. */ (void)group_addrenv(rtcb); #endif } /* We are not in an interrupt handler. Copy the user C context * into the TCB of the task that was previously active. if * up_saveusercontext returns a non-zero value, then this is really the * previously running task restarting! */ else if (!up_saveusercontext(rtcb->xcp.regs)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. */ (void)group_addrenv(rtcb); #endif /* Then switch contexts */ up_fullcontextrestore(rtcb->xcp.regs); } } }
void up_unblock_task(struct tcb_s *tcb) { struct tcb_s *rtcb = this_task(); /* Verify that the context switch can be performed */ ASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && (tcb->task_state <= LAST_BLOCKED_STATE)); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Add the task in the correct location in the prioritized * ready-to-run task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. */ /* Update scheduler parameters */ sched_suspend_scheduler(rtcb); /* Are we in an interrupt handler? */ if (current_regs) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. */ up_copystate(rtcb->xcp.regs, current_regs); /* Restore the exception context of the rtcb at the (new) head * of the ready-to-run task list. */ rtcb = this_task(); /* Update scheduler parameters */ sched_resume_scheduler(rtcb); /* Then switch contexts. Any necessary address environment * changes will be made when the interrupt returns. */ current_regs = rtcb->xcp.regs; } /* We are not in an interrupt handler. Copy the user C context * into the TCB of the task that was previously active. if * up_saveusercontext returns a non-zero value, then this is really the * previously running task restarting! */ else if (!up_saveusercontext(rtcb->xcp.regs)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * ready-to-run task list. */ rtcb = this_task(); #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. */ (void)group_addrenv(rtcb); #endif /* Update scheduler parameters */ sched_resume_scheduler(rtcb); /* Then switch contexts */ up_fullcontextrestore(rtcb->xcp.regs); } } }
void up_unblock_task(struct tcb_s *tcb) { struct tcb_s *rtcb = (struct tcb_s*)g_readytorun.head; /* Verify that the context switch can be performed */ ASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && (tcb->task_state <= LAST_BLOCKED_STATE)); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = MSEC2TICK(CONFIG_RR_INTERVAL); #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. * * Are we in an interrupt handler? */ if (current_regs) { /* Yes, then we have to do things differently. * Just copy the current_regs into the OLD rtcb. */ up_savestate(rtcb->xcp.regs); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. */ rtcb = (struct tcb_s*)g_readytorun.head; /* Then switch contexts. Any necessary address environment * changes will be made when the interrupt returns. */ up_restorestate(rtcb->xcp.regs); } /* No, then we will need to perform the user context switch */ else { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * g_readytorun task list. */ struct tcb_s *nexttcb = (struct tcb_s*)g_readytorun.head; #ifdef CONFIG_ARCH_ADDRENV /* Make sure that the address environment for the previously * running task is closed down gracefully (data caches dump, * MMU flushed) and set up the address environment for the new * thread at the head of the ready-to-run list. */ (void)group_addrenv(nexttcb); #endif /* Then switch contexts */ up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); /* up_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the * normal sense. When it does return, it is because the blocked * task is again ready to run and has execution priority. */ } } }
void up_unblock_task(struct tcb_s *tcb) { struct tcb_s *rtcb = this_task(); /* Verify that the context switch can be performed */ DEBUGASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && (tcb->task_state <= LAST_BLOCKED_STATE)); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Add the task in the correct location in the prioritized * ready-to-run task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. */ /* Update scheduler parameters */ sched_suspend_scheduler(rtcb); /* Are we in an interrupt handler? */ if (CURRENT_REGS) { /* Yes, then we have to do things differently. * Just copy the CURRENT_REGS into the OLD rtcb. */ up_savestate(rtcb->xcp.regs); /* Restore the exception context of the rtcb at the (new) head * of the ready-to-run task list. */ rtcb = this_task(); /* Update scheduler parameters */ sched_resume_scheduler(rtcb); /* Then switch contexts */ up_restorestate(rtcb->xcp.regs); } /* No, then we will need to perform the user context switch */ else { struct tcb_s *nexttcb = this_task(); /* Update scheduler parameters */ sched_resume_scheduler(nexttcb); /* Switch context to the context of the task at the head of the * ready to run list. */ up_switchcontext(rtcb->xcp.regs, nexttcb->xcp.regs); /* up_switchcontext forces a context switch to the task at the * head of the ready-to-run list. It does not 'return' in the * normal sense. When it does return, it is because the blocked * task is again ready to run and has execution priority. */ } } }
void up_unblock_task(FAR _TCB *tcb) { /* Verify that the context switch can be performed */ if ((tcb->task_state < FIRST_BLOCKED_STATE) || (tcb->task_state > LAST_BLOCKED_STATE)) { PANIC(OSERR_BADUNBLOCKSTATE); } else { FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; /* dbg("Unblocking TCB=%p\n", tcb); */ /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset its timeslice. This is only meaningful for round * robin tasks but it doesn't here to do it for everything */ #if CONFIG_RR_INTERVAL > 0 tcb->timeslice = CONFIG_RR_INTERVAL / MSEC_PER_TICK; #endif /* Add the task in the correct location in the prioritized * g_readytorun task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! We need to do * a context switch to the new task. * * Are we in an interrupt handler? */ if (IN_INTERRUPT) { /* Yes, then we have to do things differently. * Just copy the current context into the OLD rtcb. */ SAVE_IRQCONTEXT(rtcb); /* Restore the exception context of the rtcb at the (new) head * of the g_readytorun task list. */ rtcb = (FAR _TCB*)g_readytorun.head; /* dbg("New Active Task TCB=%p\n", rtcb); */ /* Then setup so that the context will be performed on exit * from the interrupt. */ SET_IRQCONTEXT(rtcb); } /* We are not in an interrupt handler. Copy the user C context * into the TCB of the task that was previously active. if * SAVE_USERCONTEXT returns a non-zero value, then this is really the * previously running task restarting! */ else if (!SAVE_USERCONTEXT(rtcb)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * g_readytorun task list. */ rtcb = (FAR _TCB*)g_readytorun.head; /* dbg("New Active Task TCB=%p\n", rtcb); */ /* Then switch contexts */ RESTORE_USERCONTEXT(rtcb); } } } }
/************************************************************************************ * Name: taskmgr_ioctl * * Description: The ioctl method for task management. * ************************************************************************************/ static int taskmgr_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { int ret = -EINVAL; struct tcb_s *tcb; tmvdbg("cmd: %d arg: %ld\n", cmd, arg); /* Handle built-in ioctl commands */ switch (cmd) { case TMIOC_START: ret = taskmgr_task_init((int)arg); if (ret != OK) { tmdbg("Fail to init new task\n"); } break; case TMIOC_PAUSE: tcb = sched_gettcb((int)arg); if (tcb == NULL) { tmdbg("Invalid pid\n"); return ERROR; } if (tcb->task_state == TSTATE_WAIT_SIG && tcb->waitdog != NULL) { /* tcb is waiting another signal, e.g. sleep */ wd_cancel(tcb->waitdog); } else if (tcb->task_state == TSTATE_WAIT_SEM) { tcb->waitsem = NULL; sched_removeblocked(tcb); sched_addblocked(tcb, TSTATE_WAIT_SIG); } ret = OK; break; case TMIOC_UNICAST: tcb = sched_gettcb((int)arg); if (tcb == NULL) { tmdbg("Invalid pid\n"); return ERROR; } ret = (int)sig_is_handler_registered(tcb, SIGTM_UNICAST); if ((bool)ret != true) { tmdbg("handler is not registered for unicast\n"); ret = ERROR; } else { ret = OK; } break; case TMIOC_RESTART: break; case TMIOC_BROADCAST: tcb = sched_gettcb((int)arg); if (tcb == NULL) { tmdbg("Invalid pid\n"); return ERROR; } ret = (int)sig_is_handler_registered(tcb, SIGTM_BROADCAST); if ((bool)ret != true) { tmdbg("handler is not registered for broadcast\n"); ret = ERROR; } else { ret = OK; } break; case TMIOC_CHECK_ALIVE: tcb = sched_gettcb((int)arg); if (tcb == NULL) { tmdbg("Invalid pid\n"); return ERROR; } ret = OK; break; default: tmdbg("Unrecognized cmd: %d arg: %ld\n", cmd, arg); break; } return ret; }
void up_unblock_task(FAR struct tcb_s *tcb) { FAR struct tcb_s *rtcb = this_task(); /* Verify that the context switch can be performed */ ASSERT((tcb->task_state >= FIRST_BLOCKED_STATE) && (tcb->task_state <= LAST_BLOCKED_STATE)); sdbg("Unblocking TCB=%p\n", tcb); /* Remove the task from the blocked task list */ sched_removeblocked(tcb); /* Reset scheduler parameters */ sched_resume_scheduler(tcb); /* Add the task in the correct location in the prioritized * ready-to-run task list */ if (sched_addreadytorun(tcb)) { /* The currently active task has changed! */ /* Update scheduler parameters */ sched_suspend_scheduler(rtcb); /* Copy the exception context into the TCB of the task that was * previously active. if up_setjmp returns a non-zero value, then * this is really the previously running task restarting! */ if (!up_setjmp(rtcb->xcp.regs)) { /* Restore the exception context of the new task that is ready to * run (probably tcb). This is the new rtcb at the head of the * ready-to-run task list. */ rtcb = this_task(); sdbg("New Active Task TCB=%p\n", rtcb); /* The way that we handle signals in the simulation is kind of * a kludge. This would be unsafe in a truly multi-threaded, interrupt * driven environment. */ if (rtcb->xcp.sigdeliver) { sdbg("Delivering signals TCB=%p\n", rtcb); ((sig_deliver_t)rtcb->xcp.sigdeliver)(rtcb); rtcb->xcp.sigdeliver = NULL; } /* Update scheduler parameters */ sched_resume_scheduler(rtcb); /* Then switch contexts */ up_longjmp(rtcb->xcp.regs, 1); } } }